feat(providers): add Z.AI coding plan (global + China)
Providers 17-18 (20th & 21st registry variants), sourced authoritatively
from Pi (earendil-works/pi), the open-source agent whose provider list is
being mirrored. Pi's zai.ts / zai-coding-cn.ts use plain openAICompletionsApi
(NO special thinking dialect — overturns the matrix's 'thinking:{type} → new
dialect' concern), so Kigi maps them to Passthrough. Global: api.z.ai/api/
coding/paas/v4, ZAI_API_KEY, models.dev zai-coding-plan. China (Zhipu
BigModel): open.bigmodel.cn/api/coding/paas/v4, ZAI_CODING_CN_API_KEY,
models.dev zhipuai-coding-plan. Both Bearer + OpenAI listing + ChatCompletions
+ restrict_to_enriched; /models is auth-gated → validator.
id-match is PROVEN (not just assumed like Qwen): Pi's static model ids
[glm-4.5-air, glm-4.7, glm-5-turbo, glm-5.1, glm-5.2, glm-5v-turbo] are
byte-identical to the models.dev zai-coding-plan keys, all tool_call=true, so
restrict keeps every model with no silent-empty risk. Review found no defects.
GLM thinking is not lost (reasoning_content is parsed regardless of dialect).
Tests: e2e proves enrichment-supplied context + non-vacuous restrict (a
non-enriched wire model is dropped) + Passthrough; both variants' validation
tests hit /models and assert the per-variant console host (z.ai vs
open.bigmodel.cn). Registry at 21; picker 22 rows.
Also fixes the welcome login-picker test for the now-taller menu (renders at
a taller viewport to verify content coverage) and logs the real menu-overflow
UX debt: the picker clips rows past the fold with no scroll (q/l shortcuts
still work; only shown when unauthenticated) — deferred to its own cycle.
This commit is contained in:
@@ -6894,7 +6894,7 @@ pub(crate) mod tests {
|
||||
#[test]
|
||||
fn pending_menu_items_lists_interactive_methods_plus_quit() {
|
||||
let items = pending_menu_items(&fresh_user_auth_methods(), None);
|
||||
assert_eq!(items.len(), 20, "19 login rows + Quit, got {items:?}");
|
||||
assert_eq!(items.len(), 22, "21 login rows + Quit, got {items:?}");
|
||||
assert!(
|
||||
matches!(&items[0], PendingMenuItem::Login { label } if label == "Kimi Code (OAuth)"),
|
||||
"row 0 must be the OAuth login, got {:?}",
|
||||
@@ -7027,7 +7027,21 @@ pub(crate) mod tests {
|
||||
label: "Kimi For Coding (API key)".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(items[19], PendingMenuItem::Quit);
|
||||
assert_eq!(
|
||||
items[19],
|
||||
PendingMenuItem::ApiKey {
|
||||
target: PlatformLogin(kigi_shell::models::PlatformId::Zai),
|
||||
label: "Z.AI (API key)".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
items[20],
|
||||
PendingMenuItem::ApiKey {
|
||||
target: PlatformLogin(kigi_shell::models::PlatformId::ZaiCodingCn),
|
||||
label: "Z.AI Coding China (API key)".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(items[21], PendingMenuItem::Quit);
|
||||
// The non-interactive methods must never appear as rows.
|
||||
let byok = kigi_shell::agent::auth_method::build_auth_methods(
|
||||
kigi_shell::agent::auth_method::AuthMethodsBuildInputs {
|
||||
@@ -7038,7 +7052,7 @@ pub(crate) mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
pending_menu_items(&byok.methods, None).len(),
|
||||
20,
|
||||
22,
|
||||
"xai.api_key / cached_token must not add rows"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2070,7 +2070,16 @@ mod tests {
|
||||
}
|
||||
|
||||
fn render_done_text(params: &WelcomeRenderParams<'_>) -> String {
|
||||
let area = Rect::new(0, 0, 100, 40);
|
||||
render_done_text_h(params, 40)
|
||||
}
|
||||
|
||||
/// Render at an explicit height. The login picker lists one row per
|
||||
/// advertised platform; with ~20 API-key providers the menu no longer
|
||||
/// fits a 40-row viewport, so the full-menu content test needs more rows
|
||||
/// to verify every label renders. (On-terminal, rows past the fold are
|
||||
/// clipped — the `q`/`l` shortcuts still work; see the menu-scroll debt.)
|
||||
fn render_done_text_h(params: &WelcomeRenderParams<'_>, height: u16) -> String {
|
||||
let area = Rect::new(0, 0, 100, height);
|
||||
let mut buf = Buffer::empty(area);
|
||||
let mut prompt = PromptWidget::new();
|
||||
let mut picker = PickerState::default();
|
||||
@@ -2093,7 +2102,9 @@ mod tests {
|
||||
let trust = TrustState::Done;
|
||||
let mut params = render_params(&auth, &trust, None);
|
||||
params.auth_methods = &built.methods;
|
||||
let text = render_done_text(¶ms);
|
||||
// Tall viewport so every advertised login row renders (the picker now
|
||||
// lists ~20 platforms); this asserts content coverage, not fit.
|
||||
let text = render_done_text_h(¶ms, 72);
|
||||
assert!(text.contains("Kimi Code (OAuth)"), "{text}");
|
||||
assert!(
|
||||
text.contains("Moonshot Open Platform (API key \u{b7} moonshot.cn)"),
|
||||
|
||||
Reference in New Issue
Block a user