Add Together AI platform + bare-array listing tolerance (provider 9)

The 12th registry row: id "together", TOGETHER_API_KEY > auth.json
"together" scope, https://api.together.xyz/v1 with KIGI_TOGETHER_BASE_URL
override, Bearer, ChatCompletions + Passthrough, enrichment-backed
metadata (models_dev_id togetherai) with the tool-calling listing
restriction (Together's listing mixes chat/embedding/rerank/image types).

Together's GET /v1/models returns a BARE JSON ARRAY, not the OpenAI
{object:list,data:[]} envelope. New shared parser parse_openai_listing
tolerates both shapes (sniffs the top-level [ vs { for accurate
diagnostics); every OpenAI-listing provider now routes through it, with
byte-equivalent envelope behavior (verified: Groq/Google/OpenRouter
unchanged) and non-silent errors. Together's org/Model ids match the
togetherai snapshot keys exactly (verified), so restrict_to_enriched keeps
the ~27 tool-calling models without the id-shape trap.

Review: ship-ready, shared-parser change proven strictly-additive and safe,
registry/e2e/dialect all correct. Backlog logged: kigi ignores the wire
per-model  field, so a live Together chat model absent from
models.dev is dropped until indexed — a future wire- filter would
unlock the fresh full catalog.
This commit is contained in:
2026-07-21 13:16:20 -04:00
parent e7dbb98207
commit 0a147bd8a5
4 changed files with 190 additions and 10 deletions
+10 -3
View File
@@ -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(), 12, "11 login rows + Quit, got {items:?}");
assert_eq!(items.len(), 13, "12 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 {:?}",
@@ -6971,7 +6971,14 @@ pub(crate) mod tests {
label: "OpenRouter (API key)".into(),
}
);
assert_eq!(items[11], PendingMenuItem::Quit);
assert_eq!(
items[11],
PendingMenuItem::ApiKey {
target: PlatformLogin(kigi_shell::models::PlatformId::Together),
label: "Together AI (API key)".into(),
}
);
assert_eq!(items[12], 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 {
@@ -6982,7 +6989,7 @@ pub(crate) mod tests {
);
assert_eq!(
pending_menu_items(&byok.methods, None).len(),
12,
13,
"xai.api_key / cached_token must not add rows"
);
}