@@ -70,6 +70,54 @@ describe("config agent writers", () => {
7070 expect ( readJsonAt ( ".claude.json" ) . hasCompletedOnboarding ) . toBe ( true ) ;
7171 } ) ;
7272
73+ test ( "claude-code 将 compatible-mode URL 改写为 apps/anthropic" , ( ) => {
74+ const tokenPlanOpenAi = "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1" ;
75+ const summary = claudeCode . write ( {
76+ baseUrl : tokenPlanOpenAi ,
77+ apiKey : "sk-a" ,
78+ model : "qwen3.8-max-preview" ,
79+ } ) ;
80+ const env = readJsonAt ( ".claude" , "settings.json" ) . env as Record < string , string > ;
81+ expect ( env . ANTHROPIC_BASE_URL ) . toBe (
82+ "https://token-plan.cn-beijing.maas.aliyuncs.com/apps/anthropic" ,
83+ ) ;
84+ expect ( summary . warnings ?. some ( ( warning ) => warning . includes ( "Rewrote base URL" ) ) ) . toBe ( true ) ;
85+ } ) ;
86+
87+ test ( "claude-code 保留已有分层模型,不整表覆盖" , ( ) => {
88+ mkdirSync ( join ( home , ".claude" ) , { recursive : true } ) ;
89+ writeFileSync (
90+ join ( home , ".claude" , "settings.json" ) ,
91+ JSON . stringify ( {
92+ env : {
93+ ANTHROPIC_DEFAULT_HAIKU_MODEL : "qwen3.6-flash" ,
94+ CLAUDE_CODE_SUBAGENT_MODEL : "qwen3.7-max" ,
95+ } ,
96+ } ) ,
97+ ) ;
98+
99+ claudeCode . write ( {
100+ baseUrl : ANTHROPIC_URL ,
101+ apiKey : "sk-a" ,
102+ model : "qwen3.8-max-preview" ,
103+ } ) ;
104+ const env = readJsonAt ( ".claude" , "settings.json" ) . env as Record < string , string > ;
105+ expect ( env . ANTHROPIC_MODEL ) . toBe ( "qwen3.8-max-preview" ) ;
106+ expect ( env . ANTHROPIC_DEFAULT_HAIKU_MODEL ) . toBe ( "qwen3.6-flash" ) ;
107+ expect ( env . CLAUDE_CODE_SUBAGENT_MODEL ) . toBe ( "qwen3.7-max" ) ;
108+ expect ( env . ANTHROPIC_DEFAULT_SONNET_MODEL ) . toBe ( "qwen3.8-max-preview" ) ;
109+ } ) ;
110+
111+ test ( "claude-code 拒绝无法改写为 Anthropic 的 base URL" , ( ) => {
112+ expect ( ( ) =>
113+ claudeCode . write ( {
114+ baseUrl : "https://api.openai.com/v1" ,
115+ apiKey : "sk-a" ,
116+ model : "qwen3-max" ,
117+ } ) ,
118+ ) . toThrow ( / A n t h r o p i c - c o m p a t i b l e b a s e U R L / ) ;
119+ } ) ;
120+
73121 test ( "qwen-code compatible-mode 走 openai 协议" , ( ) => {
74122 qwenCode . write ( { baseUrl : OAI_URL , apiKey : "sk-q" , model : "qwen3-coder-plus" } ) ;
75123 const settings = readJsonAt ( ".qwen" , "settings.json" ) ;
@@ -201,16 +249,19 @@ describe("config agent writers", () => {
201249 ) . toBe ( "@ai-sdk/openai-compatible" ) ;
202250 } ) ;
203251
204- test ( "openclaw 写入 provider、api 与 primary" , ( ) => {
252+ test ( "openclaw 写入 provider、api、 primary,并登记 defaults.models " , ( ) => {
205253 openclaw . write ( { baseUrl : OAI_URL , apiKey : "sk-c" , model : "qwen3-coder-plus" } ) ;
206254 const config = readJsonAt ( ".openclaw" , "openclaw.json" ) ;
207255 const models = config . models as Record < string , unknown > ;
208256 expect ( models . mode ) . toBe ( "merge" ) ;
209257 const bailian = ( models . providers as Record < string , Record < string , unknown > > ) [ "bailian-cli" ] ;
210258 expect ( bailian . api ) . toBe ( "openai-completions" ) ;
211259 expect ( ( bailian . models as Array < { id : string } > ) [ 0 ] . id ) . toBe ( "qwen3-coder-plus" ) ;
212- const agents = config . agents as { defaults : { model : { primary : string } } } ;
260+ const agents = config . agents as {
261+ defaults : { model : { primary : string } ; models : Record < string , unknown > } ;
262+ } ;
213263 expect ( agents . defaults . model . primary ) . toBe ( "bailian-cli/qwen3-coder-plus" ) ;
264+ expect ( agents . defaults . models [ "bailian-cli/qwen3-coder-plus" ] ) . toEqual ( { } ) ;
214265
215266 // anthropic 端点用 anthropic-messages
216267 openclaw . write ( { baseUrl : ANTHROPIC_URL , apiKey : "sk-c" , model : "qwen3-max" } ) ;
@@ -220,6 +271,57 @@ describe("config agent writers", () => {
220271 "bailian-cli"
221272 ] . api ,
222273 ) . toBe ( "anthropic-messages" ) ;
274+ expect (
275+ ( config2 . agents as { defaults : { model : { primary : string } } } ) . defaults . model . primary ,
276+ ) . toBe ( "bailian-cli/qwen3-max" ) ;
277+ } ) ;
278+
279+ test ( "openclaw 不抢占已有 token-plan primary" , ( ) => {
280+ mkdirSync ( join ( home , ".openclaw" ) , { recursive : true } ) ;
281+ writeFileSync (
282+ join ( home , ".openclaw" , "openclaw.json" ) ,
283+ JSON . stringify ( {
284+ models : {
285+ mode : "merge" ,
286+ providers : {
287+ "bailian-token-plan" : {
288+ baseUrl : "https://token-plan.cn-beijing.maas.aliyuncs.com/apps/anthropic" ,
289+ apiKey : "sk-token-plan" ,
290+ api : "anthropic-messages" ,
291+ models : [ { id : "qwen3.8-max-preview" , name : "qwen3.8-max-preview" } ] ,
292+ } ,
293+ } ,
294+ } ,
295+ agents : {
296+ defaults : {
297+ model : { primary : "bailian-token-plan/qwen3.8-max-preview" } ,
298+ models : { "bailian-token-plan/qwen3.8-max-preview" : { } } ,
299+ } ,
300+ } ,
301+ } ) ,
302+ ) ;
303+
304+ const summary = openclaw . write ( {
305+ baseUrl : "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1" ,
306+ apiKey : "sk-bailian" ,
307+ model : "qwen3.8-max-preview" ,
308+ } ) ;
309+
310+ const config = readJsonAt ( ".openclaw" , "openclaw.json" ) ;
311+ const agents = config . agents as {
312+ defaults : { model : { primary : string } ; models : Record < string , unknown > } ;
313+ } ;
314+ expect ( agents . defaults . model . primary ) . toBe ( "bailian-token-plan/qwen3.8-max-preview" ) ;
315+ expect ( agents . defaults . models [ "bailian-cli/qwen3.8-max-preview" ] ) . toEqual ( { } ) ;
316+ expect (
317+ ( config . models as { providers : Record < string , unknown > } ) . providers [ "bailian-token-plan" ] ,
318+ ) . toBeDefined ( ) ;
319+ expect (
320+ ( config . models as { providers : Record < string , unknown > } ) . providers [ "bailian-cli" ] ,
321+ ) . toBeDefined ( ) ;
322+ expect ( summary . warnings ?. some ( ( warning ) => warning . includes ( "Left existing primary" ) ) ) . toBe (
323+ true ,
324+ ) ;
223325 } ) ;
224326
225327 test ( "hermes 写入 custom_providers 与 model,合并保留其它 provider" , ( ) => {
0 commit comments