opencode-navigator 0.21.1 → 0.21.3
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 +10 -0
- package/PROVIDERS.md +1 -1
- package/README.md +21 -14
- package/dist/provider-limits.js +338 -267
- package/dist/tui.js +102 -80
- package/package.json +1 -1
package/dist/provider-limits.js
CHANGED
|
@@ -362,36 +362,66 @@ 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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return `${
|
|
367
|
+
import {createSignal as createSignal4} from "solid-js"
|
|
368
|
+
import {useIcons} from "./tui.js"
|
|
369
|
+
function measurement(window,remaining){if(remaining!==undefined)
|
|
370
|
+
return `${remaining}${window.unit === "%" ? "" : " "}${window.unit} left`
|
|
371
|
+
if(window.used!==undefined)
|
|
372
|
+
return `${window.used} ${window.unit} used`
|
|
373
|
+
return `${window.total} ${window.unit} capacity`
|
|
374
|
+
}
|
|
375
|
+
function resetTime(seconds,now){if(seconds===undefined)
|
|
376
|
+
return "Reset time unknown"
|
|
377
|
+
const date=new Date(seconds*1000)
|
|
378
|
+
const clock=date.toLocaleTimeString(undefined,{hour:"2-digit",minute:"2-digit"})
|
|
379
|
+
if(date.toDateString()===new Date(now).toDateString())
|
|
380
|
+
return `Resets ${clock}`
|
|
381
|
+
return `Resets ${date.toLocaleDateString(undefined, { month: "short", day: "numeric" })} ${clock}`
|
|
382
|
+
}
|
|
383
|
+
function quotaPresentation(window,now=Date.now()){const total=window.unit==="%"?100:window.total
|
|
384
|
+
const remaining=window.remaining??(total!==undefined&&window.used!==undefined?total-window.used:undefined)
|
|
385
|
+
const ratio=remaining!==undefined&&total!==undefined&&total>0?Math.max(0,Math.min(1,remaining / total)):undefined
|
|
386
|
+
return{value:measurement(window,remaining),ratio,reset:resetTime(window.resetsAt,now)}}
|
|
387
|
+
function QuotaWindowRow(props){const icons=useIcons()
|
|
388
|
+
const [columns,setColumns]=createSignal4(0)
|
|
389
|
+
const view=()=>quotaPresentation(props.window)
|
|
390
|
+
const scale=()=>{const ratio=view().ratio
|
|
391
|
+
if(ratio===undefined)
|
|
392
|
+
return " \xB7 scale unknown"
|
|
393
|
+
const width=Math.max(0,columns()-Bun.stringWidth(view().value)-1)
|
|
394
|
+
const filled=Math.round(ratio*width)
|
|
395
|
+
const symbols=icons.style()==="text"?["=","-"]:["\u2501","\u2500"]
|
|
396
|
+
return width?` ${symbols[0].repeat(filled)}${symbols[1].repeat(width - filled)}`:""
|
|
374
397
|
}
|
|
375
|
-
return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createElement("
|
|
398
|
+
return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createElement("span"),_el$4=_$createElement("text")
|
|
376
399
|
_$insertNode(_el$,_el$2)
|
|
377
|
-
_$insertNode(_el$,_el$3)
|
|
378
400
|
_$insertNode(_el$,_el$4)
|
|
401
|
+
_$setProp(_el$,"width","100%")
|
|
402
|
+
_$setProp(_el$,"minWidth",0)
|
|
403
|
+
_$setProp(_el$,"flexShrink",1)
|
|
404
|
+
_$setProp(_el$,"overflow","hidden")
|
|
405
|
+
_$setProp(_el$,"onSizeChange",function(){setColumns(this.width)
|
|
406
|
+
})
|
|
407
|
+
_$insertNode(_el$2,_el$3)
|
|
408
|
+
_$setProp(_el$2,"width","100%")
|
|
409
|
+
_$setProp(_el$2,"minWidth",0)
|
|
410
|
+
_$setProp(_el$2,"height",1)
|
|
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
|
-
_$setProp(_el$
|
|
387
|
-
_$
|
|
388
|
-
_$
|
|
389
|
-
_$
|
|
390
|
-
|
|
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,"width","100%")
|
|
416
|
+
_$setProp(_el$4,"minWidth",0)
|
|
417
|
+
_$setProp(_el$4,"height",1)
|
|
418
|
+
_$setProp(_el$4,"wrapMode","none")
|
|
419
|
+
_$setProp(_el$4,"truncate",true)
|
|
420
|
+
_$insert(_el$4,()=>view().reset)
|
|
421
|
+
_$effect((_p$)=>{var _v$=props.api.theme.current.textMuted,_v$2={fg:props.api.theme.current.text
|
|
422
|
+
},_v$3=props.api.theme.current.textMuted
|
|
393
423
|
_v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"fg",_v$,_p$.e))
|
|
394
|
-
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$3,"
|
|
424
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$3,"style",_v$2,_p$.t))
|
|
395
425
|
_v$3!==_p$.a&&(_p$.a=_$setProp(_el$4,"fg",_v$3,_p$.a))
|
|
396
426
|
return _p$
|
|
397
427
|
},{e:undefined,t:undefined,a:undefined
|
|
@@ -480,49 +510,32 @@ actions.review(option.value.slice("credit:".length)||undefined)
|
|
|
480
510
|
}})
|
|
481
511
|
}
|
|
482
512
|
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
513
|
import {For} from "solid-js"
|
|
489
514
|
import {effect as _$effect2} from "@opentui/solid"
|
|
490
|
-
import {memo as _$memo2} from "@opentui/solid"
|
|
491
|
-
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
492
515
|
import {insertNode as _$insertNode2} from "@opentui/solid"
|
|
493
516
|
import {insert as _$insert2} from "@opentui/solid"
|
|
517
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
494
518
|
import {setProp as _$setProp2} from "@opentui/solid"
|
|
495
519
|
import {createElement as _$createElement2} from "@opentui/solid"
|
|
496
|
-
function QuotaBalanceRow(props){return(()=>{var _el$=_$createElement2("
|
|
520
|
+
function QuotaBalanceRow(props){return(()=>{var _el$=_$createElement2("text"),_el$2=_$createElement2("span")
|
|
497
521
|
_$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)
|
|
522
|
+
_$setProp2(_el$,"wrapMode","none")
|
|
523
|
+
_$setProp2(_el$,"truncate",true)
|
|
524
|
+
_$insert2(_el$2,(()=>{var _c$=_$memo(()=>!!props.balance.unlimited)
|
|
505
525
|
return()=>_c$()?"No configured cap":`${props.balance.amount} ${props.balance.unit ?? "(provider unit not specified)"}`
|
|
506
526
|
})())
|
|
507
|
-
_$
|
|
508
|
-
|
|
509
|
-
|
|
527
|
+
_$insert2(_el$,()=>` \xB7 ${props.balance.scope} \xB7 ${props.balance.label}`,null)
|
|
528
|
+
_$effect2((_p$)=>{var _v$=props.api.theme.current.textMuted,_v$2={fg:props.api.theme.current.text
|
|
529
|
+
}
|
|
530
|
+
_v$!==_p$.e&&(_p$.e=_$setProp2(_el$,"fg",_v$,_p$.e))
|
|
531
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp2(_el$2,"style",_v$2,_p$.t))
|
|
510
532
|
return _p$
|
|
511
533
|
},{e:undefined,t:undefined
|
|
512
534
|
})
|
|
513
535
|
return _el$
|
|
514
536
|
})()
|
|
515
537
|
}
|
|
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
|
|
538
|
+
function QuotaSnapshotRows(props){return [_$createComponent4(For,{get each(){return props.snapshot.windows
|
|
526
539
|
},children:(window)=>_$createComponent4(QuotaWindowRow,{get api(){return props.api
|
|
527
540
|
},window
|
|
528
541
|
})
|
|
@@ -532,37 +545,6 @@ return _el$
|
|
|
532
545
|
})
|
|
533
546
|
})]
|
|
534
547
|
}
|
|
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
548
|
var text={type:"string",minLength:1,maxLength:512}
|
|
567
549
|
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
550
|
}
|
|
@@ -599,34 +581,40 @@ listeners.clear()
|
|
|
599
581
|
}}
|
|
600
582
|
return{adapter,onUpdated(listener){listeners.add(listener)
|
|
601
583
|
return()=>listeners.delete(listener)
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
}
|
|
584
|
+
}}}
|
|
585
|
+
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"]]
|
|
586
|
+
var PROVIDER_QUOTA_CAPABILITIES= rows.map(([id,name,sources,reason,url])=>({id,name,sources,reason,documentation:[url]}))
|
|
587
|
+
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"
|
|
588
|
+
}
|
|
589
|
+
function providerQuotaCapability(id,canonical){const key=aliases[canonical??id]??canonical??id
|
|
590
|
+
const found=PROVIDER_QUOTA_CAPABILITIES.find((entry)=>entry.id===key)
|
|
591
|
+
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/"]
|
|
592
|
+
}}
|
|
593
|
+
import {insert as _$insert8} from "@opentui/solid"
|
|
605
594
|
import {mergeProps as _$mergeProps} from "@opentui/solid"
|
|
606
|
-
import {
|
|
607
|
-
import {
|
|
608
|
-
import {effect as _$effect8} from "@opentui/solid"
|
|
595
|
+
import {setProp as _$setProp9} from "@opentui/solid"
|
|
596
|
+
import {effect as _$effect9} from "@opentui/solid"
|
|
609
597
|
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"
|
|
598
|
+
import {insertNode as _$insertNode6} from "@opentui/solid"
|
|
599
|
+
import {createElement as _$createElement9} from "@opentui/solid"
|
|
600
|
+
import {memo as _$memo7} from "@opentui/solid"
|
|
601
|
+
import {createComponent as _$createComponent12} from "@opentui/solid"
|
|
602
|
+
import {Show as Show6} from "solid-js"
|
|
603
|
+
import {useDialogs as useDialogs3} from "./tui.js"
|
|
628
604
|
import {setProp as _$setProp4} from "@opentui/solid"
|
|
605
|
+
import {effect as _$effect4} from "@opentui/solid"
|
|
606
|
+
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
607
|
+
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
629
608
|
import {createElement as _$createElement4} from "@opentui/solid"
|
|
609
|
+
import {memo as _$memo2} from "@opentui/solid"
|
|
610
|
+
import {createComponent as _$createComponent6} from "@opentui/solid"
|
|
611
|
+
import {Show} from "solid-js"
|
|
612
|
+
import {useDialogs as useDialogs2,useIcons as useIcons2} from "./tui.js"
|
|
613
|
+
import {createComponent as _$createComponent5} from "@opentui/solid"
|
|
614
|
+
import {effect as _$effect3} from "@opentui/solid"
|
|
615
|
+
import {insert as _$insert3} from "@opentui/solid"
|
|
616
|
+
import {setProp as _$setProp3} from "@opentui/solid"
|
|
617
|
+
import {createElement as _$createElement3} from "@opentui/solid"
|
|
630
618
|
import {SelectionBox} from "./tui.js"
|
|
631
619
|
import {createSignal as createSignal5,onCleanup} from "solid-js"
|
|
632
620
|
function sidebarInteractiveColors(theme,state,normalColor=theme.text,mode="row"){const highlighted=!state.disabled&&(state.focused||mode==="control"&&state.hovered)
|
|
@@ -661,63 +649,170 @@ descriptor.activate()
|
|
|
661
649
|
return true
|
|
662
650
|
}}}
|
|
663
651
|
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
|
|
652
|
+
},()=>props.api.theme.current.text,props.inline?"control":"row")
|
|
653
|
+
return _$createComponent5(SelectionBox,{ref:(node)=>item.ref(node),get id(){return props.id
|
|
654
|
+
},height:1,get flexGrow(){return props.flexGrow
|
|
655
|
+
},get maxWidth(){return props.maxWidth
|
|
656
|
+
},flexShrink:1,minWidth:3,get backgroundColor(){return item.backgroundColor()
|
|
667
657
|
},get onMouseOver(){return item.onMouseOver
|
|
668
658
|
},get onMouseOut(){return item.onMouseOut
|
|
669
659
|
},onMouseUp:(event)=>{event.stopPropagation()
|
|
670
660
|
item.activate(event)
|
|
671
|
-
},get children(){var _el$=_$
|
|
672
|
-
_$
|
|
673
|
-
_$
|
|
674
|
-
_$
|
|
675
|
-
_$
|
|
661
|
+
},get children(){var _el$=_$createElement3("text")
|
|
662
|
+
_$setProp3(_el$,"wrapMode","none")
|
|
663
|
+
_$setProp3(_el$,"truncate",true)
|
|
664
|
+
_$insert3(_el$,()=>props.label)
|
|
665
|
+
_$effect3((_$p)=>_$setProp3(_el$,"fg",item.foregroundColor(),_$p))
|
|
676
666
|
return _el$
|
|
677
667
|
}})
|
|
678
668
|
}
|
|
679
|
-
function CodexAccountControls(props){const icons=
|
|
669
|
+
function CodexAccountControls(props){const icons=useIcons2()
|
|
680
670
|
const model=()=>props.controller.current().model
|
|
681
|
-
const accountLink=createCodexAccountLink({api:props.api,preferences:props.preferences,adapter:props.codex,model,dialogs:
|
|
671
|
+
const accountLink=createCodexAccountLink({api:props.api,preferences:props.preferences,adapter:props.codex,model,dialogs:useDialogs2(props.api)
|
|
682
672
|
})
|
|
683
673
|
const eligible=()=>(props.model.providerID==="openai"||props.model.hostConnection?.providerID==="openai")&&props.model.hostConnection?.method!=="api"
|
|
684
|
-
const action=(id,row,label,onActivate)=>_$
|
|
674
|
+
const action=(id,row,label,onActivate)=>_$createComponent6(LimitsAction,{get api(){return props.api
|
|
685
675
|
},get interaction(){return props.interaction
|
|
686
676
|
},id:`${PLUGIN_ID}.limits.${id}`,get position(){return{section:props.navigationSection,row,column:0
|
|
687
677
|
}},label,onActivate,get disabled(){return accountLink.busy()
|
|
688
678
|
}})
|
|
689
|
-
return _$
|
|
690
|
-
},get children(){return [_$
|
|
691
|
-
},get children(){return [(()=>{var _el$=_$
|
|
692
|
-
_$insertNode3(_el$,_$
|
|
693
|
-
_$
|
|
679
|
+
return _$createComponent6(Show,{get when(){return eligible()
|
|
680
|
+
},get children(){return [_$createComponent6(Show,{get when(){return _$memo2(()=>!!!props.model.accountID)()&&(!props.model.hostConnection||props.model.hostConnection.status==="ready")
|
|
681
|
+
},get children(){return [(()=>{var _el$=_$createElement4("text")
|
|
682
|
+
_$insertNode3(_el$,_$createTextNode(`Link the matching Codex account once for this connection`))
|
|
683
|
+
_$effect4((_$p)=>_$setProp4(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
694
684
|
return _el$
|
|
695
|
-
})(),_$
|
|
696
|
-
}}),_$
|
|
697
|
-
},get children(){return [_$
|
|
685
|
+
})(),_$memo2(()=>action("link",2,`${icons.icon("scope")} Link Codex CLI account`,()=>void accountLink.link()))]
|
|
686
|
+
}}),_$createComponent6(Show,{get when(){return _$memo2(()=>!!(props.model.accountID&&props.model.accountSource!=="host"))()&&props.controller.snapshot()?.availability==="unauthenticated"
|
|
687
|
+
},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
688
|
},get children(){return action("relink",5,`${icons.icon("scope")} Relink Codex account`,()=>void accountLink.link())
|
|
699
689
|
}})]
|
|
700
690
|
}})]
|
|
701
691
|
}})
|
|
702
692
|
}
|
|
703
693
|
import {createComponent as _$createComponent8} from "@opentui/solid"
|
|
704
|
-
import {
|
|
694
|
+
import {Show as Show2} from "solid-js"
|
|
695
|
+
import {useIcons as useIcons3} from "./tui.js"
|
|
696
|
+
import {createComponent as _$createComponent7} from "@opentui/solid"
|
|
697
|
+
import {effect as _$effect5} from "@opentui/solid"
|
|
698
|
+
import {insert as _$insert4} from "@opentui/solid"
|
|
699
|
+
import {setProp as _$setProp5} from "@opentui/solid"
|
|
700
|
+
import {createElement as _$createElement5} from "@opentui/solid"
|
|
701
|
+
import {memo as _$memo3} from "@opentui/solid"
|
|
702
|
+
import {createEffect as createEffect2,createSignal as createSignal6,on} from "solid-js"
|
|
703
|
+
import {SelectionBox as SelectionBox2} from "./tui.js"
|
|
704
|
+
var graphemes=new Intl.Segmenter(undefined,{granularity:"grapheme"
|
|
705
|
+
})
|
|
706
|
+
function truncateEnd(value,width){if(Bun.stringWidth(value)<=width)
|
|
707
|
+
return value
|
|
708
|
+
if(width<=0)
|
|
709
|
+
return ""
|
|
710
|
+
const ellipsis=width>=3?"...":".".repeat(width)
|
|
711
|
+
let result=""
|
|
712
|
+
for(const{segment
|
|
713
|
+
} of graphemes.segment(value)){if(Bun.stringWidth(result + segment)>width-ellipsis.length)
|
|
714
|
+
break
|
|
715
|
+
result += segment
|
|
716
|
+
}
|
|
717
|
+
return result + ellipsis
|
|
718
|
+
}
|
|
719
|
+
function SectionHeaderControl(props){const [width,setWidth]=createSignal6()
|
|
720
|
+
const control=useSidebarItem(props.api,props.interaction,{id:props.action.id,position:()=>props.position,disabled:props.action.disabled,activate:props.action.onActivate
|
|
721
|
+
},()=>props.api.theme.current.accent,"control")
|
|
722
|
+
createEffect2(on(()=>[props.action.label(),props.resetWidth],()=>setWidth(undefined)))
|
|
723
|
+
const label=()=>width()===undefined||props.iconOnly?props.action.label():truncateEnd(props.action.label(),width()-2)
|
|
724
|
+
return _$createComponent7(SelectionBox2,{ref:(node)=>control.ref(node),get id(){return props.action.id
|
|
725
|
+
},get iconOnly(){return props.iconOnly
|
|
726
|
+
},get width(){return props.iconOnly?3:undefined
|
|
727
|
+
},get flexShrink(){return props.iconOnly?0:1
|
|
728
|
+
},minWidth:3,overflow:"hidden",get alignItems(){return props.iconOnly?"center":undefined
|
|
729
|
+
},get backgroundColor(){return control.backgroundColor()
|
|
730
|
+
},onSizeChange:function(){setWidth(this.width)
|
|
731
|
+
},get onMouseOver(){return control.onMouseOver
|
|
732
|
+
},get onMouseOut(){return control.onMouseOut
|
|
733
|
+
},onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
734
|
+
control.activate(event)
|
|
735
|
+
},get children(){var _el$=_$createElement5("text")
|
|
736
|
+
_$setProp5(_el$,"wrapMode","none")
|
|
737
|
+
_$setProp5(_el$,"height",1)
|
|
738
|
+
_$insert4(_el$,label)
|
|
739
|
+
_$effect5((_$p)=>_$setProp5(_el$,"fg",control.foregroundColor(),_$p))
|
|
740
|
+
return _el$
|
|
741
|
+
}})
|
|
742
|
+
}
|
|
743
|
+
function LimitsHeaderControls(props){const icons=useIcons3()
|
|
744
|
+
return [_$createComponent8(Show2,{get when(){return props.credits
|
|
745
|
+
},get children(){return _$createComponent8(SectionHeaderControl,{get api(){return props.api
|
|
746
|
+
},get interaction(){return props.interaction
|
|
747
|
+
},get position(){return{section:props.navigationSection,row:0,column:1
|
|
748
|
+
}},get action(){return{id:`${PLUGIN_ID}.limits.credits`,label:()=>"Banked Resets",disabled:()=>false,onActivate:props.onCredits
|
|
749
|
+
}}})
|
|
750
|
+
}}),_$createComponent8(SectionHeaderControl,{get api(){return props.api
|
|
751
|
+
},get interaction(){return props.interaction
|
|
752
|
+
},iconOnly:true,get position(){return{section:props.navigationSection,row:0,column:2
|
|
753
|
+
}},get action(){return{id:`${PLUGIN_ID}.limits.refresh`,label:()=>icons.icon(props.refreshing?"pending":"retry"),disabled:()=>props.refreshing||!props.canRefresh,onActivate:props.onRefresh
|
|
754
|
+
}}})]
|
|
755
|
+
}
|
|
705
756
|
import {insert as _$insert5} from "@opentui/solid"
|
|
757
|
+
import {effect as _$effect6} from "@opentui/solid"
|
|
758
|
+
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
759
|
+
import {insertNode as _$insertNode4} from "@opentui/solid"
|
|
760
|
+
import {memo as _$memo4} from "@opentui/solid"
|
|
761
|
+
import {createComponent as _$createComponent9} from "@opentui/solid"
|
|
706
762
|
import {setProp as _$setProp6} from "@opentui/solid"
|
|
707
763
|
import {createElement as _$createElement6} from "@opentui/solid"
|
|
708
|
-
import {Show as
|
|
764
|
+
import {Show as Show3} from "solid-js"
|
|
765
|
+
function LimitsModelRow(props){const names=()=>props.selection?.names(props.model)??{provider:props.model.providerID,model:props.model.modelID
|
|
766
|
+
}
|
|
767
|
+
return(()=>{var _el$=_$createElement6("box")
|
|
768
|
+
_$setProp6(_el$,"flexDirection","row")
|
|
769
|
+
_$setProp6(_el$,"minWidth",0)
|
|
770
|
+
_$insert5(_el$,_$createComponent9(LimitsAction,{get api(){return props.api
|
|
771
|
+
},get interaction(){return props.interaction
|
|
772
|
+
},inline:true,flexGrow:1,get maxWidth(){return Bun.stringWidth(`[${names().provider}] ${names().model}`) + 2
|
|
773
|
+
},id:`${PLUGIN_ID}.limits.model`,get position(){return{section:props.navigationSection,row:1,column:0
|
|
774
|
+
}},get label(){return `[${names().provider}] ${names().model}`
|
|
775
|
+
},get disabled(){return !props.selection?.canOpen("model",props.model)
|
|
776
|
+
},onActivate:()=>props.selection?.open("model",props.model)
|
|
777
|
+
}),null)
|
|
778
|
+
_$insert5(_el$,_$createComponent9(Show3,{get when(){return props.model.variant||props.selection?.variants(props.model).length
|
|
779
|
+
},get children(){return [(()=>{var _el$2=_$createElement6("text"),_el$3=_$createTextNode2(` \xB7 `)
|
|
780
|
+
_$insertNode4(_el$2,_el$3)
|
|
781
|
+
_$setProp6(_el$2,"flexShrink",0)
|
|
782
|
+
_$effect6((_$p)=>_$setProp6(_el$2,"fg",props.api.theme.current.textMuted,_$p))
|
|
783
|
+
return _el$2
|
|
784
|
+
})(),_$createComponent9(LimitsAction,{get api(){return props.api
|
|
785
|
+
},get interaction(){return props.interaction
|
|
786
|
+
},inline:true,id:`${PLUGIN_ID}.limits.variant`,get position(){return{section:props.navigationSection,row:1,column:1
|
|
787
|
+
}},get label(){return props.model.variant??"Default"
|
|
788
|
+
},get disabled(){return !props.selection?.canOpen("variant",props.model)
|
|
789
|
+
},onActivate:()=>props.selection?.open("variant",props.model)
|
|
790
|
+
})]
|
|
791
|
+
}}),null)
|
|
792
|
+
return _el$
|
|
793
|
+
})()
|
|
794
|
+
}
|
|
795
|
+
import {effect as _$effect7} from "@opentui/solid"
|
|
796
|
+
import {insert as _$insert6} from "@opentui/solid"
|
|
797
|
+
import {setProp as _$setProp7} from "@opentui/solid"
|
|
798
|
+
import {createElement as _$createElement7} from "@opentui/solid"
|
|
799
|
+
import {createComponent as _$createComponent10} from "@opentui/solid"
|
|
800
|
+
import {memo as _$memo5} from "@opentui/solid"
|
|
801
|
+
import {Show as Show4} from "solid-js"
|
|
709
802
|
function LimitsStatus(props){const message=()=>{const model=props.controller.current().model
|
|
710
803
|
const connection=model?.hostConnection
|
|
711
804
|
const snapshot=props.controller.snapshot()
|
|
712
805
|
const state=props.controller.state()
|
|
713
806
|
if(state.status==="error")
|
|
714
|
-
return snapshot?"Stale \xB7 refresh failed
|
|
807
|
+
return snapshot?"Stale \xB7 refresh failed":"Quota read failed \xB7 refresh to retry"
|
|
808
|
+
if(snapshot?.availability==="ready"&&(snapshot.windows.length>0||snapshot.balances?.length))
|
|
809
|
+
return
|
|
715
810
|
if(snapshot?.message)
|
|
716
811
|
return snapshot.availability==="stale"?`Stale \xB7 ${snapshot.message}`:snapshot.availability==="ready"?`Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()} \xB7 ${snapshot.message}`:snapshot.message
|
|
717
812
|
if(connection?.status==="loading")
|
|
718
813
|
return "Checking the OpenCode account\u2026"
|
|
719
814
|
if(connection?.status==="unavailable")
|
|
720
|
-
return "
|
|
815
|
+
return "Account metadata unavailable \xB7 refresh to retry"
|
|
721
816
|
if(connection?.status==="unsupported")
|
|
722
817
|
return "Codex quotas require an active ChatGPT OAuth connection"
|
|
723
818
|
if(!snapshot)
|
|
@@ -730,194 +825,150 @@ return "No documented quota bucket for this model"
|
|
|
730
825
|
if(availability==="rate_limited")
|
|
731
826
|
return "Provider rate-limited this read \xB7 try again later"
|
|
732
827
|
if(availability==="stale")
|
|
733
|
-
return "Stale provider data \xB7 refresh
|
|
828
|
+
return "Stale provider data \xB7 refresh to update"
|
|
734
829
|
return `Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()}`
|
|
735
830
|
}
|
|
736
|
-
return _$
|
|
737
|
-
},
|
|
738
|
-
_$
|
|
739
|
-
_$
|
|
740
|
-
_$
|
|
831
|
+
return _$createComponent10(Show4,{get when(){return _$memo5(()=>!!props.controller.current().model)()&&message()
|
|
832
|
+
},children:(value)=>(()=>{var _el$=_$createElement7("text")
|
|
833
|
+
_$setProp7(_el$,"wrapMode","word")
|
|
834
|
+
_$insert6(_el$,value)
|
|
835
|
+
_$effect7((_$p)=>_$setProp7(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
741
836
|
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"
|
|
837
|
+
})()
|
|
755
838
|
})
|
|
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
839
|
}
|
|
770
|
-
|
|
771
|
-
|
|
840
|
+
import {createComponent as _$createComponent11} from "@opentui/solid"
|
|
841
|
+
import {effect as _$effect8} from "@opentui/solid"
|
|
842
|
+
import {createTextNode as _$createTextNode3} from "@opentui/solid"
|
|
843
|
+
import {insertNode as _$insertNode5} from "@opentui/solid"
|
|
844
|
+
import {memo as _$memo6} from "@opentui/solid"
|
|
845
|
+
import {insert as _$insert7} from "@opentui/solid"
|
|
846
|
+
import {setProp as _$setProp8} from "@opentui/solid"
|
|
847
|
+
import {createElement as _$createElement8} from "@opentui/solid"
|
|
848
|
+
import {Show as Show5,createSignal as createSignal7} from "solid-js"
|
|
849
|
+
import {SelectionBox as SelectionBox3,useIcons as useIcons4} from "./tui.js"
|
|
850
|
+
function Section(props){const icons=useIcons4()
|
|
851
|
+
const [headerWidth,setHeaderWidth]=createSignal7(0)
|
|
772
852
|
const icon=()=>props.section?icons.section(props.section):props.icon
|
|
773
853
|
const theme=()=>props.api.theme.current
|
|
774
854
|
const item=useSidebarItem(props.api,props.interaction,{id:props.sectionId??`section.${props.title}`,position:()=>({section:props.navigationSection??0,row:0,column:0
|
|
775
855
|
}),activate:props.onToggle
|
|
776
856
|
})
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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
|
|
790
|
-
},flexDirection:"row",height:1,justifyContent:"space-between",gap:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
|
|
857
|
+
return(()=>{var _el$=_$createElement8("box")
|
|
858
|
+
_$setProp8(_el$,"gap",1)
|
|
859
|
+
_$insert7(_el$,_$createComponent11(SelectionBox3,{ref:(node)=>item.ref(node),get id(){return props.sectionId
|
|
860
|
+
},flexDirection:"row",height:1,justifyContent:"space-between",gap:1,get backgroundColor(){return item.backgroundColor()
|
|
791
861
|
},get onMouseOver(){return item.onMouseOver
|
|
792
862
|
},get onMouseOut(){return item.onMouseOut
|
|
793
|
-
},onMouseDown:(event)=>item.activate(event),onSizeChange:()
|
|
794
|
-
|
|
795
|
-
_$
|
|
796
|
-
_$
|
|
797
|
-
_$
|
|
798
|
-
_$
|
|
799
|
-
_$
|
|
800
|
-
_$
|
|
801
|
-
_$
|
|
863
|
+
},onMouseDown:(event)=>item.activate(event),onSizeChange:function(){setHeaderWidth(this.width)
|
|
864
|
+
},get children(){return [(()=>{var _el$2=_$createElement8("text"),_el$3=_$createElement8("span"),_el$4=_$createTextNode3(` `),_el$5=_$createElement8("span"),_el$6=_$createElement8("b")
|
|
865
|
+
_$insertNode5(_el$2,_el$3)
|
|
866
|
+
_$insertNode5(_el$2,_el$4)
|
|
867
|
+
_$insertNode5(_el$2,_el$5)
|
|
868
|
+
_$insertNode5(_el$2,_el$6)
|
|
869
|
+
_$setProp8(_el$2,"flexShrink",0)
|
|
870
|
+
_$setProp8(_el$2,"wrapMode","none")
|
|
871
|
+
_$insert7(_el$3,()=>icons.icon(props.open?"expanded":"collapsed"))
|
|
872
|
+
_$insert7(_el$5,(()=>{var _c$=_$memo6(()=>!!icon())
|
|
802
873
|
return()=>_c$()?`${icon()} `:""
|
|
803
874
|
})())
|
|
804
|
-
_$
|
|
805
|
-
_$
|
|
875
|
+
_$insert7(_el$6,()=>props.title)
|
|
876
|
+
_$effect8((_p$)=>{var _v$=item.foregroundColor(),_v$2={fg:item.focused()?item.foregroundColor():theme().accent
|
|
806
877
|
},_v$3={fg:item.focused()?item.foregroundColor():theme().accent
|
|
807
878
|
}
|
|
808
|
-
_v$!==_p$.e&&(_p$.e=_$
|
|
809
|
-
_v$2!==_p$.t&&(_p$.t=_$
|
|
810
|
-
_v$3!==_p$.a&&(_p$.a=_$
|
|
879
|
+
_v$!==_p$.e&&(_p$.e=_$setProp8(_el$2,"fg",_v$,_p$.e))
|
|
880
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp8(_el$3,"style",_v$2,_p$.t))
|
|
881
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp8(_el$5,"style",_v$3,_p$.a))
|
|
811
882
|
return _p$
|
|
812
883
|
},{e:undefined,t:undefined,a:undefined
|
|
813
884
|
})
|
|
814
885
|
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))
|
|
886
|
+
})(),(()=>{var _el$7=_$createElement8("box")
|
|
887
|
+
_$setProp8(_el$7,"flexDirection","row")
|
|
888
|
+
_$setProp8(_el$7,"gap",1)
|
|
889
|
+
_$setProp8(_el$7,"flexGrow",1)
|
|
890
|
+
_$setProp8(_el$7,"minWidth",0)
|
|
891
|
+
_$setProp8(_el$7,"justifyContent","flex-end")
|
|
892
|
+
_$insert7(_el$7,()=>props.headerControls,null)
|
|
893
|
+
_$insert7(_el$7,_$createComponent11(Show5,{get when(){return props.headerAction
|
|
894
|
+
},children:(action)=>_$createComponent11(SectionHeaderControl,{get api(){return props.api
|
|
895
|
+
},get interaction(){return props.interaction
|
|
896
|
+
},get action(){return action()
|
|
897
|
+
},get resetWidth(){return headerWidth()
|
|
898
|
+
},get position(){return{section:props.navigationSection??0,row:0,column:1
|
|
899
|
+
}}})
|
|
900
|
+
}),null)
|
|
901
|
+
_$insert7(_el$7,_$createComponent11(Show5,{get when(){return props.summary
|
|
902
|
+
},get children(){var _el$8=_$createElement8("text")
|
|
903
|
+
_$setProp8(_el$8,"wrapMode","none")
|
|
904
|
+
_$setProp8(_el$8,"truncate",true)
|
|
905
|
+
_$setProp8(_el$8,"height",1)
|
|
906
|
+
_$insert7(_el$8,()=>props.summary)
|
|
907
|
+
_$effect8((_p$)=>{var _v$4=item.focused()?item.foregroundColor():theme().textMuted,_v$5=props.headerAction?0:1
|
|
908
|
+
_v$4!==_p$.e&&(_p$.e=_$setProp8(_el$8,"fg",_v$4,_p$.e))
|
|
909
|
+
_v$5!==_p$.t&&(_p$.t=_$setProp8(_el$8,"flexShrink",_v$5,_p$.t))
|
|
844
910
|
return _p$
|
|
845
911
|
},{e:undefined,t:undefined
|
|
846
912
|
})
|
|
913
|
+
return _el$8
|
|
914
|
+
}}),null)
|
|
847
915
|
return _el$7
|
|
848
916
|
})()]
|
|
849
917
|
}}),null)
|
|
850
|
-
_$
|
|
918
|
+
_$insert7(_el$,_$createComponent11(Show5,{get when(){return props.open
|
|
851
919
|
},get children(){return props.children
|
|
852
920
|
}}),null)
|
|
853
921
|
return _el$
|
|
854
922
|
})()
|
|
855
923
|
}
|
|
856
|
-
function ProviderLimitsSection(props){const
|
|
857
|
-
const dialogs=useDialogs4(props.api)
|
|
924
|
+
function ProviderLimitsSection(props){const dialogs=useDialogs3(props.api)
|
|
858
925
|
const model=()=>props.controller.current().model
|
|
859
926
|
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
927
|
function openCredits(){const selected=model()
|
|
867
928
|
if(selected)
|
|
868
|
-
dialogs.open(()=>_$
|
|
929
|
+
dialogs.open(()=>_$createComponent12(ResetCreditDialog,{get api(){return props.api
|
|
869
930
|
},get preferences(){return props.preferences
|
|
870
931
|
},get controller(){return props.controller
|
|
871
932
|
},get adapter(){return props.codex
|
|
872
933
|
},model:selected
|
|
873
934
|
}))
|
|
874
935
|
}
|
|
875
|
-
return _$
|
|
936
|
+
return _$createComponent12(Section,{get api(){return props.api
|
|
876
937
|
},get interaction(){return props.interaction
|
|
877
938
|
},sectionId:`${PLUGIN_ID}.section.limits`,get navigationSection(){return props.navigationSection
|
|
878
|
-
},title:"LIMITS",section:"limits",get
|
|
939
|
+
},title:"LIMITS",section:"limits",summary:"",get headerControls(){return _$createComponent12(LimitsHeaderControls,{get api(){return props.api
|
|
940
|
+
},get interaction(){return props.interaction
|
|
941
|
+
},get navigationSection(){return props.navigationSection
|
|
942
|
+
},get credits(){return(snapshot()?.bankedResets?.availableCount??0)>0||Boolean(props.preferences.pendingResetAttempt())
|
|
943
|
+
},get refreshing(){return ["loading","refreshing"].includes(props.controller.state().status)
|
|
944
|
+
},get canRefresh(){return Boolean(model()&&(props.controller.current().adapter||model()?.hostConnection?.status==="unavailable"))
|
|
945
|
+
},onCredits:openCredits,onRefresh:()=>void props.controller.refresh(true)
|
|
946
|
+
})
|
|
879
947
|
},get open(){return props.preferences.expanded().limits
|
|
880
|
-
},onToggle:()=>props.preferences.toggleSectionExpanded("limits"),get children(){return _$
|
|
881
|
-
},get fallback(){return(()=>{var _el$=_$
|
|
882
|
-
_$
|
|
883
|
-
_$
|
|
948
|
+
},onToggle:()=>props.preferences.toggleSectionExpanded("limits"),get children(){return _$createComponent12(Show6,{get when(){return model()
|
|
949
|
+
},get fallback(){return(()=>{var _el$=_$createElement9("text")
|
|
950
|
+
_$insertNode6(_el$,_$createTextNode4(`Open a session to view model limits`))
|
|
951
|
+
_$effect9((_$p)=>_$setProp9(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
884
952
|
return _el$
|
|
885
953
|
})()
|
|
886
|
-
},children:(selected)=>(()=>{var _el$3=_$
|
|
887
|
-
_$
|
|
888
|
-
_$
|
|
889
|
-
_$
|
|
890
|
-
_$
|
|
891
|
-
_$
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
_$
|
|
954
|
+
},children:(selected)=>(()=>{var _el$3=_$createElement9("box")
|
|
955
|
+
_$setProp9(_el$3,"width","100%")
|
|
956
|
+
_$setProp9(_el$3,"minWidth",0)
|
|
957
|
+
_$setProp9(_el$3,"flexShrink",1)
|
|
958
|
+
_$setProp9(_el$3,"overflow","hidden")
|
|
959
|
+
_$insert8(_el$3,_$createComponent12(LimitsModelRow,_$mergeProps(props,{get model(){return selected()
|
|
960
|
+
},get selection(){return props.modelSelection
|
|
961
|
+
}})),null)
|
|
962
|
+
_$insert8(_el$3,_$createComponent12(CodexAccountControls,_$mergeProps(props,{get model(){return selected()
|
|
895
963
|
}})),null)
|
|
896
|
-
_$
|
|
897
|
-
},children:(quota)=>_$
|
|
964
|
+
_$insert8(_el$3,_$createComponent12(Show6,{get when(){return _$memo7(()=>!!(snapshot()&&["ready","stale"].includes(snapshot().availability)))()?snapshot():undefined
|
|
965
|
+
},children:(quota)=>_$createComponent12(QuotaSnapshotRows,{get api(){return props.api
|
|
898
966
|
},get snapshot(){return quota()
|
|
899
967
|
}})
|
|
900
968
|
}),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
|
|
969
|
+
_$insert8(_el$3,_$createComponent12(LimitsStatus,{get api(){return props.api
|
|
912
970
|
},get controller(){return props.controller
|
|
913
971
|
}}),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
972
|
return _el$3
|
|
922
973
|
})()
|
|
923
974
|
})
|
|
@@ -931,7 +982,7 @@ const model=api.state.session.get(sessionID)?.model
|
|
|
931
982
|
if(!model)
|
|
932
983
|
return
|
|
933
984
|
return{sessionID,providerID:model.providerID,modelID:model.id,...model.variant&&{variant:model.variant}}}
|
|
934
|
-
import {createSignal as
|
|
985
|
+
import {createSignal as createSignal8,untrack as untrack2} from "solid-js"
|
|
935
986
|
var CHATGPT_METHODS=new Set(["chatgpt-browser","chatgpt-headless"])
|
|
936
987
|
function providerAccountIdentity(provider,credentials){if(!provider.integrationID||provider.activation==="disabled")
|
|
937
988
|
return{status:"unsupported"}
|
|
@@ -953,7 +1004,7 @@ const header=Object.entries(provider.headers??{}).find(([name])=>name.toLowerCas
|
|
|
953
1004
|
if(accountID&&header&&header!==accountID)
|
|
954
1005
|
return{status:"loading"}
|
|
955
1006
|
return{status:"ready",id,method:"oauth",providerID,...accountID&&{accountID}}}
|
|
956
|
-
function createOpenCodeV2AccountSource(context,lifecycle){const [connections,setConnections]=
|
|
1007
|
+
function createOpenCodeV2AccountSource(context,lifecycle){const [connections,setConnections]=createSignal8({})
|
|
957
1008
|
let generation=0
|
|
958
1009
|
let disposed=false
|
|
959
1010
|
let lastModel
|
|
@@ -1016,6 +1067,26 @@ return{...model,accountID:undefined,accountSource:undefined}
|
|
|
1016
1067
|
const accountID=connection?.accountID??preferences.codexAccountForConnection(model.providerID,connection?.id,model.modelID)
|
|
1017
1068
|
const accountSource=connection?.accountID?"host":"binding"
|
|
1018
1069
|
return{...model,accountID,accountSource:accountID?accountSource:undefined}}
|
|
1070
|
+
var commandName=(kind)=>kind==="model"?"model.list":"variant.list"
|
|
1071
|
+
function createLimitsModelSelection(api,current,context){const sameTarget=(model)=>{const active=current()
|
|
1072
|
+
return active?.sessionID===model.sessionID&&active.providerID===model.providerID&&active.modelID===model.modelID
|
|
1073
|
+
}
|
|
1074
|
+
const legacy=(model)=>api.state.provider?.find((provider)=>provider.id===model.providerID)
|
|
1075
|
+
const variants=(model)=>context?context.ui.model.variant?.list?.()??[]:Object.keys(legacy(model)?.models[model.modelID]?.variants??{})
|
|
1076
|
+
const canOpen=(kind,model)=>{const command=api.keymap.getCommands().find((entry)=>entry.name===commandName(kind))
|
|
1077
|
+
const enabled=typeof command?.enabled==="function"?command.enabled():command?.enabled!==false
|
|
1078
|
+
return Boolean(command&&enabled&&sameTarget(model)&&(kind==="model"||variants(model).length>0))
|
|
1079
|
+
}
|
|
1080
|
+
return{names(model){if(context){const location=context.location??context.data.location.default()
|
|
1081
|
+
const provider=context.data.location.provider?.list?.(location)?.find((entry)=>entry.id===model.providerID)
|
|
1082
|
+
const item=context.data.location.model?.list?.(location)?.find((entry)=>entry.providerID===model.providerID&&entry.id===model.modelID)
|
|
1083
|
+
return{provider:provider?.name??model.providerID,model:item?.name??model.modelID}}
|
|
1084
|
+
const provider=legacy(model)
|
|
1085
|
+
return{provider:provider?.name??model.providerID,model:provider?.models[model.modelID]?.name??model.modelID
|
|
1086
|
+
}},variants,canOpen,open(kind,model){if(!canOpen(kind,model))
|
|
1087
|
+
return false
|
|
1088
|
+
return api.keymap.dispatchCommand(commandName(kind)).ok
|
|
1089
|
+
}}}
|
|
1019
1090
|
function selectedV2Model(context){const route=context.ui.router.current()
|
|
1020
1091
|
const model=context.ui.model.current()
|
|
1021
1092
|
if(route.type!=="session"||!model)
|
|
@@ -1035,7 +1106,7 @@ native?.onUpdated((providerID,modelID)=>{const selected=selectModel()
|
|
|
1035
1106
|
if(selected?.providerID===providerID&&selected.modelID===modelID)
|
|
1036
1107
|
controller.refresh()
|
|
1037
1108
|
})
|
|
1038
|
-
return{controller,codex,accountSource,selectModel,
|
|
1109
|
+
return{controller,codex,accountSource,selectModel,modelSelection:createLimitsModelSelection(api,selectModel,context)
|
|
1039
1110
|
}}
|
|
1040
1111
|
export{ProviderLimitsSection,bindCodexAccount,createCodexAppServerClient,createCodexQuotaAdapter,createOpenCodeV2AccountSource,createProviderLimitsController,createProviderQuotaIntegration,selectedV1Model
|
|
1041
1112
|
}
|