Skip to content

Kimi OAuth: auto context tier for k3 (k3-256k → k3 wire upgrade) - #416

Open
Acters wants to merge 2 commits into
aebrer:masterfrom
Acters:feature/issue-415-k3-auto-context-tier
Open

Kimi OAuth: auto context tier for k3 (k3-256k → k3 wire upgrade)#416
Acters wants to merge 2 commits into
aebrer:masterfrom
Acters:feature/issue-415-k3-auto-context-tier

Conversation

@Acters

@Acters Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes #415

The Kimi for Coding OAuth endpoint serves K3 as k3-256k (256k context, cheaper) and k3 (1M context, stated 2× quota), and switching from k3-256k to k3 seamlessly upgrades the prompt cache server-side. This PR exposes a single user-facing k3 model and automatically upgrades the wire model ID instead of compacting once session context passes the 256k cutoff (256k window minus the default compaction reserve):

  • New optional Model.wireModelId; the openai-completions provider sends it on the wire while recording the registry ID on assistant messages
  • New k3-context-tier.ts derives the effective model from current context tokens; AgentSession applies it on model set/cycle/refresh/restore/creation and upgrades ahead of compaction on both threshold and overflow paths (also when compaction is disabled, since no context reduction is involved)
  • Cutoff is fixed at the default compaction threshold of the 256k window, so a user-lowered compaction threshold compacts first and effectively disables the upgrade
  • New context_window_upgrade session event with interactive-mode status line; footer reflects the effective window
  • OAuth discovery never surfaces k3-256k as a separate selectable model

Scoped to kimi-coding-oauth only — k3-256k is exclusive to the Kimi for Coding OAuth endpoint; the pay-per-token Moonshot AI Platform does not expose it.

Implementation plan posted as a comment below.

The Kimi coding endpoint serves K3 as k3-256k (256k context, cheaper) and
k3 (1M context, stated to consume 2x the quota — not independently
verified). Switching from k3-256k to k3 seamlessly upgrades the prompt
cache server-side. 256k is large enough for most tasks, so exposing a
single user-facing k3 model and automatically upgrading the wire model ID
once the session context passes the 256k cutoff (256k window minus the
default compaction reserve) keeps the bulk of sessions on the cheaper
variant and avoids compaction on long-horizon tasks.

- Add Model.wireModelId; openai-completions sends it on the wire while
  recording the registry id on assistant messages
- New k3-context-tier module derives the effective model (256k tier with
  wireModelId k3-256k, or 1M tier) from current context tokens
- AgentSession applies the tier on model set/cycle/refresh/restore and
  session creation, and upgrades instead of compacting on both the
  threshold and overflow paths; upgrade runs even when compaction is
  disabled since no context reduction is involved
- Cutoff is fixed at the default compaction threshold of the 256k
  window, so a user-lowered compaction threshold compacts first and
  effectively disables the upgrade
- Emit context_window_upgrade session event; interactive mode shows a
  status line and the footer reflects the new window
- OAuth discovery never surfaces k3-256k as a separate selectable model
@Acters

Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Implementation Plan

Analysis

The Kimi for Coding OAuth endpoint serves K3 under two wire model IDs: k3-256k (256k context, cheaper) and k3 (1M context, stated 2× quota — unverified, but the stated rationale for switching). 256k is large enough for most tasks, and the Kimi backend team confirms switching from k3-256k to k3 seamlessly upgrades the prompt cache. dreb registered k3 as a single 1M-window model, so every request paid the 1M premium and auto-compaction was the only mitigation at the window limit.

Design decisions:

  • Registry identity stays k3 everywhere (selector, thinking-effort checks incl. xhigh, session model-change entries, restore, usage/cost tracking). Only the request payload carries the variant, via a new optional Model.wireModelId.
  • The tier is derived, not persisted: the effective model is a pure function of current context tokens, so session restore and post-compaction sessions re-derive the correct tier with no new session-file state.
  • Upgrade cutoff = 256k window − default compaction reserve (245,760 tokens), i.e. exactly where auto-compaction would fire under default settings for a 256k-window model. A user-lowered compaction threshold therefore compacts first and effectively disables the upgrade.
  • Scoped to kimi-coding-oauth/k3 onlyk3-256k is exclusive to the Kimi for Coding OAuth endpoint; the pay-per-token Moonshot AI Platform does not expose it.

Deliverables (implemented)

  1. packages/ai/src/types.ts — optional Model.wireModelId with docs.
  2. packages/ai/src/providers/openai-completions.ts — payload sends model.wireModelId ?? model.id; recorded assistant messages keep the registry ID.
  3. packages/ai/src/utils/oauth/kimi-coding.ts — discovery filters k3-256k so it never appears as a second selectable model.
  4. packages/coding-agent/src/core/k3-context-tier.ts (new) — tier constants and pure helpers (deriveK3ContextTierModel, shouldUpgradeK3Tier, isK3Model, isK3256kTier).
  5. packages/coding-agent/src/core/agent-session.ts — tier applied at every agent.setModel site (set/cycle/refresh/restore); _checkCompaction upgrades instead of compacting on the threshold path (ahead of shouldCompact) and on the overflow path (upgrade + retry, also when compaction.enabled is false; 1M-tier overflow keeps compact-and-retry); new context_window_upgrade session event.
  6. packages/coding-agent/src/core/sdk.ts — new sessions seed the 256k tier.
  7. packages/coding-agent/src/modes/interactive/interactive-mode.ts — status line on upgrade + footer refresh.
  8. Docs: providers.md (tier behavior, exclusivity, stated-quota caveat), rpc.md (event row).
  9. Tests: 22 new tests (below).

Acceptance criteria

  • Single selectable k3; discovery never surfaces k3-256k separately (unit test).
  • Fresh session sends k3-256k on the wire — verified live against the real endpoint with payload logging; resume (--continue) keeps the tier.
  • Crossing 245,760 context tokens upgrades subsequent requests to k3, emits context_window_upgrade, and performs no compaction — verified with unmocked AgentSession via the SDK (footer flipped ~94% → 23.6% of window).
  • User-lowered compaction threshold compacts first; no upgrade (unit test).
  • 256k-tier overflow upgrades and retries; 1M-tier overflow still compacts (unit tests).
  • Upgrade applies with compaction.enabled: false (unit test).
  • Full repo gate passes: biome, tsgo, 5112 tests (pre-commit hook). One unrelated pre-existing master failure in anthropic-auth-integration.test.ts reproduces on clean master.

Testing approach

  • packages/coding-agent/test/k3-context-tier.test.ts (11 tests): pure helpers — derivation both directions, cutoff inclusivity, idempotency, non-k3 passthrough.
  • packages/coding-agent/test/k3-context-tier-session.test.ts (8 tests): AgentSession with mocked compaction module — setModel derives 256k tier, upgrade-instead-of-compact at default threshold, no-op below cutoff, lowered threshold compacts first, overflow upgrade + retry (incl. compaction disabled), 1M-tier overflow falls back to compaction.
  • packages/ai/test/openai-completions-kimi.test.ts (2 new tests): payload carries wireModelId / falls back to registry id; recorded message keeps registry id.
  • packages/ai/test/kimi-coding-oauth.test.ts (1 new test): discovered k3-256k is filtered from the selectable list.
  • Live smoke: two minimal-quota prompts against the production endpoint (fresh + resumed session), payload verified as k3-256k with thinking effort mapping intact.

Risks and open questions

  • The 2× quota figure is stated by the Kimi team and not independently verified; code comments and docs phrase it as such.
  • Derivation is conservative: if Kimi later advertises a different k3 window, K3_1M_CONTEXT_WINDOW in k3-context-tier.ts should be updated alongside the registry entry.
  • Out of scope (possible follow-up, needs maintainer agreement): the API-key kimi-coding provider (same coding endpoint, Anthropic-compatible) could receive the same treatment; the Moonshot AI Platform is not applicable.

Plan created by mach6

@Acters
Acters marked this pull request as ready for review July 30, 2026 01:40
@Acters

Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Code Review

Critical

None.

Important

  1. Threshold-based upgrade suppressed when compaction is disabled (code-reviewer, error-auditor, completeness-checker; conf. 98–99) — agent-session.ts _checkCompaction: the threshold path returns at the !settings.enabled gate before evaluating shouldUpgradeK3Tier. With compaction disabled, a successful response crossing 245,760 stays on k3-256k until an actual overflow triggers the Case 1 upgrade. Conflicts with acceptance criterion 6 ("Upgrade occurs even when auto-compaction is disabled").

  2. SDK resume does not re-derive the tier; post-compaction sessions stay in the 1M tier (completeness-checker, code-reviewer; conf. 99) — sdk.ts seeds deriveK3ContextTierModel(model, 0) then restores messages without re-deriving (--continue with >cutoff context starts on k3-256k; switchSession does re-derive). Also _runAutoCompaction replaces messages without re-deriving, so a compacted session keeps paying 1M rates. Conflicts with acceptance criterion 7.

  3. Upgrade can pre-empt a user-configured compaction threshold on large single-response jumps (completeness-checker, error-auditor; conf. 98–99) — the upgrade runs before shouldCompact; after upgrading, the window is 1M, so a user threshold (e.g. reserveTokens: 100000 → compact above 162,144) is skipped if one response jumps past the cutoff. Ordering vs acceptance criterion 4 needs review.

  4. Missing test coverage for scoped behaviors (test-reviewer; conf. 97–98) — fresh-session bootstrap via createAgentSession; pre-prompt path (skipAbortedCheck=false); non-K3 overflow with compaction disabled after the settings-gate move (regression protection); restore/cycle/refresh derivation sites (criterion 7).

Suggestions

  1. Delayed retry timer survives disposal/state changes (error-auditor, conf. 99) — the 100ms setTimeout retry is not cancellable; continue() can run after disposal or a model switch. (Same pre-existing pattern as the compaction retry.)

  2. Derivation ignores models.json context-window overrides (error-auditor, conf. 94) — a user override of k3.contextWindow is silently replaced by the tier constants.

  3. Test-quality improvements (test-reviewer, conf. 86–98) — boundary test at exactly 245,760; compaction mock diverges from real estimateContextTokens semantics (trailing tokens); disabled-compaction test should assert retry + no-compaction; interactive status-line rendering untested; upgrade event assertions should check payload/count; thinking-effort mapping on a derived tiered model untested.

  4. Simplifications (simplifier, conf. 96–98) — extract the three duplicated "remove last assistant message" blocks into a helper; drop the redundant && this._tryUpgradeK3ContextTier() boolean after shouldUpgradeK3Tier.

Strengths

  • Registry identity (k3) stays stable everywhere — selector, thinking checks (xhigh), session model-change entries, restore matching, and usage tracking all work unmodified; only the payload carries the variant via Model.wireModelId.
  • Tier derivation is pure, idempotent, and centralized in one small module with clear constants.
  • Live verification against the production endpoint confirmed k3-256k acceptance on fresh and resumed sessions.
  • Overflow upgrade reuses the existing recovery ordering; 1M-tier overflow correctly falls back to compact-and-retry.

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier


Reviewed by mach6

@Acters

Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Review Assessment

Assessed against review comment, verified against the actual code at 54365f4.

Classifications

Finding Classification Reasoning
1. Disabled compaction suppresses threshold upgrade genuine Factual: threshold path returns at the !settings.enabled gate before evaluating the upgrade. Scope: violates acceptance criterion 6.
2. Resume/post-compaction tier not re-derived genuine Factual: sdk.ts derives with 0 then restores messages without re-deriving; _runAutoCompaction likewise. Scope: violates criterion 7 and the plan's "derived, not persisted" requirement.
3. Large jumps bypass a lowered compaction threshold genuine Factual: upgrade runs before shouldCompact; after upgrading, the 1M window skips a user threshold (e.g. 162,144) when one response jumps past the cutoff. Scope: violates criterion 4.
4. Missing createAgentSession bootstrap test genuine Factual: no test covers the new SDK bootstrap path. Scope: fresh-session wire selection is criterion 2.
5. Missing pre-prompt (skipAbortedCheck=false) test genuine Factual: only the agent-end path is tested. Scope: the modified compaction logic must be protected on both paths.
6. Missing non-K3 disabled-overflow regression test genuine Factual: the settings gate moved into shared overflow logic with no regression test. Scope: PR-introduced regression surface; existing behavior must be preserved.
7. Missing restore/cycle/refresh derivation tests genuine Factual: only direct setModel is tested. Scope: plan requires derivation at each site; resume is criterion 7.
8. Retry timer uncancellable deferred Factual: accurate — untracked 100ms setTimeout. Scope: same pattern pre-exists in master's compaction retry; cancellation is outside this issue.
9. models.json context-window overrides ignored genuine Factual: derivation forcibly replaces a user-overridden k3.contextWindow. Scope: PR-introduced regression in supported model configuration.
10. No exact-cutoff _checkCompaction test deferred Factual: accurate; boundary covered in pure-helper tests. Scope: cutoff contract already covered; integration assertion optional.
11. Compaction mock diverges from real estimator deferred Factual: accurate (trailing tokens, no-usage fallback). Scope: fixture fidelity hardening, not a production defect.
12. Disabled-overflow test lacks retry/no-compaction assertions genuine Factual: only model and event checked. Scope: retry and no-compaction are explicit acceptance requirements.
13. Interactive status-line untested genuine Factual: new event handler never dispatched in tests. Scope: status rendering and footer refresh are required behavior.
14. Upgrade event payload/count weakly asserted genuine Factual: .some(...) only. Scope: event fields are part of the documented contract.
15. Derived-tier thinking mapping untested deferred Factual: accurate. Scope: mapping coverage exists; derivation preserves compat; no mapping code changed.
16. Extract duplicate removal blocks nitpick Factual: similar code in three places. Scope: refactor only.
17. Redundant upgrade boolean nitpick Factual: second check is implied. Scope: simplification only.

Action Plan

  1. Allow threshold-based K3 upgrades when compaction is disabled (finding 1).
  2. Check the user's configured 256k compaction threshold before applying the K3 upgrade, so lowered thresholds compact first even on large jumps (finding 3).
  3. Re-derive the tier after SDK session restore and after auto-compaction (finding 2).
  4. Preserve supported models.json context-window overrides safely (finding 9).
  5. Add tests: fresh SDK bootstrap, restore, cycle, refresh, pre-prompt paths (findings 4, 5, 7).
  6. Add non-K3 disabled-overflow regression coverage (finding 6).
  7. Assert disabled K3 overflow retries exactly once and never compacts (finding 12).
  8. Test interactive status/footer handling and exact upgrade event payload/count (findings 13, 14).

Assessment by mach6

- Threshold-path upgrade now fires even when compaction is disabled:
  the upgrade is model-capability management, not context reduction
- Resume re-derives the tier from restored session context instead of
  always starting in the 256k tier; compacted sessions return to the
  cheaper 256k wire tier (auto and manual compaction paths)
- models.json contextWindow overrides disable automatic tiering instead
  of being silently replaced
- A user-lowered compaction threshold preempts the upgrade even when a
  single response jumps straight past the cutoff
- Extract duplicated last-assistant-message removal into a helper and
  drop a redundant upgrade guard
- Tests: SDK bootstrap/resume, post-compaction tier return, override
  passthrough, jump precedence, pre-prompt path, non-K3 disabled-overflow
  regression, interactive status line, exact event payload assertions
@Acters

Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Progress Update

Implemented the genuine findings from the review assessment, scoped per maintainer-delegate review:

Behavioral fixes

  • Threshold-path upgrade now fires even when compaction is disabled — the upgrade is model-capability management, not context reduction (finding 1)
  • Resume re-derives the tier from restored session context; compacted sessions return to the cheaper 256k wire tier on both auto and manual compaction paths (finding 2)
  • User-lowered compaction threshold preempts the upgrade even when a single response jumps straight past the cutoff (finding 3)
  • models.json context-window overrides disable automatic tiering instead of being silently replaced (finding 9)

Cleanups

  • Extracted duplicated last-assistant-message removal into a helper; dropped a redundant upgrade guard (simplifier items)

Tests — 7 new + 3 strengthened: SDK bootstrap/resume, post-compaction tier return, override passthrough, jump precedence, pre-prompt path, non-K3 disabled-overflow regression, interactive status line + footer invalidation, exact event payload/count assertions, disabled-overflow retry assertion (findings 4–7, 12–14)

Deferred per assessment: uncancellable retry timer (pre-existing pattern in master's compaction retry), exact-cutoff integration test, mock fidelity, derived-tier thinking test.

Verified: biome clean, tsgo clean, full suites pass (coding-agent 2766, ai 326).

Commit: 0fe577e


Progress tracked by mach6

@Acters

Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Ready for maintainer publish

@aebrer — this PR is complete from the contributor side and ready for your publish decision (version bump, merge, tag, release are all yours).

State:

  • Based on current master (23d7ec8), two commits: 54365f4 (feature) and 0fe577e (review fixes)
  • Full local gate green on the head: biome, tsgo, coding-agent 2766 tests, ai 326 tests
  • Live-verified against the Kimi OAuth endpoint: k3-256k accepted on fresh and resumed sessions; upgrade path verified with the unmocked session machinery
  • mach6 self-review completed: 17 findings → 11 genuine (all fixed) → 4 deferred with reasons + 2 nitpicks; trail is in the comments above
  • Issue 415 updated to match the shipped behavior (all acceptance criteria checked)

Behavior in one paragraph: the single selectable k3 model starts every session on the cheaper k3-256k wire ID and upgrades to k3 at 245,760 context tokens (256k − default compaction reserve) instead of compacting — cache upgrades seamlessly server-side. Lowered compaction thresholds preempt the upgrade (effectively an opt-out), resume re-derives the tier, compacted sessions return to the cheaper tier, and a models.json context-window override disables tiering. Scoped strictly to kimi-coding-oauth; no other provider touched.

One pre-existing note: anthropic-auth-integration.test.ts flaked once locally on clean master (unrelated to this PR; passed in all gate runs since).


Progress tracked by mach6

@Acters

Acters commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

During the making of this PR, I was able to catch the model from going out of scope and overreaching. I further refined my local workflow to introduce tighter contributor role specific restrictions for the LLM to reason over issues without overstepping maintainer/owner boundary and stricter out-of-scope discipline.

I was able to complete this PR within the 256k context window. This proves that the 256k context is perfectly acceptable for even medium difficulty tasks and allows users(including me) to get the most out of their kimi code quota.

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.

Kimi OAuth: auto-upgrade k3 wire model ID from k3-256k to k3 at the 256k context cutoff

1 participant