|
960 | 960 | GROQ: { name:'Groq', keyUrl:'https://console.groq.com/keys', keyLabel:'Get API Key for Groq' }, |
961 | 961 | VERCEL: { name:'Vercel', keyUrl:'https://vercel.com/ai-gateway', keyLabel:'Get API Key for Vercel' }, |
962 | 962 | CLOUDFLARE:{ name:'Cloudflare',keyUrl:'https://dash.cloudflare.com/', keyLabel:'Get API Key for Cloudflare' }, |
| 963 | + KILO: { name:'Kilo', keyUrl:'https://app.kilo.ai/settings/api-keys', keyLabel:'Get API Key for Kilo (optional)' }, |
963 | 964 | HUMAN_EXPERT:{ name:'Human Expert', keyUrl:'', keyLabel:'' }, |
964 | 965 | }; |
965 | 966 |
|
966 | | -const PROVIDER_ORDER = ['VERCEL','CEREBRAS','GOOGLE','MISTRAL','GROQ','CLOUDFLARE','PUTER']; |
| 967 | +const PROVIDER_ORDER = ['VERCEL','CEREBRAS','GOOGLE','MISTRAL','GROQ','CLOUDFLARE','KILO','PUTER']; |
967 | 968 |
|
968 | 969 | /* ════════════════════════════════════════════════════════ |
969 | 970 | CUSTOM PROVIDERS — add a genuinely new provider/model here, entirely in |
|
1018 | 1019 | { id:'PUTER_QWEN2_5_VL_72B', displayName:'Qwen3.7 Plus (Puter)', modelName:'qwen/qwen3.7-plus', apiProvider:'PUTER', supportsScreenshot:true, supportsTopK:false, supportsThinking:true, isOffline:false, hint:'$0.32/M input | $1.28/M output – thinking enabled', strike:false }, |
1019 | 1020 | { id:'PUTER_LING_3_FLASH', displayName:'Ling 3.0 Flash (Puter)', modelName:'inclusionai/ling-3.0-flash:free', apiProvider:'PUTER', supportsScreenshot:false, supportsTopK:false, supportsThinking:true, isOffline:false, hint:'Free - Free access is only available for a short time; after that, access will be interrupted server-side. – thinking enabled', strike:false }, |
1020 | 1021 | { id:'PUTER_NEMOTRON_3_NANO_OMNI_30B', displayName:'Nemotron 3 Nano Omni 30B A3B (Puter)', modelName:'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free', apiProvider:'PUTER', supportsScreenshot:true, supportsTopK:false, supportsThinking:true, isOffline:false, hint:'free - Can watch videos. Free models could be deactivated server-side at any time – thinking enabled', strike:false }, |
| 1022 | + { id:'KILO_NEMOTRON_3_ULTRA_550B', displayName:'Nemotron 3 Ultra 550B A55B (Kilo)', modelName:'nvidia/nemotron-3-ultra-550b-a55b:free', apiProvider:'KILO', supportsScreenshot:false, supportsTopK:false, supportsThinking:false, isOffline:false, hint:'200 requests/hour per IP address are free', strike:false }, |
1021 | 1023 | { id:'GROQ_QWEN3_6_27B', displayName:'Qwen3.6 27B (Groq)', modelName:'qwen/qwen3.6-27b', apiProvider:'GROQ', supportsScreenshot:false, supportsTopK:true, supportsThinking:true, isOffline:false, hint:'30 free requests per min – thinking enabled', strike:false }, |
1022 | 1024 | { id:'GROQ_GPT_OSS_120B', displayName:'GPT-OSS 120B (Groq)', modelName:'openai/gpt-oss-120b', apiProvider:'GROQ', supportsScreenshot:false, supportsTopK:true, supportsThinking:true, isOffline:false, hint:'30 free requests per min – thinking enabled', strike:false }, |
1023 | 1025 | { id:'MISTRAL_LARGE_3', displayName:'Mistral Large 3', modelName:'mistral-large-latest', apiProvider:'MISTRAL', supportsScreenshot:true, supportsTopK:false, supportsThinking:false, isOffline:false, hint:'', strike:false }, |
|
1506 | 1508 | if (!m) return true; |
1507 | 1509 | if (m.id === 'HUMAN_EXPERT') return true; |
1508 | 1510 | if (m.isOffline) return true; |
| 1511 | + // KILO free tier needs no API key (anonymous, 200 req/h per IP); key is optional for paid use. |
| 1512 | + if (m.apiProvider === 'KILO') return true; |
1509 | 1513 | if (m.apiProvider === 'CUSTOM') { |
1510 | 1514 | const keys = _getCustomModelApiKeys(m.id); |
1511 | 1515 | return keys.length > 0; |
|
2077 | 2081 | keyHeader: 'Authorization', |
2078 | 2082 | keyPrefix: 'Bearer ', |
2079 | 2083 | }, |
| 2084 | + KILO: { |
| 2085 | + endpoint: () => 'https://api.kilo.ai/api/gateway/chat/completions', |
| 2086 | + keyHeader: 'Authorization', |
| 2087 | + keyPrefix: 'Bearer ', |
| 2088 | + // Free tier: no API key required (200 req/hour per IP); key is optional for paid use. |
| 2089 | + keyOptional: true, |
| 2090 | + }, |
2080 | 2091 | }; |
2081 | 2092 |
|
2082 | 2093 | /* ── MAIN ENTRY POINT: called by Android for every AI turn ───── */ |
|
3255 | 3266 | keyHeader = provDef.keyHeader; |
3256 | 3267 | keyPrefix = provDef.keyPrefix || ''; |
3257 | 3268 | keys = Bridge.getAllApiKeys(provider); |
3258 | | - if (!keys.length) { |
| 3269 | + if (!keys.length && !provDef.keyOptional) { |
3259 | 3270 | Bridge.onCustomModelError('No API key for ' + provider + '. Please add one in the menu.'); |
3260 | 3271 | return; |
3261 | 3272 | } |
3262 | 3273 | keyIdx = Bridge.getCurrentKeyIndex(provider) || 0; |
3263 | | - apiKey = keys[keyIdx] || keys[0]; |
| 3274 | + apiKey = keys.length ? (keys[keyIdx] || keys[0]) : undefined; |
3264 | 3275 | } else { |
3265 | 3276 | // Custom model (defined in CUSTOM_PROVIDERS above) – supports multiple keys with rotation |
3266 | 3277 | endpoint = payload.endpoint; |
|
5412 | 5423 | link.style.display = 'none'; |
5413 | 5424 | } |
5414 | 5425 | document.getElementById('new-key-input').placeholder = |
5415 | | - currentProviderId==='PUTER' ? 'Enter Puter Auth Token' : 'Enter '+PROVIDERS[currentProviderId]?.name+' API Key'; |
| 5426 | + currentProviderId==='PUTER' ? 'Enter Puter Auth Token' : |
| 5427 | + currentProviderId==='KILO' ? 'Enter Kilo API Key (optional – free without key)' : |
| 5428 | + 'Enter '+PROVIDERS[currentProviderId]?.name+' API Key'; |
5416 | 5429 | } |
5417 | 5430 | function renderKeyList() { |
5418 | 5431 | const list = document.getElementById('key-list'); |
|
0 commit comments