Skip to content

Use CanopyWave Kimi K2.6 as base2-free model#548

Open
jahooma wants to merge 3 commits intomainfrom
canopy-wave-kimi
Open

Use CanopyWave Kimi K2.6 as base2-free model#548
jahooma wants to merge 3 commits intomainfrom
canopy-wave-kimi

Conversation

@jahooma
Copy link
Copy Markdown
Contributor

@jahooma jahooma commented Apr 25, 2026

Summary

  • Switch base2-free (and editor-lite, code-reviewer-lite) from Fireworks GLM 5.1 to CanopyWave Kimi K2.6
  • Wire CanopyWave routing in the web chat-completions endpoint (was previously dead-coded behind `useCanopyWave = false`)
  • Add per-model pricing in canopywave.ts so kimi-k2.6 is billed correctly
  • Update freebuff model registry, free-mode whitelist, instant-admit capacity, and rate limits

Test plan

  • `bun tsc --noEmit` passes for web, common, agents, cli
  • `web/src/server/free-session` tests pass
  • `web/src/app/api/v1/chat/completions/tests/completions.test.ts` passes (now asserts CanopyWave routing)
  • `web/src/app/api/v1/freebuff/session/tests/session.test.ts` passes
  • `agents/tests/editor.test.ts` passes
  • `cli/src/utils/tests/freebuff-model-navigation.test.ts` passes
  • Smoke-test end-to-end: `bun scripts/test-canopywave.ts both` against a running web instance

🤖 Generated with Claude Code

jahooma and others added 2 commits April 25, 2026 12:41
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This 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 canopywave.ts. The mechanical rename across agents, registry, whitelist, config, and tests is consistent and correct.

Confidence Score: 5/5

Safe to merge; only P2 suggestions remain.

All routing, pricing, and whitelist changes are consistent across the codebase. Remaining findings are style/maintainability suggestions (restoring as const satisfies, hardening the pricing fallback) with no impact on correctness.

common/src/constants/freebuff-models.ts (type maintainability), web/src/llm-api/canopywave.ts (pricing fallback)

Important Files Changed

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

Comment on lines +42 to +59
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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Comment thread web/src/llm-api/canopywave.ts Outdated
Comment on lines +109 to +111
function getCanopyWavePricing(model: string): CanopyWavePricing {
return CANOPYWAVE_PRICING_MAP[model] ?? CANOPYWAVE_PRICING_MAP['moonshotai/kimi-k2.6']
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant