Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR swaps the base2-free/editor-lite/code-reviewer-lite model from Fireworks GLM 5.1 to CanopyWave Kimi K2.6, activates the previously dead-coded CanopyWave routing in the chat-completions endpoint, and adds per-model pricing to Confidence Score: 5/5Safe to merge; only P2 suggestions remain. All routing, pricing, and whitelist changes are consistent across the codebase. Remaining findings are style/maintainability suggestions (restoring common/src/constants/freebuff-models.ts (type maintainability), web/src/llm-api/canopywave.ts (pricing fallback)
|
| Filename | Overview |
|---|---|
| web/src/llm-api/canopywave.ts | Adds kimi-k2.6 to the model and pricing maps; extracts per-model pricing into CANOPYWAVE_PRICING_MAP; fallback in getCanopyWavePricing silently applies kimi pricing for any future unknown model |
| common/src/constants/freebuff-models.ts | Replaces GLM with Kimi; changes availability to 'always'; drops as const satisfies in favour of an explicit type annotation, which breaks automatic type-sync for FreebuffModelId |
| web/src/app/api/v1/chat/completions/_post.ts | Enables CanopyWave routing (previously dead-coded); guard ordering updated so CanopyWave takes priority over Fireworks/OpenAI-direct |
| web/src/server/free-session/config.ts | Updates INSTANT_ADMIT_CAPACITY key from z-ai/glm-5.1 to moonshotai/kimi-k2.6; capacity unchanged at 50 |
| web/src/server/free-session/public-api.ts | Updates RATE_LIMITS key from glm-5.1 to kimi-k2.6; rate-limit values (5 admits / 20 h) unchanged |
| agents/editor/editor.ts | Replaces 'glm' model key and z-ai/glm-5.1 string with 'kimi' / moonshotai/kimi-k2.6 throughout the editor factory |
| agents/base2/base2.ts | One-line swap of the free-mode model from z-ai/glm-5.1 to moonshotai/kimi-k2.6 |
| common/src/constants/free-agents.ts | Updates FREE_MODE_AGENT_MODELS whitelist for base2-free, editor-lite, and code-reviewer-lite from glm-5.1 to kimi-k2.6 |
| cli/src/components/freebuff-model-selector.tsx | Replaces FREEBUFF_GLM_MODEL_ID import/usage with FREEBUFF_KIMI_MODEL_ID to keep Kimi first in the selector list |
Prompt To Fix All With AI
This is a comment left during a code review.
Path: common/src/constants/freebuff-models.ts
Line: 42-59
Comment:
**`as const satisfies` removal makes `FreebuffModelId` drift-prone**
Switching from `as const satisfies readonly FreebuffModelOption[]` to an explicit `readonly FreebuffModelOption[]` annotation widens the inferred element types to `string`, which is why `FreebuffModelId` had to be redefined as a manual union. The old pattern was simpler: a new entry in `FREEBUFF_MODELS` automatically expanded the union type with no extra edit required.
```ts
export const FREEBUFF_MODELS = [
{
id: FREEBUFF_MINIMAX_MODEL_ID,
displayName: 'MiniMax M2.7',
tagline: 'Fastest',
availability: 'always',
},
{
id: FREEBUFF_KIMI_MODEL_ID,
displayName: 'Kimi K2.6',
tagline: 'Smartest',
availability: 'always',
},
] as const satisfies readonly FreebuffModelOption[]
export type FreebuffModelId = (typeof FREEBUFF_MODELS)[number]['id']
```
This restores the original self-maintaining type while keeping the `readonly FreebuffModelOption[]` constraint via `satisfies`.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: web/src/llm-api/canopywave.ts
Line: 109-111
Comment:
**Silent pricing fallback for unknown CanopyWave models**
`getCanopyWavePricing` falls back to kimi-k2.6 rates for any model not in `CANOPYWAVE_PRICING_MAP`. Since a model can only reach this function if it passed `isCanopyWaveModel` (i.e. it's already in `CANOPYWAVE_MODEL_MAP`), a missing pricing entry means a future model would silently be billed at kimi prices rather than its own. Throwing here would surface the misconfiguration immediately:
```ts
function getCanopyWavePricing(model: string): CanopyWavePricing {
const pricing = CANOPYWAVE_PRICING_MAP[model]
if (!pricing) throw new Error(`No CanopyWave pricing configured for model: ${model}`)
return pricing
}
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "Wire Kimi K2.6 via CanopyWave through to..." | Re-trigger Greptile
| export const FREEBUFF_MODELS: readonly FreebuffModelOption[] = [ | ||
| { | ||
| id: FREEBUFF_MINIMAX_MODEL_ID, | ||
| displayName: 'MiniMax M2.7', | ||
| tagline: 'Fastest', | ||
| availability: 'always', | ||
| }, | ||
| { | ||
| id: FREEBUFF_GLM_MODEL_ID, | ||
| displayName: 'GLM 5.1', | ||
| id: FREEBUFF_KIMI_MODEL_ID, | ||
| displayName: 'Kimi K2.6', | ||
| tagline: 'Smartest', | ||
| availability: 'deployment_hours', | ||
| availability: 'always', | ||
| }, | ||
| ] as const satisfies readonly FreebuffModelOption[] | ||
| ] | ||
|
|
||
| export type FreebuffModelId = (typeof FREEBUFF_MODELS)[number]['id'] | ||
| export type FreebuffModelId = | ||
| | typeof FREEBUFF_MINIMAX_MODEL_ID | ||
| | typeof FREEBUFF_KIMI_MODEL_ID |
There was a problem hiding this comment.
as const satisfies removal makes FreebuffModelId drift-prone
Switching from as const satisfies readonly FreebuffModelOption[] to an explicit readonly FreebuffModelOption[] annotation widens the inferred element types to string, which is why FreebuffModelId had to be redefined as a manual union. The old pattern was simpler: a new entry in FREEBUFF_MODELS automatically expanded the union type with no extra edit required.
export const FREEBUFF_MODELS = [
{
id: FREEBUFF_MINIMAX_MODEL_ID,
displayName: 'MiniMax M2.7',
tagline: 'Fastest',
availability: 'always',
},
{
id: FREEBUFF_KIMI_MODEL_ID,
displayName: 'Kimi K2.6',
tagline: 'Smartest',
availability: 'always',
},
] as const satisfies readonly FreebuffModelOption[]
export type FreebuffModelId = (typeof FREEBUFF_MODELS)[number]['id']This restores the original self-maintaining type while keeping the readonly FreebuffModelOption[] constraint via satisfies.
Prompt To Fix With AI
This is a comment left during a code review.
Path: common/src/constants/freebuff-models.ts
Line: 42-59
Comment:
**`as const satisfies` removal makes `FreebuffModelId` drift-prone**
Switching from `as const satisfies readonly FreebuffModelOption[]` to an explicit `readonly FreebuffModelOption[]` annotation widens the inferred element types to `string`, which is why `FreebuffModelId` had to be redefined as a manual union. The old pattern was simpler: a new entry in `FREEBUFF_MODELS` automatically expanded the union type with no extra edit required.
```ts
export const FREEBUFF_MODELS = [
{
id: FREEBUFF_MINIMAX_MODEL_ID,
displayName: 'MiniMax M2.7',
tagline: 'Fastest',
availability: 'always',
},
{
id: FREEBUFF_KIMI_MODEL_ID,
displayName: 'Kimi K2.6',
tagline: 'Smartest',
availability: 'always',
},
] as const satisfies readonly FreebuffModelOption[]
export type FreebuffModelId = (typeof FREEBUFF_MODELS)[number]['id']
```
This restores the original self-maintaining type while keeping the `readonly FreebuffModelOption[]` constraint via `satisfies`.
How can I resolve this? If you propose a fix, please make it concise.| function getCanopyWavePricing(model: string): CanopyWavePricing { | ||
| return CANOPYWAVE_PRICING_MAP[model] ?? CANOPYWAVE_PRICING_MAP['moonshotai/kimi-k2.6'] | ||
| } |
There was a problem hiding this comment.
Silent pricing fallback for unknown CanopyWave models
getCanopyWavePricing falls back to kimi-k2.6 rates for any model not in CANOPYWAVE_PRICING_MAP. Since a model can only reach this function if it passed isCanopyWaveModel (i.e. it's already in CANOPYWAVE_MODEL_MAP), a missing pricing entry means a future model would silently be billed at kimi prices rather than its own. Throwing here would surface the misconfiguration immediately:
function getCanopyWavePricing(model: string): CanopyWavePricing {
const pricing = CANOPYWAVE_PRICING_MAP[model]
if (!pricing) throw new Error(`No CanopyWave pricing configured for model: ${model}`)
return pricing
}Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/llm-api/canopywave.ts
Line: 109-111
Comment:
**Silent pricing fallback for unknown CanopyWave models**
`getCanopyWavePricing` falls back to kimi-k2.6 rates for any model not in `CANOPYWAVE_PRICING_MAP`. Since a model can only reach this function if it passed `isCanopyWaveModel` (i.e. it's already in `CANOPYWAVE_MODEL_MAP`), a missing pricing entry means a future model would silently be billed at kimi prices rather than its own. Throwing here would surface the misconfiguration immediately:
```ts
function getCanopyWavePricing(model: string): CanopyWavePricing {
const pricing = CANOPYWAVE_PRICING_MAP[model]
if (!pricing) throw new Error(`No CanopyWave pricing configured for model: ${model}`)
return pricing
}
```
How can I resolve this? If you propose a fix, please make it concise.# Conflicts: # web/src/llm-api/canopywave.ts
Summary
Test plan
🤖 Generated with Claude Code