(
config: ManagedKimiConfigShape,
options: {
readonly models: readonly ManagedKimiCodeModelInfo[];
readonly baseUrl?: string | undefined;
readonly oauthKey?: string | undefined;
readonly oauthHost?: string | undefined;
readonly preserveDefaultModel?: boolean | undefined;
},
)
| 511 | } |
| 512 | |
| 513 | export function applyManagedKimiCodeConfig( |
| 514 | config: ManagedKimiConfigShape, |
| 515 | options: { |
| 516 | readonly models: readonly ManagedKimiCodeModelInfo[]; |
| 517 | readonly baseUrl?: string | undefined; |
| 518 | readonly oauthKey?: string | undefined; |
| 519 | readonly oauthHost?: string | undefined; |
| 520 | readonly preserveDefaultModel?: boolean | undefined; |
| 521 | }, |
| 522 | ): ManagedKimiCodeApplyResult { |
| 523 | if (options.models.length === 0) { |
| 524 | throw new Error('No models available for Kimi Code.'); |
| 525 | } |
| 526 | for (const model of options.models) { |
| 527 | assertPositiveContextLength(model); |
| 528 | } |
| 529 | |
| 530 | const baseUrl = defaultBaseUrl(options.baseUrl); |
| 531 | const oauth = |
| 532 | options.oauthKey !== undefined |
| 533 | ? managedOAuthRef({ key: options.oauthKey, oauthHost: options.oauthHost }) |
| 534 | : resolveKimiCodeOAuthRef({ baseUrl, oauthHost: options.oauthHost }); |
| 535 | const existingModels = config.models ?? {}; |
| 536 | const selectedDefault = selectDefaultModel(config, options.models, { |
| 537 | preserveExisting: options.preserveDefaultModel === true, |
| 538 | }); |
| 539 | |
| 540 | config.providers[KIMI_CODE_PROVIDER_NAME] = { |
| 541 | type: 'kimi', |
| 542 | baseUrl, |
| 543 | apiKey: '', |
| 544 | oauth, |
| 545 | }; |
| 546 | |
| 547 | // Selectively merge upstream models into the existing config so any fields |
| 548 | // the user added by hand (or that upstream does not declare) survive a |
| 549 | // refresh. Managed models that upstream no longer lists are removed; the |
| 550 | // rest are merged field-by-field — upstream-owned fields are overwritten, |
| 551 | // everything else is preserved. |
| 552 | const upstreamKeys = new Set(options.models.map((m) => managedModelKey(m.id))); |
| 553 | for (const [key, model] of Object.entries(existingModels)) { |
| 554 | if ( |
| 555 | isRecord(model) && |
| 556 | model['provider'] === KIMI_CODE_PROVIDER_NAME && |
| 557 | !upstreamKeys.has(key) |
| 558 | ) { |
| 559 | delete existingModels[key]; |
| 560 | } |
| 561 | } |
| 562 | for (const model of options.models) { |
| 563 | const capabilities = capabilitiesForModel(model); |
| 564 | const key = managedModelKey(model.id); |
| 565 | const existing = isRecord(existingModels[key]) ? existingModels[key] : {}; |
| 566 | // Kimi's Anthropic-compatible endpoint only accepts adaptive thinking |
| 567 | // (`thinking: { type: 'adaptive' }`); the kosong adapter otherwise infers |
| 568 | // budget-based thinking from the model name, which fails for Kimi model ids. |
| 569 | // Restrict the override to thinking-capable models: the UI treats |
| 570 | // `adaptiveThinking === true` as "supports a thinking toggle", so marking a |
no test coverage detected