opencode-navigator 0.21.1 → 0.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +18 -13
- package/dist/provider-limits.js +330 -266
- package/dist/tui.js +94 -73
- package/package.json +1 -1
package/dist/provider-limits.js
CHANGED
|
@@ -362,36 +362,63 @@ return{link,busy
|
|
|
362
362
|
import {effect as _$effect} from "@opentui/solid"
|
|
363
363
|
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
364
364
|
import {insert as _$insert} from "@opentui/solid"
|
|
365
|
-
import {memo as _$memo} from "@opentui/solid"
|
|
366
365
|
import {setProp as _$setProp} from "@opentui/solid"
|
|
367
366
|
import {createElement as _$createElement} from "@opentui/solid"
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
return `${
|
|
371
|
-
if(
|
|
372
|
-
return `${
|
|
373
|
-
|
|
367
|
+
import {useIcons} from "./tui.js"
|
|
368
|
+
function duration(minutes){if(minutes%10080===0)
|
|
369
|
+
return `${minutes / 10080}w`
|
|
370
|
+
if(minutes%1440===0)
|
|
371
|
+
return `${minutes / 1440}d`
|
|
372
|
+
if(minutes%60===0)
|
|
373
|
+
return `${minutes / 60}h`
|
|
374
|
+
return `${minutes}m`
|
|
375
|
+
}
|
|
376
|
+
function measurement(window,remaining){if(remaining!==undefined)
|
|
377
|
+
return `${remaining}${window.unit === "%" ? "" : " "}${window.unit} left`
|
|
378
|
+
if(window.used!==undefined)
|
|
379
|
+
return `${window.used} ${window.unit} used`
|
|
380
|
+
return `${window.total} ${window.unit} capacity`
|
|
381
|
+
}
|
|
382
|
+
function resetTime(seconds,now){if(seconds===undefined)
|
|
383
|
+
return "Reset time unknown"
|
|
384
|
+
const date=new Date(seconds*1000)
|
|
385
|
+
const clock=date.toLocaleTimeString(undefined,{hour:"2-digit",minute:"2-digit"})
|
|
386
|
+
if(date.toDateString()===new Date(now).toDateString())
|
|
387
|
+
return `Resets ${clock}`
|
|
388
|
+
return `Resets ${date.toLocaleDateString(undefined, { month: "short", day: "numeric" })} ${clock}`
|
|
374
389
|
}
|
|
375
|
-
|
|
390
|
+
function quotaPresentation(window,now=Date.now()){const total=window.unit==="%"?100:window.total
|
|
391
|
+
const remaining=window.remaining??(total!==undefined&&window.used!==undefined?total-window.used:undefined)
|
|
392
|
+
const ratio=remaining!==undefined&&total!==undefined&&total>0?Math.max(0,Math.min(1,remaining / total)):undefined
|
|
393
|
+
const account=window.scope==="account"?"Account":undefined
|
|
394
|
+
const scope=window.kind==="rate_limit"?"API":account
|
|
395
|
+
const period=window.durationMinutes?duration(window.durationMinutes):undefined
|
|
396
|
+
const context=[scope,window.kind?window.label:period??window.label,window.kind?period:undefined].filter(Boolean).join(" \xB7 ")
|
|
397
|
+
return{value:measurement(window,remaining),ratio,reset:`${resetTime(window.resetsAt, now)} \xB7 ${context}`}}
|
|
398
|
+
function QuotaWindowRow(props){const icons=useIcons()
|
|
399
|
+
const view=()=>quotaPresentation(props.window)
|
|
400
|
+
const scale=()=>{const ratio=view().ratio
|
|
401
|
+
if(ratio===undefined)
|
|
402
|
+
return " \xB7 scale unknown"
|
|
403
|
+
const filled=Math.round(ratio*10)
|
|
404
|
+
const symbols=icons.style()==="text"?["#","-"]:["\u2588","\u2591"]
|
|
405
|
+
return ` [${symbols[0].repeat(filled)}${symbols[1].repeat(10 - filled)}]`
|
|
406
|
+
}
|
|
407
|
+
return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createElement("span"),_el$4=_$createElement("text")
|
|
376
408
|
_$insertNode(_el$,_el$2)
|
|
377
|
-
_$insertNode(_el$,_el$3)
|
|
378
409
|
_$insertNode(_el$,_el$4)
|
|
410
|
+
_$insertNode(_el$2,_el$3)
|
|
379
411
|
_$setProp(_el$2,"wrapMode","none")
|
|
380
412
|
_$setProp(_el$2,"truncate",true)
|
|
381
|
-
_$insert(_el$
|
|
382
|
-
_$insert(_el$2,
|
|
383
|
-
_$
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
_$
|
|
387
|
-
|
|
388
|
-
_$setProp(_el$4,"wrapMode","word")
|
|
389
|
-
_$insert(_el$4,(()=>{var _c$2=_$memo(()=>props.window.resetsAt===undefined)
|
|
390
|
-
return()=>_c$2()?"Reset time unavailable":`resets ${new Date(props.window.resetsAt * 1000).toLocaleString()}`
|
|
391
|
-
})())
|
|
392
|
-
_$effect((_p$)=>{var _v$=props.api.theme.current.text,_v$2=props.api.theme.current.text,_v$3=props.api.theme.current.textMuted
|
|
413
|
+
_$insert(_el$3,()=>view().value)
|
|
414
|
+
_$insert(_el$2,scale,null)
|
|
415
|
+
_$setProp(_el$4,"wrapMode","none")
|
|
416
|
+
_$setProp(_el$4,"truncate",true)
|
|
417
|
+
_$insert(_el$4,()=>view().reset)
|
|
418
|
+
_$effect((_p$)=>{var _v$=props.api.theme.current.textMuted,_v$2={fg:props.api.theme.current.text
|
|
419
|
+
},_v$3=props.api.theme.current.textMuted
|
|
393
420
|
_v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"fg",_v$,_p$.e))
|
|
394
|
-
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$3,"
|
|
421
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$3,"style",_v$2,_p$.t))
|
|
395
422
|
_v$3!==_p$.a&&(_p$.a=_$setProp(_el$4,"fg",_v$3,_p$.a))
|
|
396
423
|
return _p$
|
|
397
424
|
},{e:undefined,t:undefined,a:undefined
|
|
@@ -480,49 +507,32 @@ actions.review(option.value.slice("credit:".length)||undefined)
|
|
|
480
507
|
}})
|
|
481
508
|
}
|
|
482
509
|
import {createComponent as _$createComponent4} from "@opentui/solid"
|
|
483
|
-
import {effect as _$effect3} from "@opentui/solid"
|
|
484
|
-
import {insert as _$insert3} from "@opentui/solid"
|
|
485
|
-
import {memo as _$memo3} from "@opentui/solid"
|
|
486
|
-
import {setProp as _$setProp3} from "@opentui/solid"
|
|
487
|
-
import {createElement as _$createElement3} from "@opentui/solid"
|
|
488
510
|
import {For} from "solid-js"
|
|
489
511
|
import {effect as _$effect2} from "@opentui/solid"
|
|
490
|
-
import {memo as _$memo2} from "@opentui/solid"
|
|
491
|
-
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
492
512
|
import {insertNode as _$insertNode2} from "@opentui/solid"
|
|
493
513
|
import {insert as _$insert2} from "@opentui/solid"
|
|
514
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
494
515
|
import {setProp as _$setProp2} from "@opentui/solid"
|
|
495
516
|
import {createElement as _$createElement2} from "@opentui/solid"
|
|
496
|
-
function QuotaBalanceRow(props){return(()=>{var _el$=_$createElement2("
|
|
517
|
+
function QuotaBalanceRow(props){return(()=>{var _el$=_$createElement2("text"),_el$2=_$createElement2("span")
|
|
497
518
|
_$insertNode2(_el$,_el$2)
|
|
498
|
-
_$
|
|
499
|
-
_$
|
|
500
|
-
_$
|
|
501
|
-
_$insert2(_el$2,()=>props.balance.label,_el$3)
|
|
502
|
-
_$insert2(_el$2,()=>props.balance.scope,null)
|
|
503
|
-
_$setProp2(_el$4,"wrapMode","word")
|
|
504
|
-
_$insert2(_el$4,(()=>{var _c$=_$memo2(()=>!!props.balance.unlimited)
|
|
519
|
+
_$setProp2(_el$,"wrapMode","none")
|
|
520
|
+
_$setProp2(_el$,"truncate",true)
|
|
521
|
+
_$insert2(_el$2,(()=>{var _c$=_$memo(()=>!!props.balance.unlimited)
|
|
505
522
|
return()=>_c$()?"No configured cap":`${props.balance.amount} ${props.balance.unit ?? "(provider unit not specified)"}`
|
|
506
523
|
})())
|
|
507
|
-
_$
|
|
508
|
-
|
|
509
|
-
|
|
524
|
+
_$insert2(_el$,()=>` \xB7 ${props.balance.scope} \xB7 ${props.balance.label}`,null)
|
|
525
|
+
_$effect2((_p$)=>{var _v$=props.api.theme.current.textMuted,_v$2={fg:props.api.theme.current.text
|
|
526
|
+
}
|
|
527
|
+
_v$!==_p$.e&&(_p$.e=_$setProp2(_el$,"fg",_v$,_p$.e))
|
|
528
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp2(_el$2,"style",_v$2,_p$.t))
|
|
510
529
|
return _p$
|
|
511
530
|
},{e:undefined,t:undefined
|
|
512
531
|
})
|
|
513
532
|
return _el$
|
|
514
533
|
})()
|
|
515
534
|
}
|
|
516
|
-
function QuotaSnapshotRows(props){return [(()
|
|
517
|
-
_$setProp3(_el$,"wrapMode","none")
|
|
518
|
-
_$setProp3(_el$,"truncate",true)
|
|
519
|
-
_$insert3(_el$,()=>props.snapshot.providerName,null)
|
|
520
|
-
_$insert3(_el$,(()=>{var _c$=_$memo3(()=>!!props.snapshot.accountId)
|
|
521
|
-
return()=>_c$()?` \xB7 ${props.snapshot.accountId}`:""
|
|
522
|
-
})(),null)
|
|
523
|
-
_$effect3((_$p)=>_$setProp3(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
524
|
-
return _el$
|
|
525
|
-
})(),_$createComponent4(For,{get each(){return props.snapshot.windows
|
|
535
|
+
function QuotaSnapshotRows(props){return [_$createComponent4(For,{get each(){return props.snapshot.windows
|
|
526
536
|
},children:(window)=>_$createComponent4(QuotaWindowRow,{get api(){return props.api
|
|
527
537
|
},window
|
|
528
538
|
})
|
|
@@ -532,37 +542,6 @@ return _el$
|
|
|
532
542
|
})
|
|
533
543
|
})]
|
|
534
544
|
}
|
|
535
|
-
import {createComponent as _$createComponent5} from "@opentui/solid"
|
|
536
|
-
import {createSignal as createSignal4,onMount} from "solid-js"
|
|
537
|
-
import {SelectionMenu as SelectionMenu2,useDialogs as useDialogs2} from "./tui.js"
|
|
538
|
-
var rows=[["openai","OpenAI / Codex",["subscription","api-rate-limits"],"Verified Codex account quota shared across models; HTTP response request/token limits for API connections.","https://developers.openai.com/api/docs/guides/rate-limits"],["anthropic","Anthropic / Claude",["api-rate-limits","configured-limits"],"Model HTTP headers; eligible organization/admin credentials can read configured model limits. Claude subscription windows are separate.","https://platform.claude.com/docs/en/manage-claude/rate-limits-api"],["openrouter","OpenRouter",["key-budget","account-balance"],"Inference-key budget; account credits require a management key. Free-model request limits apply only to free variants.","https://openrouter.ai/docs/api/api-reference/api-keys/get-current-api-key"],["deepseek","DeepSeek",["account-balance"],"Provider-reported USD/CNY available, granted and topped-up balances.","https://api-docs.deepseek.com/api/get-user-balance"],["moonshotai","Moonshot / Kimi API",["account-balance"],"International USD balances; coding subscriptions are a different product.","https://platform.moonshot.ai/docs/api/balance"],["moonshotai-cn","Moonshot / Kimi API China",["account-balance"],"China CNY balances; never reuse an international key against the China endpoint.","https://platform.moonshot.cn/docs/api/balance"],["minimax","MiniMax",["subscription","account-balance"],"Token Plan model rows/explicit percentages; official SDK balance response for pay-as-you-go keys.","https://platform.minimax.io/docs/token-plan/faq"],["minimax-cn","MiniMax China",["subscription","account-balance"],"Region-specific native Token Plan and SDK balance endpoints.","https://github.com/MiniMax-AI/cli/tree/main/src/sdk/quota"],["github-copilot","GitHub Copilot",["subscription"],"Official SDK token-scoped quota/model RPC; no direct copilot_internal calls or ambient CLI login.","https://github.com/github/copilot-sdk/blob/main/docs/features/usage-and-billing.md"],["groq","Groq",["api-rate-limits"],"Native model response headers: requests per day and tokens per minute.","https://console.groq.com/docs/rate-limits"],["fireworks-ai","Fireworks",["configured-limits","api-rate-limits"],"Native model token/second capacities and account monthly spend quota; GPU quotas are excluded.","https://docs.fireworks.ai/serverless/rate-limits"],["siliconflow","SiliconFlow",["account-balance"],"Native current-user balances; retain unknown currency when the API does not report it.","https://docs.siliconflow.com/en/api-reference/userinfo/get-user-info"],["siliconflow-cn","SiliconFlow China",["account-balance"],"Region-specific current-user balances; currency is unknown when the API omits it.","https://docs.siliconflow.cn/"],["novita-ai","Novita",["account-balance"],"Native current-user balances in 1/10000 USD.","https://novita.ai/docs/api-reference/basic-get-user-balance"],["poe","Poe",["account-balance"],"API account point balance; includes plan and add-on points, not session token usage.","https://creator.poe.com/docs/resources/usage-api"],["nano-gpt","NanoGPT",["account-balance","subscription"],"Native USD/Nano balance and documented subscription token windows; null/degraded counters remain unknown.","https://docs.nano-gpt.com/api-reference/endpoint/subscription-usage"],["aihubmix","AIHubMix",["account-balance"],"Current-account balance API needs a Manage Key; inference keys do not grant management access.","https://docs.aihubmix.com/en/api/CliEndpoints/get-self"],["azure","Azure OpenAI",["api-rate-limits"],"Remaining request/token headers for the actual deployment; no ChatGPT subscription or inferred cloud balance.","https://learn.microsoft.com/en-us/azure/ai-foundry/openai/quotas-limits"],["cerebras","Cerebras",["api-rate-limits"],"Only self-describing native counters actually returned for the selected model; console tier examples are not live quota.","https://inference-docs.cerebras.ai/support/rate-limits"],["mistral","Mistral",[],"Documented remaining header lacks a verified unit/window association; no inferred subscription balance.","https://docs.mistral.ai/resources/known-limitations"],["togetherai","Together AI",[],"Dynamic model limits expose retry intervals, not remaining quota; billing UI does not establish a remaining-credit API.","https://docs.together.ai/docs/rate-limits"],["xai","xAI / Grok",[],"Management billing needs separate team credentials; no verified portable remaining API for this inference connection.","https://docs.x.ai/"],["perplexity","Perplexity",[],"No verified remaining-credit API for an inference key. API credits, consumer subscriptions and Computer credits are distinct.","https://www.perplexity.ai/help-center/en/articles/10354847-api-payment-and-billing"],["google","Google Gemini",["configured-limits"],"Native model-matched QuotaFailure responses when provided; cloud quota permissions differ from an inference key.","https://ai.google.dev/gemini-api/docs/rate-limits"],["google-vertex","Google Vertex AI",["configured-limits"],"Native model-matched quota error details; cloud project/region management and dynamic shared quotas are separate.","https://cloud.google.com/vertex-ai/generative-ai/docs/quotas"],["amazon-bedrock","Amazon Bedrock",[],"Service Quotas/CloudWatch require cloud IAM/region/model mapping not exposed by a portable inference connection.","https://docs.aws.amazon.com/bedrock/latest/userguide/quotas.html"],["cloudflare-workers-ai","Cloudflare Workers AI",[],"Account analytics do not prove remaining free allowance; separate account management capability is required.","https://developers.cloudflare.com/workers-ai/platform/limits/"],["huggingface","Hugging Face Inference Providers",[],"Hub request quota is not an inference-model quota or inference-credit balance.","https://huggingface.co/docs/inference-providers/pricing"],["zai","Z.ai / GLM Coding Plan",[],"No verified external quota contract for monitor/dashboard APIs; private endpoints are excluded.","https://docs.z.ai/devpack/overview"],["kimi-for-coding","Kimi Code subscription",[],"Keep separate from Moonshot API balance; an external subscription usage contract/model mapping must be verified.","https://www.kimi.com/code/docs/en/"],["alibaba","Alibaba Cloud / Qwen / DashScope",[],"Cloud account/project billing permissions and model mapping are required; browser OAuth state is not a quota source.","https://www.alibabacloud.com/help/en/model-studio/"],["opencode","OpenCode Zen / Go",[],"Session token/cost statistics are not provider quota; no undocumented billing endpoints.","https://opencode.ai/docs/zen/"],["cursor","Cursor",[],"Consumer usage needs a supported external API; no cookie or credential-file integrations.","https://docs.cursor.com/"],["windsurf","Windsurf / Codeium",[],"Consumer plan windows need a supported external API; no private account endpoints.","https://docs.windsurf.com/"],["amp","Amp",[],"Product credits need a supported external account API; no cookie or local credential extraction.","https://ampcode.com/manual"],["ollama","Ollama",[],"Local inference has no provider subscription window; cloud products require their own account API.","https://docs.ollama.com/api"],["lmstudio","LM Studio",[],"Local inference has no provider subscription quota to read.","https://lmstudio.ai/docs/developer"],["nvidia","NVIDIA NIM / NGC",[],"Inference access does not identify cloud/trial NGC credit balance or self-hosted resource quota.","https://docs.nvidia.com/nim/"],["cohere","Cohere",[],"No verified native remaining-counter contract for this integration; static organization tier examples are not live quotas.","https://docs.cohere.com/docs/rate-limits"],["ai21","AI21",[],"No verified native remaining-counter contract or subscription balance endpoint for this integration.","https://docs.ai21.com/"],["replicate","Replicate",[],"Prediction cost is not remaining account credit; no inferred balance from execution cost.","https://replicate.com/docs/topics/billing"],["chutes","Chutes",[],"Current-user quota APIs exist, but their public schemas do not establish native units/model allowance semantics yet.","https://chutes.ai/docs/api-reference/users"],["requesty","Requesty",[],"Enterprise management key and key ID are required; dated usage reports alone are not remaining budget.","https://docs.requesty.ai/features/key-management-api"],["baseten","Baseten",[],"No independently verified portable remaining quota API for the configured inference connection.","https://docs.baseten.co/"],["modelscope","ModelScope",[],"No independently verified portable remaining quota API/model mapping for the selected connection.","https://opencode.ai/docs/providers/"],["nebius","Nebius",[],"Cloud billing/management access is separate from a plain inference credential.","https://docs.nebius.com/"],["vultr","Vultr",[],"Cloud management quota/billing permissions are separate from inference access.","https://docs.vultr.com/"],["v0","Vercel v0",[],"Consumer/product credits need their own documented external account API.","https://v0.dev/docs"]]
|
|
539
|
-
var PROVIDER_QUOTA_CAPABILITIES= rows.map(([id,name,sources,reason,url])=>({id,name,sources,reason,documentation:[url]}))
|
|
540
|
-
var aliases={fireworks:"fireworks-ai",novita:"novita-ai",moonshot:"moonshotai","minimax-coding-plan":"minimax","minimax-coding-plan-cn":"minimax-cn",together:"togetherai","silicon-flow":"siliconflow","github-copilot-enterprise":"github-copilot","google-vertex-anthropic":"google-vertex","z-ai":"zai",zhipuai:"zai",dashscope:"alibaba","alibaba-cn":"alibaba",qwen:"alibaba","opencode-go":"opencode","opencode-zen":"opencode",codeium:"windsurf","azure-cognitive-services":"azure"
|
|
541
|
-
}
|
|
542
|
-
function providerQuotaCapability(id,canonical){const key=aliases[canonical??id]??canonical??id
|
|
543
|
-
const found=PROVIDER_QUOTA_CAPABILITIES.find((entry)=>entry.id===key)
|
|
544
|
-
return found??{id,name:id,sources:[],reason:"No independent quota/balance API or native counter semantics are verified for this provider.",documentation:["https://opencode.ai/docs/providers/"]
|
|
545
|
-
}}
|
|
546
|
-
function providerQuotaCatalog(providers=[]){const entries=new Map(PROVIDER_QUOTA_CAPABILITIES.map((entry)=>[entry.id,entry]))
|
|
547
|
-
for(const provider of providers)
|
|
548
|
-
entries.set(provider.id,{...providerQuotaCapability(provider.id,provider.canonical),id:provider.id,name:provider.name
|
|
549
|
-
})
|
|
550
|
-
return [...entries.values()].sort((a,b)=>a.name.localeCompare(b.name))
|
|
551
|
-
}
|
|
552
|
-
function ProviderSupportDialog(props){const dialogs=useDialogs2(props.api)
|
|
553
|
-
const [entries,setEntries]=createSignal4(providerQuotaCatalog())
|
|
554
|
-
onMount(()=>{if(props.load)
|
|
555
|
-
props.load().then(setEntries).catch(()=>{})
|
|
556
|
-
})
|
|
557
|
-
return _$createComponent5(SelectionMenu2,{get api(){return props.api
|
|
558
|
-
},get title(){return `Provider sources \xB7 ${entries().length}`
|
|
559
|
-
},height:18,get options(){return [...entries().map((entry)=>({title:entry.name,value:entry.id,icon:entry.sources.length>0?"info":"help",description:`${entry.sources.length > 0 ? entry.sources.join(", ") : "API-dependent"} \xB7 ${entry.reason}`
|
|
560
|
-
})),{title:"Close",value:"close",description:"Return to the sidebar",icon:"close"
|
|
561
|
-
}]
|
|
562
|
-
},onSelect:(option)=>{if(option.value==="close")
|
|
563
|
-
dialogs.back()
|
|
564
|
-
}})
|
|
565
|
-
}
|
|
566
545
|
var text={type:"string",minLength:1,maxLength:512}
|
|
567
546
|
var model2={type:"object",properties:{providerID:text,modelID:text,sessionID:text,connectionID:text,variant:text,force:{type:"boolean"}},required:["providerID","modelID","sessionID"],additionalProperties:false
|
|
568
547
|
}
|
|
@@ -599,36 +578,42 @@ listeners.clear()
|
|
|
599
578
|
}}
|
|
600
579
|
return{adapter,onUpdated(listener){listeners.add(listener)
|
|
601
580
|
return()=>listeners.delete(listener)
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
}
|
|
581
|
+
}}}
|
|
582
|
+
var rows=[["openai","OpenAI / Codex",["subscription","api-rate-limits"],"Verified Codex account quota shared across models; HTTP response request/token limits for API connections.","https://developers.openai.com/api/docs/guides/rate-limits"],["anthropic","Anthropic / Claude",["api-rate-limits","configured-limits"],"Model HTTP headers; eligible organization/admin credentials can read configured model limits. Claude subscription windows are separate.","https://platform.claude.com/docs/en/manage-claude/rate-limits-api"],["openrouter","OpenRouter",["key-budget","account-balance"],"Inference-key budget; account credits require a management key. Free-model request limits apply only to free variants.","https://openrouter.ai/docs/api/api-reference/api-keys/get-current-api-key"],["deepseek","DeepSeek",["account-balance"],"Provider-reported USD/CNY available, granted and topped-up balances.","https://api-docs.deepseek.com/api/get-user-balance"],["moonshotai","Moonshot / Kimi API",["account-balance"],"International USD balances; coding subscriptions are a different product.","https://platform.moonshot.ai/docs/api/balance"],["moonshotai-cn","Moonshot / Kimi API China",["account-balance"],"China CNY balances; never reuse an international key against the China endpoint.","https://platform.moonshot.cn/docs/api/balance"],["minimax","MiniMax",["subscription","account-balance"],"Token Plan model rows/explicit percentages; official SDK balance response for pay-as-you-go keys.","https://platform.minimax.io/docs/token-plan/faq"],["minimax-cn","MiniMax China",["subscription","account-balance"],"Region-specific native Token Plan and SDK balance endpoints.","https://github.com/MiniMax-AI/cli/tree/main/src/sdk/quota"],["github-copilot","GitHub Copilot",["subscription"],"Official SDK token-scoped quota/model RPC; no direct copilot_internal calls or ambient CLI login.","https://github.com/github/copilot-sdk/blob/main/docs/features/usage-and-billing.md"],["groq","Groq",["api-rate-limits"],"Native model response headers: requests per day and tokens per minute.","https://console.groq.com/docs/rate-limits"],["fireworks-ai","Fireworks",["configured-limits","api-rate-limits"],"Native model token/second capacities and account monthly spend quota; GPU quotas are excluded.","https://docs.fireworks.ai/serverless/rate-limits"],["siliconflow","SiliconFlow",["account-balance"],"Native current-user balances; retain unknown currency when the API does not report it.","https://docs.siliconflow.com/en/api-reference/userinfo/get-user-info"],["siliconflow-cn","SiliconFlow China",["account-balance"],"Region-specific current-user balances; currency is unknown when the API omits it.","https://docs.siliconflow.cn/"],["novita-ai","Novita",["account-balance"],"Native current-user balances in 1/10000 USD.","https://novita.ai/docs/api-reference/basic-get-user-balance"],["poe","Poe",["account-balance"],"API account point balance; includes plan and add-on points, not session token usage.","https://creator.poe.com/docs/resources/usage-api"],["nano-gpt","NanoGPT",["account-balance","subscription"],"Native USD/Nano balance and documented subscription token windows; null/degraded counters remain unknown.","https://docs.nano-gpt.com/api-reference/endpoint/subscription-usage"],["aihubmix","AIHubMix",["account-balance"],"Current-account balance API needs a Manage Key; inference keys do not grant management access.","https://docs.aihubmix.com/en/api/CliEndpoints/get-self"],["azure","Azure OpenAI",["api-rate-limits"],"Remaining request/token headers for the actual deployment; no ChatGPT subscription or inferred cloud balance.","https://learn.microsoft.com/en-us/azure/ai-foundry/openai/quotas-limits"],["cerebras","Cerebras",["api-rate-limits"],"Only self-describing native counters actually returned for the selected model; console tier examples are not live quota.","https://inference-docs.cerebras.ai/support/rate-limits"],["mistral","Mistral",[],"Documented remaining header lacks a verified unit/window association; no inferred subscription balance.","https://docs.mistral.ai/resources/known-limitations"],["togetherai","Together AI",[],"Dynamic model limits expose retry intervals, not remaining quota; billing UI does not establish a remaining-credit API.","https://docs.together.ai/docs/rate-limits"],["xai","xAI / Grok",[],"Management billing needs separate team credentials; no verified portable remaining API for this inference connection.","https://docs.x.ai/"],["perplexity","Perplexity",[],"No verified remaining-credit API for an inference key. API credits, consumer subscriptions and Computer credits are distinct.","https://www.perplexity.ai/help-center/en/articles/10354847-api-payment-and-billing"],["google","Google Gemini",["configured-limits"],"Native model-matched QuotaFailure responses when provided; cloud quota permissions differ from an inference key.","https://ai.google.dev/gemini-api/docs/rate-limits"],["google-vertex","Google Vertex AI",["configured-limits"],"Native model-matched quota error details; cloud project/region management and dynamic shared quotas are separate.","https://cloud.google.com/vertex-ai/generative-ai/docs/quotas"],["amazon-bedrock","Amazon Bedrock",[],"Service Quotas/CloudWatch require cloud IAM/region/model mapping not exposed by a portable inference connection.","https://docs.aws.amazon.com/bedrock/latest/userguide/quotas.html"],["cloudflare-workers-ai","Cloudflare Workers AI",[],"Account analytics do not prove remaining free allowance; separate account management capability is required.","https://developers.cloudflare.com/workers-ai/platform/limits/"],["huggingface","Hugging Face Inference Providers",[],"Hub request quota is not an inference-model quota or inference-credit balance.","https://huggingface.co/docs/inference-providers/pricing"],["zai","Z.ai / GLM Coding Plan",[],"No verified external quota contract for monitor/dashboard APIs; private endpoints are excluded.","https://docs.z.ai/devpack/overview"],["kimi-for-coding","Kimi Code subscription",[],"Keep separate from Moonshot API balance; an external subscription usage contract/model mapping must be verified.","https://www.kimi.com/code/docs/en/"],["alibaba","Alibaba Cloud / Qwen / DashScope",[],"Cloud account/project billing permissions and model mapping are required; browser OAuth state is not a quota source.","https://www.alibabacloud.com/help/en/model-studio/"],["opencode","OpenCode Zen / Go",[],"Session token/cost statistics are not provider quota; no undocumented billing endpoints.","https://opencode.ai/docs/zen/"],["cursor","Cursor",[],"Consumer usage needs a supported external API; no cookie or credential-file integrations.","https://docs.cursor.com/"],["windsurf","Windsurf / Codeium",[],"Consumer plan windows need a supported external API; no private account endpoints.","https://docs.windsurf.com/"],["amp","Amp",[],"Product credits need a supported external account API; no cookie or local credential extraction.","https://ampcode.com/manual"],["ollama","Ollama",[],"Local inference has no provider subscription window; cloud products require their own account API.","https://docs.ollama.com/api"],["lmstudio","LM Studio",[],"Local inference has no provider subscription quota to read.","https://lmstudio.ai/docs/developer"],["nvidia","NVIDIA NIM / NGC",[],"Inference access does not identify cloud/trial NGC credit balance or self-hosted resource quota.","https://docs.nvidia.com/nim/"],["cohere","Cohere",[],"No verified native remaining-counter contract for this integration; static organization tier examples are not live quotas.","https://docs.cohere.com/docs/rate-limits"],["ai21","AI21",[],"No verified native remaining-counter contract or subscription balance endpoint for this integration.","https://docs.ai21.com/"],["replicate","Replicate",[],"Prediction cost is not remaining account credit; no inferred balance from execution cost.","https://replicate.com/docs/topics/billing"],["chutes","Chutes",[],"Current-user quota APIs exist, but their public schemas do not establish native units/model allowance semantics yet.","https://chutes.ai/docs/api-reference/users"],["requesty","Requesty",[],"Enterprise management key and key ID are required; dated usage reports alone are not remaining budget.","https://docs.requesty.ai/features/key-management-api"],["baseten","Baseten",[],"No independently verified portable remaining quota API for the configured inference connection.","https://docs.baseten.co/"],["modelscope","ModelScope",[],"No independently verified portable remaining quota API/model mapping for the selected connection.","https://opencode.ai/docs/providers/"],["nebius","Nebius",[],"Cloud billing/management access is separate from a plain inference credential.","https://docs.nebius.com/"],["vultr","Vultr",[],"Cloud management quota/billing permissions are separate from inference access.","https://docs.vultr.com/"],["v0","Vercel v0",[],"Consumer/product credits need their own documented external account API.","https://v0.dev/docs"]]
|
|
583
|
+
var PROVIDER_QUOTA_CAPABILITIES= rows.map(([id,name,sources,reason,url])=>({id,name,sources,reason,documentation:[url]}))
|
|
584
|
+
var aliases={fireworks:"fireworks-ai",novita:"novita-ai",moonshot:"moonshotai","minimax-coding-plan":"minimax","minimax-coding-plan-cn":"minimax-cn",together:"togetherai","silicon-flow":"siliconflow","github-copilot-enterprise":"github-copilot","google-vertex-anthropic":"google-vertex","z-ai":"zai",zhipuai:"zai",dashscope:"alibaba","alibaba-cn":"alibaba",qwen:"alibaba","opencode-go":"opencode","opencode-zen":"opencode",codeium:"windsurf","azure-cognitive-services":"azure"
|
|
585
|
+
}
|
|
586
|
+
function providerQuotaCapability(id,canonical){const key=aliases[canonical??id]??canonical??id
|
|
587
|
+
const found=PROVIDER_QUOTA_CAPABILITIES.find((entry)=>entry.id===key)
|
|
588
|
+
return found??{id,name:id,sources:[],reason:"No independent quota/balance API or native counter semantics are verified for this provider.",documentation:["https://opencode.ai/docs/providers/"]
|
|
589
|
+
}}
|
|
590
|
+
import {insert as _$insert8} from "@opentui/solid"
|
|
605
591
|
import {mergeProps as _$mergeProps} from "@opentui/solid"
|
|
606
|
-
import {
|
|
607
|
-
import {
|
|
608
|
-
import {effect as _$effect8} from "@opentui/solid"
|
|
592
|
+
import {setProp as _$setProp9} from "@opentui/solid"
|
|
593
|
+
import {effect as _$effect9} from "@opentui/solid"
|
|
609
594
|
import {createTextNode as _$createTextNode4} from "@opentui/solid"
|
|
610
|
-
import {insertNode as _$
|
|
611
|
-
import {createElement as _$
|
|
612
|
-
import {memo as _$
|
|
613
|
-
import {createComponent as _$
|
|
614
|
-
import {Show as
|
|
615
|
-
import {useDialogs as
|
|
616
|
-
import {setProp as _$setProp5} from "@opentui/solid"
|
|
617
|
-
import {effect as _$effect5} from "@opentui/solid"
|
|
618
|
-
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
619
|
-
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
620
|
-
import {createElement as _$createElement5} from "@opentui/solid"
|
|
621
|
-
import {memo as _$memo4} from "@opentui/solid"
|
|
622
|
-
import {createComponent as _$createComponent7} from "@opentui/solid"
|
|
623
|
-
import {Show} from "solid-js"
|
|
624
|
-
import {useDialogs as useDialogs3,useIcons} from "./tui.js"
|
|
625
|
-
import {createComponent as _$createComponent6} from "@opentui/solid"
|
|
626
|
-
import {effect as _$effect4} from "@opentui/solid"
|
|
627
|
-
import {insert as _$insert4} from "@opentui/solid"
|
|
595
|
+
import {insertNode as _$insertNode6} from "@opentui/solid"
|
|
596
|
+
import {createElement as _$createElement9} from "@opentui/solid"
|
|
597
|
+
import {memo as _$memo7} from "@opentui/solid"
|
|
598
|
+
import {createComponent as _$createComponent12} from "@opentui/solid"
|
|
599
|
+
import {Show as Show6} from "solid-js"
|
|
600
|
+
import {useDialogs as useDialogs3} from "./tui.js"
|
|
628
601
|
import {setProp as _$setProp4} from "@opentui/solid"
|
|
602
|
+
import {effect as _$effect4} from "@opentui/solid"
|
|
603
|
+
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
604
|
+
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
629
605
|
import {createElement as _$createElement4} from "@opentui/solid"
|
|
606
|
+
import {memo as _$memo2} from "@opentui/solid"
|
|
607
|
+
import {createComponent as _$createComponent6} from "@opentui/solid"
|
|
608
|
+
import {Show} from "solid-js"
|
|
609
|
+
import {useDialogs as useDialogs2,useIcons as useIcons2} from "./tui.js"
|
|
610
|
+
import {createComponent as _$createComponent5} from "@opentui/solid"
|
|
611
|
+
import {effect as _$effect3} from "@opentui/solid"
|
|
612
|
+
import {insert as _$insert3} from "@opentui/solid"
|
|
613
|
+
import {setProp as _$setProp3} from "@opentui/solid"
|
|
614
|
+
import {createElement as _$createElement3} from "@opentui/solid"
|
|
630
615
|
import {SelectionBox} from "./tui.js"
|
|
631
|
-
import {createSignal as
|
|
616
|
+
import {createSignal as createSignal4,onCleanup} from "solid-js"
|
|
632
617
|
function sidebarInteractiveColors(theme,state,normalColor=theme.text,mode="row"){const highlighted=!state.disabled&&(state.focused||mode==="control"&&state.hovered)
|
|
633
618
|
let backgroundColor=theme.backgroundPanel
|
|
634
619
|
let foregroundColor=normalColor
|
|
@@ -644,7 +629,7 @@ else if(highlighted)
|
|
|
644
629
|
foregroundColor=theme.selectedListItemText
|
|
645
630
|
return{backgroundColor,foregroundColor}}
|
|
646
631
|
function useSidebarItem(api,interaction,descriptor,normalColor=()=>api.theme.current.text,mode="row"){let unregister
|
|
647
|
-
const [hovered,setHovered]=
|
|
632
|
+
const [hovered,setHovered]=createSignal4(false)
|
|
648
633
|
const disabled=()=>descriptor.disabled?.()===true
|
|
649
634
|
const focused=()=>Boolean(interaction?.ownsFocus()&&interaction.isSelected(descriptor.id))
|
|
650
635
|
const colors=()=>sidebarInteractiveColors(api.theme.current,{focused:focused(),hovered:hovered(),disabled:disabled()},normalColor(),mode)
|
|
@@ -661,63 +646,170 @@ descriptor.activate()
|
|
|
661
646
|
return true
|
|
662
647
|
}}}
|
|
663
648
|
function LimitsAction(props){const item=useSidebarItem(props.api,props.interaction,{id:props.id,position:()=>props.position,disabled:()=>props.disabled===true,activate:props.onActivate
|
|
664
|
-
})
|
|
665
|
-
return _$
|
|
666
|
-
},height:1,get
|
|
649
|
+
},()=>props.api.theme.current.text,props.inline?"control":"row")
|
|
650
|
+
return _$createComponent5(SelectionBox,{ref:(node)=>item.ref(node),get id(){return props.id
|
|
651
|
+
},height:1,get flexGrow(){return props.flexGrow
|
|
652
|
+
},get maxWidth(){return props.maxWidth
|
|
653
|
+
},flexShrink:1,minWidth:3,get backgroundColor(){return item.backgroundColor()
|
|
667
654
|
},get onMouseOver(){return item.onMouseOver
|
|
668
655
|
},get onMouseOut(){return item.onMouseOut
|
|
669
656
|
},onMouseUp:(event)=>{event.stopPropagation()
|
|
670
657
|
item.activate(event)
|
|
671
|
-
},get children(){var _el$=_$
|
|
672
|
-
_$
|
|
673
|
-
_$
|
|
674
|
-
_$
|
|
675
|
-
_$
|
|
658
|
+
},get children(){var _el$=_$createElement3("text")
|
|
659
|
+
_$setProp3(_el$,"wrapMode","none")
|
|
660
|
+
_$setProp3(_el$,"truncate",true)
|
|
661
|
+
_$insert3(_el$,()=>props.label)
|
|
662
|
+
_$effect3((_$p)=>_$setProp3(_el$,"fg",item.foregroundColor(),_$p))
|
|
676
663
|
return _el$
|
|
677
664
|
}})
|
|
678
665
|
}
|
|
679
|
-
function CodexAccountControls(props){const icons=
|
|
666
|
+
function CodexAccountControls(props){const icons=useIcons2()
|
|
680
667
|
const model=()=>props.controller.current().model
|
|
681
|
-
const accountLink=createCodexAccountLink({api:props.api,preferences:props.preferences,adapter:props.codex,model,dialogs:
|
|
668
|
+
const accountLink=createCodexAccountLink({api:props.api,preferences:props.preferences,adapter:props.codex,model,dialogs:useDialogs2(props.api)
|
|
682
669
|
})
|
|
683
670
|
const eligible=()=>(props.model.providerID==="openai"||props.model.hostConnection?.providerID==="openai")&&props.model.hostConnection?.method!=="api"
|
|
684
|
-
const action=(id,row,label,onActivate)=>_$
|
|
671
|
+
const action=(id,row,label,onActivate)=>_$createComponent6(LimitsAction,{get api(){return props.api
|
|
685
672
|
},get interaction(){return props.interaction
|
|
686
673
|
},id:`${PLUGIN_ID}.limits.${id}`,get position(){return{section:props.navigationSection,row,column:0
|
|
687
674
|
}},label,onActivate,get disabled(){return accountLink.busy()
|
|
688
675
|
}})
|
|
689
|
-
return _$
|
|
690
|
-
},get children(){return [_$
|
|
691
|
-
},get children(){return [(()=>{var _el$=_$
|
|
692
|
-
_$insertNode3(_el$,_$
|
|
693
|
-
_$
|
|
676
|
+
return _$createComponent6(Show,{get when(){return eligible()
|
|
677
|
+
},get children(){return [_$createComponent6(Show,{get when(){return _$memo2(()=>!!!props.model.accountID)()&&(!props.model.hostConnection||props.model.hostConnection.status==="ready")
|
|
678
|
+
},get children(){return [(()=>{var _el$=_$createElement4("text")
|
|
679
|
+
_$insertNode3(_el$,_$createTextNode(`Link the matching Codex account once for this connection`))
|
|
680
|
+
_$effect4((_$p)=>_$setProp4(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
694
681
|
return _el$
|
|
695
|
-
})(),_$
|
|
696
|
-
}}),_$
|
|
697
|
-
},get children(){return [_$
|
|
682
|
+
})(),_$memo2(()=>action("link",2,`${icons.icon("scope")} Link Codex CLI account`,()=>void accountLink.link()))]
|
|
683
|
+
}}),_$createComponent6(Show,{get when(){return _$memo2(()=>!!(props.model.accountID&&props.model.accountSource!=="host"))()&&props.controller.snapshot()?.availability==="unauthenticated"
|
|
684
|
+
},get children(){return [_$memo2(()=>action("unlink",4,`${icons.icon("close")} Unlink Codex account`,()=>props.preferences.setCodexConnectionBinding(props.model.providerID,props.model.hostConnection?.id))),_$createComponent6(Show,{get when(){return props.controller.snapshot()?.availability==="unauthenticated"
|
|
698
685
|
},get children(){return action("relink",5,`${icons.icon("scope")} Relink Codex account`,()=>void accountLink.link())
|
|
699
686
|
}})]
|
|
700
687
|
}})]
|
|
701
688
|
}})
|
|
702
689
|
}
|
|
703
690
|
import {createComponent as _$createComponent8} from "@opentui/solid"
|
|
704
|
-
import {
|
|
691
|
+
import {Show as Show2} from "solid-js"
|
|
692
|
+
import {useIcons as useIcons3} from "./tui.js"
|
|
693
|
+
import {createComponent as _$createComponent7} from "@opentui/solid"
|
|
694
|
+
import {effect as _$effect5} from "@opentui/solid"
|
|
695
|
+
import {insert as _$insert4} from "@opentui/solid"
|
|
696
|
+
import {setProp as _$setProp5} from "@opentui/solid"
|
|
697
|
+
import {createElement as _$createElement5} from "@opentui/solid"
|
|
698
|
+
import {memo as _$memo3} from "@opentui/solid"
|
|
699
|
+
import {createEffect as createEffect2,createSignal as createSignal5,on} from "solid-js"
|
|
700
|
+
import {SelectionBox as SelectionBox2} from "./tui.js"
|
|
701
|
+
var graphemes=new Intl.Segmenter(undefined,{granularity:"grapheme"
|
|
702
|
+
})
|
|
703
|
+
function truncateEnd(value,width){if(Bun.stringWidth(value)<=width)
|
|
704
|
+
return value
|
|
705
|
+
if(width<=0)
|
|
706
|
+
return ""
|
|
707
|
+
const ellipsis=width>=3?"...":".".repeat(width)
|
|
708
|
+
let result=""
|
|
709
|
+
for(const{segment
|
|
710
|
+
} of graphemes.segment(value)){if(Bun.stringWidth(result + segment)>width-ellipsis.length)
|
|
711
|
+
break
|
|
712
|
+
result += segment
|
|
713
|
+
}
|
|
714
|
+
return result + ellipsis
|
|
715
|
+
}
|
|
716
|
+
function SectionHeaderControl(props){const [width,setWidth]=createSignal5()
|
|
717
|
+
const control=useSidebarItem(props.api,props.interaction,{id:props.action.id,position:()=>props.position,disabled:props.action.disabled,activate:props.action.onActivate
|
|
718
|
+
},()=>props.api.theme.current.accent,"control")
|
|
719
|
+
createEffect2(on(()=>[props.action.label(),props.resetWidth],()=>setWidth(undefined)))
|
|
720
|
+
const label=()=>width()===undefined||props.iconOnly?props.action.label():truncateEnd(props.action.label(),width()-2)
|
|
721
|
+
return _$createComponent7(SelectionBox2,{ref:(node)=>control.ref(node),get id(){return props.action.id
|
|
722
|
+
},get iconOnly(){return props.iconOnly
|
|
723
|
+
},get width(){return props.iconOnly?3:undefined
|
|
724
|
+
},get flexShrink(){return props.iconOnly?0:1
|
|
725
|
+
},minWidth:3,overflow:"hidden",get alignItems(){return props.iconOnly?"center":undefined
|
|
726
|
+
},get backgroundColor(){return control.backgroundColor()
|
|
727
|
+
},onSizeChange:function(){setWidth(this.width)
|
|
728
|
+
},get onMouseOver(){return control.onMouseOver
|
|
729
|
+
},get onMouseOut(){return control.onMouseOut
|
|
730
|
+
},onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
731
|
+
control.activate(event)
|
|
732
|
+
},get children(){var _el$=_$createElement5("text")
|
|
733
|
+
_$setProp5(_el$,"wrapMode","none")
|
|
734
|
+
_$setProp5(_el$,"height",1)
|
|
735
|
+
_$insert4(_el$,label)
|
|
736
|
+
_$effect5((_$p)=>_$setProp5(_el$,"fg",control.foregroundColor(),_$p))
|
|
737
|
+
return _el$
|
|
738
|
+
}})
|
|
739
|
+
}
|
|
740
|
+
function LimitsHeaderControls(props){const icons=useIcons3()
|
|
741
|
+
return [_$createComponent8(Show2,{get when(){return props.credits
|
|
742
|
+
},get children(){return _$createComponent8(SectionHeaderControl,{get api(){return props.api
|
|
743
|
+
},get interaction(){return props.interaction
|
|
744
|
+
},get position(){return{section:props.navigationSection,row:0,column:1
|
|
745
|
+
}},get action(){return{id:`${PLUGIN_ID}.limits.credits`,label:()=>"Banked Resets",disabled:()=>false,onActivate:props.onCredits
|
|
746
|
+
}}})
|
|
747
|
+
}}),_$createComponent8(SectionHeaderControl,{get api(){return props.api
|
|
748
|
+
},get interaction(){return props.interaction
|
|
749
|
+
},iconOnly:true,get position(){return{section:props.navigationSection,row:0,column:2
|
|
750
|
+
}},get action(){return{id:`${PLUGIN_ID}.limits.refresh`,label:()=>icons.icon(props.refreshing?"pending":"retry"),disabled:()=>props.refreshing||!props.canRefresh,onActivate:props.onRefresh
|
|
751
|
+
}}})]
|
|
752
|
+
}
|
|
705
753
|
import {insert as _$insert5} from "@opentui/solid"
|
|
754
|
+
import {effect as _$effect6} from "@opentui/solid"
|
|
755
|
+
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
756
|
+
import {insertNode as _$insertNode4} from "@opentui/solid"
|
|
757
|
+
import {memo as _$memo4} from "@opentui/solid"
|
|
758
|
+
import {createComponent as _$createComponent9} from "@opentui/solid"
|
|
706
759
|
import {setProp as _$setProp6} from "@opentui/solid"
|
|
707
760
|
import {createElement as _$createElement6} from "@opentui/solid"
|
|
708
|
-
import {Show as
|
|
761
|
+
import {Show as Show3} from "solid-js"
|
|
762
|
+
function LimitsModelRow(props){const names=()=>props.selection?.names(props.model)??{provider:props.model.providerID,model:props.model.modelID
|
|
763
|
+
}
|
|
764
|
+
return(()=>{var _el$=_$createElement6("box")
|
|
765
|
+
_$setProp6(_el$,"flexDirection","row")
|
|
766
|
+
_$setProp6(_el$,"minWidth",0)
|
|
767
|
+
_$insert5(_el$,_$createComponent9(LimitsAction,{get api(){return props.api
|
|
768
|
+
},get interaction(){return props.interaction
|
|
769
|
+
},inline:true,flexGrow:1,get maxWidth(){return Bun.stringWidth(`[${names().provider}] ${names().model}`) + 2
|
|
770
|
+
},id:`${PLUGIN_ID}.limits.model`,get position(){return{section:props.navigationSection,row:1,column:0
|
|
771
|
+
}},get label(){return `[${names().provider}] ${names().model}`
|
|
772
|
+
},get disabled(){return !props.selection?.canOpen("model",props.model)
|
|
773
|
+
},onActivate:()=>props.selection?.open("model",props.model)
|
|
774
|
+
}),null)
|
|
775
|
+
_$insert5(_el$,_$createComponent9(Show3,{get when(){return props.model.variant||props.selection?.variants(props.model).length
|
|
776
|
+
},get children(){return [(()=>{var _el$2=_$createElement6("text"),_el$3=_$createTextNode2(` \xB7 `)
|
|
777
|
+
_$insertNode4(_el$2,_el$3)
|
|
778
|
+
_$setProp6(_el$2,"flexShrink",0)
|
|
779
|
+
_$effect6((_$p)=>_$setProp6(_el$2,"fg",props.api.theme.current.textMuted,_$p))
|
|
780
|
+
return _el$2
|
|
781
|
+
})(),_$createComponent9(LimitsAction,{get api(){return props.api
|
|
782
|
+
},get interaction(){return props.interaction
|
|
783
|
+
},inline:true,id:`${PLUGIN_ID}.limits.variant`,get position(){return{section:props.navigationSection,row:1,column:1
|
|
784
|
+
}},get label(){return props.model.variant??"Default"
|
|
785
|
+
},get disabled(){return !props.selection?.canOpen("variant",props.model)
|
|
786
|
+
},onActivate:()=>props.selection?.open("variant",props.model)
|
|
787
|
+
})]
|
|
788
|
+
}}),null)
|
|
789
|
+
return _el$
|
|
790
|
+
})()
|
|
791
|
+
}
|
|
792
|
+
import {effect as _$effect7} from "@opentui/solid"
|
|
793
|
+
import {insert as _$insert6} from "@opentui/solid"
|
|
794
|
+
import {setProp as _$setProp7} from "@opentui/solid"
|
|
795
|
+
import {createElement as _$createElement7} from "@opentui/solid"
|
|
796
|
+
import {createComponent as _$createComponent10} from "@opentui/solid"
|
|
797
|
+
import {memo as _$memo5} from "@opentui/solid"
|
|
798
|
+
import {Show as Show4} from "solid-js"
|
|
709
799
|
function LimitsStatus(props){const message=()=>{const model=props.controller.current().model
|
|
710
800
|
const connection=model?.hostConnection
|
|
711
801
|
const snapshot=props.controller.snapshot()
|
|
712
802
|
const state=props.controller.state()
|
|
713
803
|
if(state.status==="error")
|
|
714
|
-
return snapshot?"Stale \xB7 refresh failed
|
|
804
|
+
return snapshot?"Stale \xB7 refresh failed":"Quota read failed \xB7 refresh to retry"
|
|
805
|
+
if(snapshot?.availability==="ready"&&(snapshot.windows.length>0||snapshot.balances?.length))
|
|
806
|
+
return
|
|
715
807
|
if(snapshot?.message)
|
|
716
808
|
return snapshot.availability==="stale"?`Stale \xB7 ${snapshot.message}`:snapshot.availability==="ready"?`Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()} \xB7 ${snapshot.message}`:snapshot.message
|
|
717
809
|
if(connection?.status==="loading")
|
|
718
810
|
return "Checking the OpenCode account\u2026"
|
|
719
811
|
if(connection?.status==="unavailable")
|
|
720
|
-
return "
|
|
812
|
+
return "Account metadata unavailable \xB7 refresh to retry"
|
|
721
813
|
if(connection?.status==="unsupported")
|
|
722
814
|
return "Codex quotas require an active ChatGPT OAuth connection"
|
|
723
815
|
if(!snapshot)
|
|
@@ -730,194 +822,146 @@ return "No documented quota bucket for this model"
|
|
|
730
822
|
if(availability==="rate_limited")
|
|
731
823
|
return "Provider rate-limited this read \xB7 try again later"
|
|
732
824
|
if(availability==="stale")
|
|
733
|
-
return "Stale provider data \xB7 refresh
|
|
825
|
+
return "Stale provider data \xB7 refresh to update"
|
|
734
826
|
return `Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()}`
|
|
735
827
|
}
|
|
736
|
-
return _$
|
|
737
|
-
},
|
|
738
|
-
_$
|
|
739
|
-
_$
|
|
740
|
-
_$
|
|
828
|
+
return _$createComponent10(Show4,{get when(){return _$memo5(()=>!!props.controller.current().model)()&&message()
|
|
829
|
+
},children:(value)=>(()=>{var _el$=_$createElement7("text")
|
|
830
|
+
_$setProp7(_el$,"wrapMode","word")
|
|
831
|
+
_$insert6(_el$,value)
|
|
832
|
+
_$effect7((_$p)=>_$setProp7(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
741
833
|
return _el$
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
import {createComponent as _$createComponent9} from "@opentui/solid"
|
|
745
|
-
import {effect as _$effect7} from "@opentui/solid"
|
|
746
|
-
import {createTextNode as _$createTextNode3} from "@opentui/solid"
|
|
747
|
-
import {insertNode as _$insertNode4} from "@opentui/solid"
|
|
748
|
-
import {memo as _$memo5} from "@opentui/solid"
|
|
749
|
-
import {insert as _$insert6} from "@opentui/solid"
|
|
750
|
-
import {setProp as _$setProp7} from "@opentui/solid"
|
|
751
|
-
import {createElement as _$createElement7} from "@opentui/solid"
|
|
752
|
-
import {Show as Show3,createEffect as createEffect2,createSignal as createSignal6} from "solid-js"
|
|
753
|
-
import {SelectionBox as SelectionBox2,useIcons as useIcons2} from "./tui.js"
|
|
754
|
-
var graphemes=new Intl.Segmenter(undefined,{granularity:"grapheme"
|
|
834
|
+
})()
|
|
755
835
|
})
|
|
756
|
-
function truncateEnd(value,maxWidth){if(Bun.stringWidth(value)<=maxWidth)
|
|
757
|
-
return value
|
|
758
|
-
if(maxWidth<=0)
|
|
759
|
-
return ""
|
|
760
|
-
const ellipsis=maxWidth>=3?"...":".".repeat(maxWidth)
|
|
761
|
-
const contentWidth=maxWidth-Bun.stringWidth(ellipsis)
|
|
762
|
-
let result=""
|
|
763
|
-
for(const{segment
|
|
764
|
-
} of graphemes.segment(value)){if(Bun.stringWidth(result + segment)>contentWidth)
|
|
765
|
-
break
|
|
766
|
-
result += segment
|
|
767
|
-
}
|
|
768
|
-
return result + ellipsis
|
|
769
836
|
}
|
|
770
|
-
|
|
771
|
-
|
|
837
|
+
import {createComponent as _$createComponent11} from "@opentui/solid"
|
|
838
|
+
import {effect as _$effect8} from "@opentui/solid"
|
|
839
|
+
import {createTextNode as _$createTextNode3} from "@opentui/solid"
|
|
840
|
+
import {insertNode as _$insertNode5} from "@opentui/solid"
|
|
841
|
+
import {memo as _$memo6} from "@opentui/solid"
|
|
842
|
+
import {insert as _$insert7} from "@opentui/solid"
|
|
843
|
+
import {setProp as _$setProp8} from "@opentui/solid"
|
|
844
|
+
import {createElement as _$createElement8} from "@opentui/solid"
|
|
845
|
+
import {Show as Show5,createSignal as createSignal6} from "solid-js"
|
|
846
|
+
import {SelectionBox as SelectionBox3,useIcons as useIcons4} from "./tui.js"
|
|
847
|
+
function Section(props){const icons=useIcons4()
|
|
848
|
+
const [headerWidth,setHeaderWidth]=createSignal6(0)
|
|
772
849
|
const icon=()=>props.section?icons.section(props.section):props.icon
|
|
773
850
|
const theme=()=>props.api.theme.current
|
|
774
851
|
const item=useSidebarItem(props.api,props.interaction,{id:props.sectionId??`section.${props.title}`,position:()=>({section:props.navigationSection??0,row:0,column:0
|
|
775
852
|
}),activate:props.onToggle
|
|
776
853
|
})
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
createEffect2(()=>{props.headerAction?.label()
|
|
781
|
-
setActionWidth(undefined)
|
|
782
|
-
})
|
|
783
|
-
const actionLabel=()=>{const label=props.headerAction?.label()??""
|
|
784
|
-
const width=actionWidth()
|
|
785
|
-
return width===undefined?label:truncateEnd(label,width-2)
|
|
786
|
-
}
|
|
787
|
-
return(()=>{var _el$=_$createElement7("box")
|
|
788
|
-
_$setProp7(_el$,"gap",1)
|
|
789
|
-
_$insert6(_el$,_$createComponent9(SelectionBox2,{ref:(node)=>item.ref(node),get id(){return props.sectionId
|
|
854
|
+
return(()=>{var _el$=_$createElement8("box")
|
|
855
|
+
_$setProp8(_el$,"gap",1)
|
|
856
|
+
_$insert7(_el$,_$createComponent11(SelectionBox3,{ref:(node)=>item.ref(node),get id(){return props.sectionId
|
|
790
857
|
},flexDirection:"row",height:1,justifyContent:"space-between",gap:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
|
|
791
858
|
},get onMouseOver(){return item.onMouseOver
|
|
792
859
|
},get onMouseOut(){return item.onMouseOut
|
|
793
|
-
},onMouseDown:(event)=>item.activate(event),onSizeChange:()
|
|
794
|
-
|
|
795
|
-
_$
|
|
796
|
-
_$
|
|
797
|
-
_$
|
|
798
|
-
_$
|
|
799
|
-
_$
|
|
800
|
-
_$
|
|
801
|
-
_$
|
|
860
|
+
},onMouseDown:(event)=>item.activate(event),onSizeChange:function(){setHeaderWidth(this.width)
|
|
861
|
+
},get children(){return [(()=>{var _el$2=_$createElement8("text"),_el$3=_$createElement8("span"),_el$4=_$createTextNode3(` `),_el$5=_$createElement8("span"),_el$6=_$createElement8("b")
|
|
862
|
+
_$insertNode5(_el$2,_el$3)
|
|
863
|
+
_$insertNode5(_el$2,_el$4)
|
|
864
|
+
_$insertNode5(_el$2,_el$5)
|
|
865
|
+
_$insertNode5(_el$2,_el$6)
|
|
866
|
+
_$setProp8(_el$2,"flexShrink",0)
|
|
867
|
+
_$setProp8(_el$2,"wrapMode","none")
|
|
868
|
+
_$insert7(_el$3,()=>icons.icon(props.open?"expanded":"collapsed"))
|
|
869
|
+
_$insert7(_el$5,(()=>{var _c$=_$memo6(()=>!!icon())
|
|
802
870
|
return()=>_c$()?`${icon()} `:""
|
|
803
871
|
})())
|
|
804
|
-
_$
|
|
805
|
-
_$
|
|
872
|
+
_$insert7(_el$6,()=>props.title)
|
|
873
|
+
_$effect8((_p$)=>{var _v$=item.foregroundColor(),_v$2={fg:item.focused()?item.foregroundColor():theme().accent
|
|
806
874
|
},_v$3={fg:item.focused()?item.foregroundColor():theme().accent
|
|
807
875
|
}
|
|
808
|
-
_v$!==_p$.e&&(_p$.e=_$
|
|
809
|
-
_v$2!==_p$.t&&(_p$.t=_$
|
|
810
|
-
_v$3!==_p$.a&&(_p$.a=_$
|
|
876
|
+
_v$!==_p$.e&&(_p$.e=_$setProp8(_el$2,"fg",_v$,_p$.e))
|
|
877
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp8(_el$3,"style",_v$2,_p$.t))
|
|
878
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp8(_el$5,"style",_v$3,_p$.a))
|
|
811
879
|
return _p$
|
|
812
880
|
},{e:undefined,t:undefined,a:undefined
|
|
813
881
|
})
|
|
814
882
|
return _el$2
|
|
815
|
-
})(),(()=>{var _el$7=_$
|
|
816
|
-
_$
|
|
817
|
-
_$
|
|
818
|
-
_$
|
|
819
|
-
_$
|
|
820
|
-
_$
|
|
821
|
-
_$
|
|
822
|
-
_$
|
|
823
|
-
},
|
|
824
|
-
},
|
|
825
|
-
},get
|
|
826
|
-
},get
|
|
827
|
-
},
|
|
828
|
-
|
|
829
|
-
},
|
|
830
|
-
_$
|
|
831
|
-
_$
|
|
832
|
-
_$
|
|
833
|
-
_$
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
_$
|
|
838
|
-
_$
|
|
839
|
-
_$setProp7(_el$8,"height",1)
|
|
840
|
-
_$insert6(_el$8,()=>props.summary)
|
|
841
|
-
_$effect7((_p$)=>{var _v$4=item.focused()?item.foregroundColor():theme().textMuted,_v$5=props.headerAction?0:1
|
|
842
|
-
_v$4!==_p$.e&&(_p$.e=_$setProp7(_el$8,"fg",_v$4,_p$.e))
|
|
843
|
-
_v$5!==_p$.t&&(_p$.t=_$setProp7(_el$8,"flexShrink",_v$5,_p$.t))
|
|
883
|
+
})(),(()=>{var _el$7=_$createElement8("box")
|
|
884
|
+
_$setProp8(_el$7,"flexDirection","row")
|
|
885
|
+
_$setProp8(_el$7,"gap",1)
|
|
886
|
+
_$setProp8(_el$7,"flexGrow",1)
|
|
887
|
+
_$setProp8(_el$7,"minWidth",0)
|
|
888
|
+
_$setProp8(_el$7,"justifyContent","flex-end")
|
|
889
|
+
_$insert7(_el$7,()=>props.headerControls,null)
|
|
890
|
+
_$insert7(_el$7,_$createComponent11(Show5,{get when(){return props.headerAction
|
|
891
|
+
},children:(action)=>_$createComponent11(SectionHeaderControl,{get api(){return props.api
|
|
892
|
+
},get interaction(){return props.interaction
|
|
893
|
+
},get action(){return action()
|
|
894
|
+
},get resetWidth(){return headerWidth()
|
|
895
|
+
},get position(){return{section:props.navigationSection??0,row:0,column:1
|
|
896
|
+
}}})
|
|
897
|
+
}),null)
|
|
898
|
+
_$insert7(_el$7,_$createComponent11(Show5,{get when(){return props.summary
|
|
899
|
+
},get children(){var _el$8=_$createElement8("text")
|
|
900
|
+
_$setProp8(_el$8,"wrapMode","none")
|
|
901
|
+
_$setProp8(_el$8,"truncate",true)
|
|
902
|
+
_$setProp8(_el$8,"height",1)
|
|
903
|
+
_$insert7(_el$8,()=>props.summary)
|
|
904
|
+
_$effect8((_p$)=>{var _v$4=item.focused()?item.foregroundColor():theme().textMuted,_v$5=props.headerAction?0:1
|
|
905
|
+
_v$4!==_p$.e&&(_p$.e=_$setProp8(_el$8,"fg",_v$4,_p$.e))
|
|
906
|
+
_v$5!==_p$.t&&(_p$.t=_$setProp8(_el$8,"flexShrink",_v$5,_p$.t))
|
|
844
907
|
return _p$
|
|
845
908
|
},{e:undefined,t:undefined
|
|
846
909
|
})
|
|
910
|
+
return _el$8
|
|
911
|
+
}}),null)
|
|
847
912
|
return _el$7
|
|
848
913
|
})()]
|
|
849
914
|
}}),null)
|
|
850
|
-
_$
|
|
915
|
+
_$insert7(_el$,_$createComponent11(Show5,{get when(){return props.open
|
|
851
916
|
},get children(){return props.children
|
|
852
917
|
}}),null)
|
|
853
918
|
return _el$
|
|
854
919
|
})()
|
|
855
920
|
}
|
|
856
|
-
function ProviderLimitsSection(props){const
|
|
857
|
-
const dialogs=useDialogs4(props.api)
|
|
921
|
+
function ProviderLimitsSection(props){const dialogs=useDialogs3(props.api)
|
|
858
922
|
const model=()=>props.controller.current().model
|
|
859
923
|
const snapshot=props.controller.snapshot
|
|
860
|
-
const count=()=>(snapshot()?.windows.length??0) + (snapshot()?.balances?.length??0)
|
|
861
|
-
const action=(id,row,label,onActivate,disabled=false)=>_$createComponent10(LimitsAction,{get api(){return props.api
|
|
862
|
-
},get interaction(){return props.interaction
|
|
863
|
-
},id:`${PLUGIN_ID}.limits.${id}`,get position(){return{section:props.navigationSection,row,column:0
|
|
864
|
-
}},label,onActivate,disabled
|
|
865
|
-
})
|
|
866
924
|
function openCredits(){const selected=model()
|
|
867
925
|
if(selected)
|
|
868
|
-
dialogs.open(()=>_$
|
|
926
|
+
dialogs.open(()=>_$createComponent12(ResetCreditDialog,{get api(){return props.api
|
|
869
927
|
},get preferences(){return props.preferences
|
|
870
928
|
},get controller(){return props.controller
|
|
871
929
|
},get adapter(){return props.codex
|
|
872
930
|
},model:selected
|
|
873
931
|
}))
|
|
874
932
|
}
|
|
875
|
-
return _$
|
|
933
|
+
return _$createComponent12(Section,{get api(){return props.api
|
|
876
934
|
},get interaction(){return props.interaction
|
|
877
935
|
},sectionId:`${PLUGIN_ID}.section.limits`,get navigationSection(){return props.navigationSection
|
|
878
|
-
},title:"LIMITS",section:"limits",get
|
|
936
|
+
},title:"LIMITS",section:"limits",summary:"",get headerControls(){return _$createComponent12(LimitsHeaderControls,{get api(){return props.api
|
|
937
|
+
},get interaction(){return props.interaction
|
|
938
|
+
},get navigationSection(){return props.navigationSection
|
|
939
|
+
},get credits(){return(snapshot()?.bankedResets?.availableCount??0)>0||Boolean(props.preferences.pendingResetAttempt())
|
|
940
|
+
},get refreshing(){return ["loading","refreshing"].includes(props.controller.state().status)
|
|
941
|
+
},get canRefresh(){return Boolean(model()&&(props.controller.current().adapter||model()?.hostConnection?.status==="unavailable"))
|
|
942
|
+
},onCredits:openCredits,onRefresh:()=>void props.controller.refresh(true)
|
|
943
|
+
})
|
|
879
944
|
},get open(){return props.preferences.expanded().limits
|
|
880
|
-
},onToggle:()=>props.preferences.toggleSectionExpanded("limits"),get children(){return _$
|
|
881
|
-
},get fallback(){return(()=>{var _el$=_$
|
|
882
|
-
_$
|
|
883
|
-
_$
|
|
945
|
+
},onToggle:()=>props.preferences.toggleSectionExpanded("limits"),get children(){return _$createComponent12(Show6,{get when(){return model()
|
|
946
|
+
},get fallback(){return(()=>{var _el$=_$createElement9("text")
|
|
947
|
+
_$insertNode6(_el$,_$createTextNode4(`Open a session to view model limits`))
|
|
948
|
+
_$effect9((_$p)=>_$setProp9(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
884
949
|
return _el$
|
|
885
950
|
})()
|
|
886
|
-
},children:(selected)=>(()=>{var _el$3=_$
|
|
887
|
-
_$
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
_$
|
|
891
|
-
_$setProp8(_el$4,"truncate",true)
|
|
892
|
-
_$insert7(_el$4,()=>selected().providerID,_el$5)
|
|
893
|
-
_$insert7(_el$4,()=>selected().modelID,null)
|
|
894
|
-
_$insert7(_el$3,_$createComponent10(CodexAccountControls,_$mergeProps(props,{get model(){return selected()
|
|
951
|
+
},children:(selected)=>(()=>{var _el$3=_$createElement9("box")
|
|
952
|
+
_$insert8(_el$3,_$createComponent12(LimitsModelRow,_$mergeProps(props,{get model(){return selected()
|
|
953
|
+
},get selection(){return props.modelSelection
|
|
954
|
+
}})),null)
|
|
955
|
+
_$insert8(_el$3,_$createComponent12(CodexAccountControls,_$mergeProps(props,{get model(){return selected()
|
|
895
956
|
}})),null)
|
|
896
|
-
_$
|
|
897
|
-
},children:(quota)=>_$
|
|
957
|
+
_$insert8(_el$3,_$createComponent12(Show6,{get when(){return _$memo7(()=>!!(snapshot()&&["ready","stale"].includes(snapshot().availability)))()?snapshot():undefined
|
|
958
|
+
},children:(quota)=>_$createComponent12(QuotaSnapshotRows,{get api(){return props.api
|
|
898
959
|
},get snapshot(){return quota()
|
|
899
960
|
}})
|
|
900
961
|
}),null)
|
|
901
|
-
_$
|
|
902
|
-
},children:(credits)=>[(()=>{var _el$6=_$createElement8("text"),_el$7=_$createTextNode4(`Banked resets: `)
|
|
903
|
-
_$insertNode5(_el$6,_el$7)
|
|
904
|
-
_$insert7(_el$6,()=>credits().availableCount,null)
|
|
905
|
-
_$effect8((_$p)=>_$setProp8(_el$6,"fg",props.api.theme.current.textMuted,_$p))
|
|
906
|
-
return _el$6
|
|
907
|
-
})(),_$createComponent10(Show4,{get when(){return credits().availableCount>0||props.preferences.pendingResetAttempt()
|
|
908
|
-
},get children(){return action("credits",2,`${icons.icon("info")} Review reset credits`,openCredits)
|
|
909
|
-
}})]
|
|
910
|
-
}),null)
|
|
911
|
-
_$insert7(_el$3,_$createComponent10(LimitsStatus,{get api(){return props.api
|
|
962
|
+
_$insert8(_el$3,_$createComponent12(LimitsStatus,{get api(){return props.api
|
|
912
963
|
},get controller(){return props.controller
|
|
913
964
|
}}),null)
|
|
914
|
-
_$insert7(_el$3,_$createComponent10(Show4,{get when(){return props.controller.current().adapter||selected().hostConnection?.status==="unavailable"
|
|
915
|
-
},get children(){return action("refresh",3,`${icons.icon("retry")} ${props.controller.state().status === "error" ? "Retry" : "Refresh"}`,()=>void props.controller.refresh(true),["loading","refreshing"].includes(props.controller.state().status))
|
|
916
|
-
}}),null)
|
|
917
|
-
_$insert7(_el$3,()=>action("sources",6,`${icons.icon("info")} Provider sources`,()=>dialogs.open(()=>_$createComponent10(ProviderSupportDialog,{get api(){return props.api
|
|
918
|
-
},get load(){return props.capabilities
|
|
919
|
-
}}))),null)
|
|
920
|
-
_$effect8((_$p)=>_$setProp8(_el$4,"fg",props.api.theme.current.textMuted,_$p))
|
|
921
965
|
return _el$3
|
|
922
966
|
})()
|
|
923
967
|
})
|
|
@@ -1016,6 +1060,26 @@ return{...model,accountID:undefined,accountSource:undefined}
|
|
|
1016
1060
|
const accountID=connection?.accountID??preferences.codexAccountForConnection(model.providerID,connection?.id,model.modelID)
|
|
1017
1061
|
const accountSource=connection?.accountID?"host":"binding"
|
|
1018
1062
|
return{...model,accountID,accountSource:accountID?accountSource:undefined}}
|
|
1063
|
+
var commandName=(kind)=>kind==="model"?"model.list":"variant.list"
|
|
1064
|
+
function createLimitsModelSelection(api,current,context){const sameTarget=(model)=>{const active=current()
|
|
1065
|
+
return active?.sessionID===model.sessionID&&active.providerID===model.providerID&&active.modelID===model.modelID
|
|
1066
|
+
}
|
|
1067
|
+
const legacy=(model)=>api.state.provider?.find((provider)=>provider.id===model.providerID)
|
|
1068
|
+
const variants=(model)=>context?context.ui.model.variant?.list?.()??[]:Object.keys(legacy(model)?.models[model.modelID]?.variants??{})
|
|
1069
|
+
const canOpen=(kind,model)=>{const command=api.keymap.getCommands().find((entry)=>entry.name===commandName(kind))
|
|
1070
|
+
const enabled=typeof command?.enabled==="function"?command.enabled():command?.enabled!==false
|
|
1071
|
+
return Boolean(command&&enabled&&sameTarget(model)&&(kind==="model"||variants(model).length>0))
|
|
1072
|
+
}
|
|
1073
|
+
return{names(model){if(context){const location=context.location??context.data.location.default()
|
|
1074
|
+
const provider=context.data.location.provider?.list?.(location)?.find((entry)=>entry.id===model.providerID)
|
|
1075
|
+
const item=context.data.location.model?.list?.(location)?.find((entry)=>entry.providerID===model.providerID&&entry.id===model.modelID)
|
|
1076
|
+
return{provider:provider?.name??model.providerID,model:item?.name??model.modelID}}
|
|
1077
|
+
const provider=legacy(model)
|
|
1078
|
+
return{provider:provider?.name??model.providerID,model:provider?.models[model.modelID]?.name??model.modelID
|
|
1079
|
+
}},variants,canOpen,open(kind,model){if(!canOpen(kind,model))
|
|
1080
|
+
return false
|
|
1081
|
+
return api.keymap.dispatchCommand(commandName(kind)).ok
|
|
1082
|
+
}}}
|
|
1019
1083
|
function selectedV2Model(context){const route=context.ui.router.current()
|
|
1020
1084
|
const model=context.ui.model.current()
|
|
1021
1085
|
if(route.type!=="session"||!model)
|
|
@@ -1035,7 +1099,7 @@ native?.onUpdated((providerID,modelID)=>{const selected=selectModel()
|
|
|
1035
1099
|
if(selected?.providerID===providerID&&selected.modelID===modelID)
|
|
1036
1100
|
controller.refresh()
|
|
1037
1101
|
})
|
|
1038
|
-
return{controller,codex,accountSource,selectModel,
|
|
1102
|
+
return{controller,codex,accountSource,selectModel,modelSelection:createLimitsModelSelection(api,selectModel,context)
|
|
1039
1103
|
}}
|
|
1040
1104
|
export{ProviderLimitsSection,bindCodexAccount,createCodexAppServerClient,createCodexQuotaAdapter,createOpenCodeV2AccountSource,createProviderLimitsController,createProviderQuotaIntegration,selectedV1Model
|
|
1041
1105
|
}
|