opencode-navigator 0.21.0 → 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 +10 -0
- package/PROVIDERS.md +1 -1
- package/README.md +25 -18
- package/dist/provider-limits.js +352 -274
- package/dist/server.js +2 -2
- package/dist/tui.js +94 -73
- package/package.json +1 -1
package/dist/provider-limits.js
CHANGED
|
@@ -117,7 +117,7 @@ child?.kill()
|
|
|
117
117
|
}}}
|
|
118
118
|
function normalizeProviderQuota(snapshot){if(!snapshot.providerId||!snapshot.providerName||!snapshot.model.providerID||!snapshot.model.modelID||!snapshot.model.sessionID||!Number.isFinite(snapshot.fetchedAt)){throw new Error("Invalid provider quota identity")
|
|
119
119
|
}
|
|
120
|
-
const windows=snapshot.windows.map((window)=>{if(!window.id||!window.label||window.modelID!==snapshot.model.modelID||!window.unit||window.used!==undefined&&!Number.isFinite(window.used)||window.remaining!==undefined&&!Number.isFinite(window.remaining)||window.used===undefined&&window.remaining===undefined&&window.total===undefined||window.total!==undefined&&(!Number.isFinite(window.total)||window.total<0)||window.durationMinutes!==undefined&&(!Number.isFinite(window.durationMinutes)||window.durationMinutes<0)||window.resetsAt!==undefined&&!Number.isFinite(window.resetsAt)){throw new Error("Quota window does not match the selected model or contains invalid values")
|
|
120
|
+
const windows=snapshot.windows.map((window)=>{if(!window.id||!window.label||window.scope!==undefined&&window.scope!=="account"&&window.scope!=="model"||(window.scope==="account"?!snapshot.accountId||window.modelID!==undefined:window.modelID!==snapshot.model.modelID)||!window.unit||window.used!==undefined&&!Number.isFinite(window.used)||window.remaining!==undefined&&!Number.isFinite(window.remaining)||window.used===undefined&&window.remaining===undefined&&window.total===undefined||window.total!==undefined&&(!Number.isFinite(window.total)||window.total<0)||window.durationMinutes!==undefined&&(!Number.isFinite(window.durationMinutes)||window.durationMinutes<0)||window.resetsAt!==undefined&&!Number.isFinite(window.resetsAt)){throw new Error("Quota window does not match the selected model or contains invalid values")
|
|
121
121
|
}
|
|
122
122
|
return{...window}})
|
|
123
123
|
const bankedResets=snapshot.bankedResets
|
|
@@ -239,8 +239,23 @@ requests.abortAll()
|
|
|
239
239
|
for(const adapter of adapters)
|
|
240
240
|
adapter.dispose?.()
|
|
241
241
|
}}}
|
|
242
|
-
function
|
|
243
|
-
|
|
242
|
+
function codexQuotaWindows(usage,modelID){const buckets=new Map
|
|
243
|
+
const legacy=usage.rateLimits
|
|
244
|
+
if(legacy.limitId==="codex"||!legacy.limitId&&!legacy.normalModelSlug)
|
|
245
|
+
buckets.set("codex",legacy)
|
|
246
|
+
const entries=Object.entries(usage.rateLimitsByLimitId??{})
|
|
247
|
+
for(const [key,limit] of entries)
|
|
248
|
+
buckets.set(limit.limitId??key,limit)
|
|
249
|
+
if(legacy.limitId&&!buckets.has(legacy.limitId))
|
|
250
|
+
buckets.set(legacy.limitId,legacy)
|
|
251
|
+
return [...buckets].flatMap(([id,limit])=>{const account=id==="codex"
|
|
252
|
+
if(!account&&limit.normalModelSlug!==modelID)
|
|
253
|
+
return []
|
|
254
|
+
return ["primary","secondary"].flatMap((name)=>{const value=limit[name]
|
|
255
|
+
if(!value)
|
|
256
|
+
return []
|
|
257
|
+
return [{id:`${id}.${name}`,label:account?`Codex account \xB7 ${name}`:`${limit.limitName ?? id} \xB7 ${name}`,limitID:id,...account?{scope:"account"}:{modelID},unit:"%",used:value.usedPercent,...value.windowDurationMins!==null&&{durationMinutes:value.windowDurationMins},...value.resetsAt!==null&&{resetsAt:value.resetsAt}}]
|
|
258
|
+
})
|
|
244
259
|
})
|
|
245
260
|
}
|
|
246
261
|
function createCodexQuotaAdapter(client,validateHost){const adapter={id:"codex",name:"Codex CLI",supports:(model)=>(model.providerID==="openai"||model.hostConnection?.providerID==="openai")&&model.hostConnection?.method!=="api"&&Boolean(model.accountID)&&(!model.hostConnection||model.hostConnection.status==="ready"),...validateHost&&{validateHost},async discoverAccount(signal){const account=await client.request("account/read",{refreshToken:false},signal)
|
|
@@ -260,12 +275,11 @@ return{...base,availability:"unauthenticated"}
|
|
|
260
275
|
const usage=await client.request("account/rateLimits/read",{supportsLunaReserve:false,excludeResetCreditDetails:false},signal)
|
|
261
276
|
if(!usage.accountId||usage.accountId!==model.accountID)
|
|
262
277
|
return{...base,availability:"unauthenticated"}
|
|
263
|
-
const
|
|
264
|
-
const matched=(candidates.length>0?candidates:[usage.rateLimits]).filter((limit)=>limit.normalModelSlug===model.modelID)
|
|
265
|
-
if(matched.length===0)
|
|
266
|
-
return{...base,accountId:usage.accountId,availability:"unsupported"}
|
|
278
|
+
const windows=codexQuotaWindows(usage,model.modelID)
|
|
267
279
|
const creditSummary=usage.rateLimitResetCredits
|
|
268
|
-
return normalizeProviderQuota({...base,accountId:usage.accountId,availability:"ready",ordinaryUsageAllowed:usage.ordinaryUsageAllowed??undefined,windows
|
|
280
|
+
return normalizeProviderQuota({...base,accountId:usage.accountId,availability:windows.length>0?"ready":"unavailable",ordinaryUsageAllowed:usage.ordinaryUsageAllowed??undefined,windows,...windows.some((window)=>window.scope==="account")&&{message:"Codex account quota; shared across models, not a model-specific allowance."
|
|
281
|
+
},...windows.length===0&&{message:"Codex reported no applicable usage windows for this account and model."
|
|
282
|
+
},...creditSummary&&{bankedResets:{availableCount:creditSummary.availableCount,...creditSummary.credits&&{credits:creditSummary.credits.map((credit)=>({id:credit.id,type:credit.resetType,status:credit.status,grantedAt:credit.grantedAt,...credit.expiresAt!==null&&{expiresAt:credit.expiresAt},...credit.title&&{title:credit.title},...credit.description&&{description:credit.description}}))
|
|
269
283
|
}}}})
|
|
270
284
|
},async prepareResetCreditConsumption(model,creditID,signal){const snapshot=await adapter.read(model,signal)
|
|
271
285
|
if(snapshot.availability==="unauthenticated"||!snapshot.accountId||snapshot.accountId!==model.accountID){throw new Error("Codex account is unavailable or changed")
|
|
@@ -348,36 +362,63 @@ return{link,busy
|
|
|
348
362
|
import {effect as _$effect} from "@opentui/solid"
|
|
349
363
|
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
350
364
|
import {insert as _$insert} from "@opentui/solid"
|
|
351
|
-
import {memo as _$memo} from "@opentui/solid"
|
|
352
365
|
import {setProp as _$setProp} from "@opentui/solid"
|
|
353
366
|
import {createElement as _$createElement} from "@opentui/solid"
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return `${
|
|
357
|
-
if(
|
|
358
|
-
return `${
|
|
359
|
-
|
|
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`
|
|
360
381
|
}
|
|
361
|
-
|
|
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}`
|
|
389
|
+
}
|
|
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")
|
|
362
408
|
_$insertNode(_el$,_el$2)
|
|
363
|
-
_$insertNode(_el$,_el$3)
|
|
364
409
|
_$insertNode(_el$,_el$4)
|
|
410
|
+
_$insertNode(_el$2,_el$3)
|
|
365
411
|
_$setProp(_el$2,"wrapMode","none")
|
|
366
412
|
_$setProp(_el$2,"truncate",true)
|
|
367
|
-
_$insert(_el$
|
|
368
|
-
_$insert(_el$2,
|
|
369
|
-
_$
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
_$
|
|
373
|
-
|
|
374
|
-
_$setProp(_el$4,"wrapMode","word")
|
|
375
|
-
_$insert(_el$4,(()=>{var _c$2=_$memo(()=>props.window.resetsAt===undefined)
|
|
376
|
-
return()=>_c$2()?"Reset time unavailable":`resets ${new Date(props.window.resetsAt * 1000).toLocaleString()}`
|
|
377
|
-
})())
|
|
378
|
-
_$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
|
|
379
420
|
_v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"fg",_v$,_p$.e))
|
|
380
|
-
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$3,"
|
|
421
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$3,"style",_v$2,_p$.t))
|
|
381
422
|
_v$3!==_p$.a&&(_p$.a=_$setProp(_el$4,"fg",_v$3,_p$.a))
|
|
382
423
|
return _p$
|
|
383
424
|
},{e:undefined,t:undefined,a:undefined
|
|
@@ -466,49 +507,32 @@ actions.review(option.value.slice("credit:".length)||undefined)
|
|
|
466
507
|
}})
|
|
467
508
|
}
|
|
468
509
|
import {createComponent as _$createComponent4} from "@opentui/solid"
|
|
469
|
-
import {effect as _$effect3} from "@opentui/solid"
|
|
470
|
-
import {insert as _$insert3} from "@opentui/solid"
|
|
471
|
-
import {memo as _$memo3} from "@opentui/solid"
|
|
472
|
-
import {setProp as _$setProp3} from "@opentui/solid"
|
|
473
|
-
import {createElement as _$createElement3} from "@opentui/solid"
|
|
474
510
|
import {For} from "solid-js"
|
|
475
511
|
import {effect as _$effect2} from "@opentui/solid"
|
|
476
|
-
import {memo as _$memo2} from "@opentui/solid"
|
|
477
|
-
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
478
512
|
import {insertNode as _$insertNode2} from "@opentui/solid"
|
|
479
513
|
import {insert as _$insert2} from "@opentui/solid"
|
|
514
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
480
515
|
import {setProp as _$setProp2} from "@opentui/solid"
|
|
481
516
|
import {createElement as _$createElement2} from "@opentui/solid"
|
|
482
|
-
function QuotaBalanceRow(props){return(()=>{var _el$=_$createElement2("
|
|
517
|
+
function QuotaBalanceRow(props){return(()=>{var _el$=_$createElement2("text"),_el$2=_$createElement2("span")
|
|
483
518
|
_$insertNode2(_el$,_el$2)
|
|
484
|
-
_$
|
|
485
|
-
_$
|
|
486
|
-
_$
|
|
487
|
-
_$insert2(_el$2,()=>props.balance.label,_el$3)
|
|
488
|
-
_$insert2(_el$2,()=>props.balance.scope,null)
|
|
489
|
-
_$setProp2(_el$4,"wrapMode","word")
|
|
490
|
-
_$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)
|
|
491
522
|
return()=>_c$()?"No configured cap":`${props.balance.amount} ${props.balance.unit ?? "(provider unit not specified)"}`
|
|
492
523
|
})())
|
|
493
|
-
_$
|
|
494
|
-
|
|
495
|
-
|
|
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))
|
|
496
529
|
return _p$
|
|
497
530
|
},{e:undefined,t:undefined
|
|
498
531
|
})
|
|
499
532
|
return _el$
|
|
500
533
|
})()
|
|
501
534
|
}
|
|
502
|
-
function QuotaSnapshotRows(props){return [(()
|
|
503
|
-
_$setProp3(_el$,"wrapMode","none")
|
|
504
|
-
_$setProp3(_el$,"truncate",true)
|
|
505
|
-
_$insert3(_el$,()=>props.snapshot.providerName,null)
|
|
506
|
-
_$insert3(_el$,(()=>{var _c$=_$memo3(()=>!!props.snapshot.accountId)
|
|
507
|
-
return()=>_c$()?` \xB7 ${props.snapshot.accountId}`:""
|
|
508
|
-
})(),null)
|
|
509
|
-
_$effect3((_$p)=>_$setProp3(_el$,"fg",props.api.theme.current.textMuted,_$p))
|
|
510
|
-
return _el$
|
|
511
|
-
})(),_$createComponent4(For,{get each(){return props.snapshot.windows
|
|
535
|
+
function QuotaSnapshotRows(props){return [_$createComponent4(For,{get each(){return props.snapshot.windows
|
|
512
536
|
},children:(window)=>_$createComponent4(QuotaWindowRow,{get api(){return props.api
|
|
513
537
|
},window
|
|
514
538
|
})
|
|
@@ -518,37 +542,6 @@ return _el$
|
|
|
518
542
|
})
|
|
519
543
|
})]
|
|
520
544
|
}
|
|
521
|
-
import {createComponent as _$createComponent5} from "@opentui/solid"
|
|
522
|
-
import {createSignal as createSignal4,onMount} from "solid-js"
|
|
523
|
-
import {SelectionMenu as SelectionMenu2,useDialogs as useDialogs2} from "./tui.js"
|
|
524
|
-
var rows=[["openai","OpenAI / Codex",["subscription","api-rate-limits"],"Codex account RPC; 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"]]
|
|
525
|
-
var PROVIDER_QUOTA_CAPABILITIES= rows.map(([id,name,sources,reason,url])=>({id,name,sources,reason,documentation:[url]}))
|
|
526
|
-
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"
|
|
527
|
-
}
|
|
528
|
-
function providerQuotaCapability(id,canonical){const key=aliases[canonical??id]??canonical??id
|
|
529
|
-
const found=PROVIDER_QUOTA_CAPABILITIES.find((entry)=>entry.id===key)
|
|
530
|
-
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/"]
|
|
531
|
-
}}
|
|
532
|
-
function providerQuotaCatalog(providers=[]){const entries=new Map(PROVIDER_QUOTA_CAPABILITIES.map((entry)=>[entry.id,entry]))
|
|
533
|
-
for(const provider of providers)
|
|
534
|
-
entries.set(provider.id,{...providerQuotaCapability(provider.id,provider.canonical),id:provider.id,name:provider.name
|
|
535
|
-
})
|
|
536
|
-
return [...entries.values()].sort((a,b)=>a.name.localeCompare(b.name))
|
|
537
|
-
}
|
|
538
|
-
function ProviderSupportDialog(props){const dialogs=useDialogs2(props.api)
|
|
539
|
-
const [entries,setEntries]=createSignal4(providerQuotaCatalog())
|
|
540
|
-
onMount(()=>{if(props.load)
|
|
541
|
-
props.load().then(setEntries).catch(()=>{})
|
|
542
|
-
})
|
|
543
|
-
return _$createComponent5(SelectionMenu2,{get api(){return props.api
|
|
544
|
-
},get title(){return `Provider sources \xB7 ${entries().length}`
|
|
545
|
-
},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}`
|
|
546
|
-
})),{title:"Close",value:"close",description:"Return to the sidebar",icon:"close"
|
|
547
|
-
}]
|
|
548
|
-
},onSelect:(option)=>{if(option.value==="close")
|
|
549
|
-
dialogs.back()
|
|
550
|
-
}})
|
|
551
|
-
}
|
|
552
545
|
var text={type:"string",minLength:1,maxLength:512}
|
|
553
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
|
|
554
547
|
}
|
|
@@ -585,36 +578,42 @@ listeners.clear()
|
|
|
585
578
|
}}
|
|
586
579
|
return{adapter,onUpdated(listener){listeners.add(listener)
|
|
587
580
|
return()=>listeners.delete(listener)
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
}
|
|
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"
|
|
591
591
|
import {mergeProps as _$mergeProps} from "@opentui/solid"
|
|
592
|
-
import {
|
|
593
|
-
import {
|
|
594
|
-
import {effect as _$effect8} from "@opentui/solid"
|
|
592
|
+
import {setProp as _$setProp9} from "@opentui/solid"
|
|
593
|
+
import {effect as _$effect9} from "@opentui/solid"
|
|
595
594
|
import {createTextNode as _$createTextNode4} from "@opentui/solid"
|
|
596
|
-
import {insertNode as _$
|
|
597
|
-
import {createElement as _$
|
|
598
|
-
import {memo as _$
|
|
599
|
-
import {createComponent as _$
|
|
600
|
-
import {Show as
|
|
601
|
-
import {useDialogs as
|
|
602
|
-
import {setProp as _$setProp5} from "@opentui/solid"
|
|
603
|
-
import {effect as _$effect5} from "@opentui/solid"
|
|
604
|
-
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
605
|
-
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
606
|
-
import {createElement as _$createElement5} from "@opentui/solid"
|
|
607
|
-
import {memo as _$memo4} from "@opentui/solid"
|
|
608
|
-
import {createComponent as _$createComponent7} from "@opentui/solid"
|
|
609
|
-
import {Show} from "solid-js"
|
|
610
|
-
import {useDialogs as useDialogs3,useIcons} from "./tui.js"
|
|
611
|
-
import {createComponent as _$createComponent6} from "@opentui/solid"
|
|
612
|
-
import {effect as _$effect4} from "@opentui/solid"
|
|
613
|
-
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"
|
|
614
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"
|
|
615
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"
|
|
616
615
|
import {SelectionBox} from "./tui.js"
|
|
617
|
-
import {createSignal as
|
|
616
|
+
import {createSignal as createSignal4,onCleanup} from "solid-js"
|
|
618
617
|
function sidebarInteractiveColors(theme,state,normalColor=theme.text,mode="row"){const highlighted=!state.disabled&&(state.focused||mode==="control"&&state.hovered)
|
|
619
618
|
let backgroundColor=theme.backgroundPanel
|
|
620
619
|
let foregroundColor=normalColor
|
|
@@ -630,7 +629,7 @@ else if(highlighted)
|
|
|
630
629
|
foregroundColor=theme.selectedListItemText
|
|
631
630
|
return{backgroundColor,foregroundColor}}
|
|
632
631
|
function useSidebarItem(api,interaction,descriptor,normalColor=()=>api.theme.current.text,mode="row"){let unregister
|
|
633
|
-
const [hovered,setHovered]=
|
|
632
|
+
const [hovered,setHovered]=createSignal4(false)
|
|
634
633
|
const disabled=()=>descriptor.disabled?.()===true
|
|
635
634
|
const focused=()=>Boolean(interaction?.ownsFocus()&&interaction.isSelected(descriptor.id))
|
|
636
635
|
const colors=()=>sidebarInteractiveColors(api.theme.current,{focused:focused(),hovered:hovered(),disabled:disabled()},normalColor(),mode)
|
|
@@ -647,63 +646,170 @@ descriptor.activate()
|
|
|
647
646
|
return true
|
|
648
647
|
}}}
|
|
649
648
|
function LimitsAction(props){const item=useSidebarItem(props.api,props.interaction,{id:props.id,position:()=>props.position,disabled:()=>props.disabled===true,activate:props.onActivate
|
|
650
|
-
})
|
|
651
|
-
return _$
|
|
652
|
-
},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()
|
|
653
654
|
},get onMouseOver(){return item.onMouseOver
|
|
654
655
|
},get onMouseOut(){return item.onMouseOut
|
|
655
656
|
},onMouseUp:(event)=>{event.stopPropagation()
|
|
656
657
|
item.activate(event)
|
|
657
|
-
},get children(){var _el$=_$
|
|
658
|
-
_$
|
|
659
|
-
_$
|
|
660
|
-
_$
|
|
661
|
-
_$
|
|
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))
|
|
662
663
|
return _el$
|
|
663
664
|
}})
|
|
664
665
|
}
|
|
665
|
-
function CodexAccountControls(props){const icons=
|
|
666
|
+
function CodexAccountControls(props){const icons=useIcons2()
|
|
666
667
|
const model=()=>props.controller.current().model
|
|
667
|
-
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)
|
|
668
669
|
})
|
|
669
670
|
const eligible=()=>(props.model.providerID==="openai"||props.model.hostConnection?.providerID==="openai")&&props.model.hostConnection?.method!=="api"
|
|
670
|
-
const action=(id,row,label,onActivate)=>_$
|
|
671
|
+
const action=(id,row,label,onActivate)=>_$createComponent6(LimitsAction,{get api(){return props.api
|
|
671
672
|
},get interaction(){return props.interaction
|
|
672
673
|
},id:`${PLUGIN_ID}.limits.${id}`,get position(){return{section:props.navigationSection,row,column:0
|
|
673
674
|
}},label,onActivate,get disabled(){return accountLink.busy()
|
|
674
675
|
}})
|
|
675
|
-
return _$
|
|
676
|
-
},get children(){return [_$
|
|
677
|
-
},get children(){return [(()=>{var _el$=_$
|
|
678
|
-
_$insertNode3(_el$,_$
|
|
679
|
-
_$
|
|
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))
|
|
680
681
|
return _el$
|
|
681
|
-
})(),_$
|
|
682
|
-
}}),_$
|
|
683
|
-
},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"
|
|
684
685
|
},get children(){return action("relink",5,`${icons.icon("scope")} Relink Codex account`,()=>void accountLink.link())
|
|
685
686
|
}})]
|
|
686
687
|
}})]
|
|
687
688
|
}})
|
|
688
689
|
}
|
|
689
690
|
import {createComponent as _$createComponent8} from "@opentui/solid"
|
|
690
|
-
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
|
+
}
|
|
691
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"
|
|
692
759
|
import {setProp as _$setProp6} from "@opentui/solid"
|
|
693
760
|
import {createElement as _$createElement6} from "@opentui/solid"
|
|
694
|
-
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"
|
|
695
799
|
function LimitsStatus(props){const message=()=>{const model=props.controller.current().model
|
|
696
800
|
const connection=model?.hostConnection
|
|
697
801
|
const snapshot=props.controller.snapshot()
|
|
698
802
|
const state=props.controller.state()
|
|
699
803
|
if(state.status==="error")
|
|
700
|
-
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
|
|
701
807
|
if(snapshot?.message)
|
|
702
808
|
return snapshot.availability==="stale"?`Stale \xB7 ${snapshot.message}`:snapshot.availability==="ready"?`Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()} \xB7 ${snapshot.message}`:snapshot.message
|
|
703
809
|
if(connection?.status==="loading")
|
|
704
810
|
return "Checking the OpenCode account\u2026"
|
|
705
811
|
if(connection?.status==="unavailable")
|
|
706
|
-
return "
|
|
812
|
+
return "Account metadata unavailable \xB7 refresh to retry"
|
|
707
813
|
if(connection?.status==="unsupported")
|
|
708
814
|
return "Codex quotas require an active ChatGPT OAuth connection"
|
|
709
815
|
if(!snapshot)
|
|
@@ -716,194 +822,146 @@ return "No documented quota bucket for this model"
|
|
|
716
822
|
if(availability==="rate_limited")
|
|
717
823
|
return "Provider rate-limited this read \xB7 try again later"
|
|
718
824
|
if(availability==="stale")
|
|
719
|
-
return "Stale provider data \xB7 refresh
|
|
825
|
+
return "Stale provider data \xB7 refresh to update"
|
|
720
826
|
return `Updated ${new Date(snapshot.fetchedAt).toLocaleTimeString()}`
|
|
721
827
|
}
|
|
722
|
-
return _$
|
|
723
|
-
},
|
|
724
|
-
_$
|
|
725
|
-
_$
|
|
726
|
-
_$
|
|
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))
|
|
727
833
|
return _el$
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
import {createComponent as _$createComponent9} from "@opentui/solid"
|
|
731
|
-
import {effect as _$effect7} from "@opentui/solid"
|
|
732
|
-
import {createTextNode as _$createTextNode3} from "@opentui/solid"
|
|
733
|
-
import {insertNode as _$insertNode4} from "@opentui/solid"
|
|
734
|
-
import {memo as _$memo5} from "@opentui/solid"
|
|
735
|
-
import {insert as _$insert6} from "@opentui/solid"
|
|
736
|
-
import {setProp as _$setProp7} from "@opentui/solid"
|
|
737
|
-
import {createElement as _$createElement7} from "@opentui/solid"
|
|
738
|
-
import {Show as Show3,createEffect as createEffect2,createSignal as createSignal6} from "solid-js"
|
|
739
|
-
import {SelectionBox as SelectionBox2,useIcons as useIcons2} from "./tui.js"
|
|
740
|
-
var graphemes=new Intl.Segmenter(undefined,{granularity:"grapheme"
|
|
834
|
+
})()
|
|
741
835
|
})
|
|
742
|
-
function truncateEnd(value,maxWidth){if(Bun.stringWidth(value)<=maxWidth)
|
|
743
|
-
return value
|
|
744
|
-
if(maxWidth<=0)
|
|
745
|
-
return ""
|
|
746
|
-
const ellipsis=maxWidth>=3?"...":".".repeat(maxWidth)
|
|
747
|
-
const contentWidth=maxWidth-Bun.stringWidth(ellipsis)
|
|
748
|
-
let result=""
|
|
749
|
-
for(const{segment
|
|
750
|
-
} of graphemes.segment(value)){if(Bun.stringWidth(result + segment)>contentWidth)
|
|
751
|
-
break
|
|
752
|
-
result += segment
|
|
753
|
-
}
|
|
754
|
-
return result + ellipsis
|
|
755
836
|
}
|
|
756
|
-
|
|
757
|
-
|
|
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)
|
|
758
849
|
const icon=()=>props.section?icons.section(props.section):props.icon
|
|
759
850
|
const theme=()=>props.api.theme.current
|
|
760
851
|
const item=useSidebarItem(props.api,props.interaction,{id:props.sectionId??`section.${props.title}`,position:()=>({section:props.navigationSection??0,row:0,column:0
|
|
761
852
|
}),activate:props.onToggle
|
|
762
853
|
})
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
createEffect2(()=>{props.headerAction?.label()
|
|
767
|
-
setActionWidth(undefined)
|
|
768
|
-
})
|
|
769
|
-
const actionLabel=()=>{const label=props.headerAction?.label()??""
|
|
770
|
-
const width=actionWidth()
|
|
771
|
-
return width===undefined?label:truncateEnd(label,width-2)
|
|
772
|
-
}
|
|
773
|
-
return(()=>{var _el$=_$createElement7("box")
|
|
774
|
-
_$setProp7(_el$,"gap",1)
|
|
775
|
-
_$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
|
|
776
857
|
},flexDirection:"row",height:1,justifyContent:"space-between",gap:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
|
|
777
858
|
},get onMouseOver(){return item.onMouseOver
|
|
778
859
|
},get onMouseOut(){return item.onMouseOut
|
|
779
|
-
},onMouseDown:(event)=>item.activate(event),onSizeChange:()
|
|
780
|
-
|
|
781
|
-
_$
|
|
782
|
-
_$
|
|
783
|
-
_$
|
|
784
|
-
_$
|
|
785
|
-
_$
|
|
786
|
-
_$
|
|
787
|
-
_$
|
|
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())
|
|
788
870
|
return()=>_c$()?`${icon()} `:""
|
|
789
871
|
})())
|
|
790
|
-
_$
|
|
791
|
-
_$
|
|
872
|
+
_$insert7(_el$6,()=>props.title)
|
|
873
|
+
_$effect8((_p$)=>{var _v$=item.foregroundColor(),_v$2={fg:item.focused()?item.foregroundColor():theme().accent
|
|
792
874
|
},_v$3={fg:item.focused()?item.foregroundColor():theme().accent
|
|
793
875
|
}
|
|
794
|
-
_v$!==_p$.e&&(_p$.e=_$
|
|
795
|
-
_v$2!==_p$.t&&(_p$.t=_$
|
|
796
|
-
_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))
|
|
797
879
|
return _p$
|
|
798
880
|
},{e:undefined,t:undefined,a:undefined
|
|
799
881
|
})
|
|
800
882
|
return _el$2
|
|
801
|
-
})(),(()=>{var _el$7=_$
|
|
802
|
-
_$
|
|
803
|
-
_$
|
|
804
|
-
_$
|
|
805
|
-
_$
|
|
806
|
-
_$
|
|
807
|
-
_$
|
|
808
|
-
_$
|
|
809
|
-
},
|
|
810
|
-
},
|
|
811
|
-
},get
|
|
812
|
-
},get
|
|
813
|
-
},
|
|
814
|
-
|
|
815
|
-
},
|
|
816
|
-
_$
|
|
817
|
-
_$
|
|
818
|
-
_$
|
|
819
|
-
_$
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
_$
|
|
824
|
-
_$
|
|
825
|
-
_$setProp7(_el$8,"height",1)
|
|
826
|
-
_$insert6(_el$8,()=>props.summary)
|
|
827
|
-
_$effect7((_p$)=>{var _v$4=item.focused()?item.foregroundColor():theme().textMuted,_v$5=props.headerAction?0:1
|
|
828
|
-
_v$4!==_p$.e&&(_p$.e=_$setProp7(_el$8,"fg",_v$4,_p$.e))
|
|
829
|
-
_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))
|
|
830
907
|
return _p$
|
|
831
908
|
},{e:undefined,t:undefined
|
|
832
909
|
})
|
|
910
|
+
return _el$8
|
|
911
|
+
}}),null)
|
|
833
912
|
return _el$7
|
|
834
913
|
})()]
|
|
835
914
|
}}),null)
|
|
836
|
-
_$
|
|
915
|
+
_$insert7(_el$,_$createComponent11(Show5,{get when(){return props.open
|
|
837
916
|
},get children(){return props.children
|
|
838
917
|
}}),null)
|
|
839
918
|
return _el$
|
|
840
919
|
})()
|
|
841
920
|
}
|
|
842
|
-
function ProviderLimitsSection(props){const
|
|
843
|
-
const dialogs=useDialogs4(props.api)
|
|
921
|
+
function ProviderLimitsSection(props){const dialogs=useDialogs3(props.api)
|
|
844
922
|
const model=()=>props.controller.current().model
|
|
845
923
|
const snapshot=props.controller.snapshot
|
|
846
|
-
const count=()=>(snapshot()?.windows.length??0) + (snapshot()?.balances?.length??0)
|
|
847
|
-
const action=(id,row,label,onActivate,disabled=false)=>_$createComponent10(LimitsAction,{get api(){return props.api
|
|
848
|
-
},get interaction(){return props.interaction
|
|
849
|
-
},id:`${PLUGIN_ID}.limits.${id}`,get position(){return{section:props.navigationSection,row,column:0
|
|
850
|
-
}},label,onActivate,disabled
|
|
851
|
-
})
|
|
852
924
|
function openCredits(){const selected=model()
|
|
853
925
|
if(selected)
|
|
854
|
-
dialogs.open(()=>_$
|
|
926
|
+
dialogs.open(()=>_$createComponent12(ResetCreditDialog,{get api(){return props.api
|
|
855
927
|
},get preferences(){return props.preferences
|
|
856
928
|
},get controller(){return props.controller
|
|
857
929
|
},get adapter(){return props.codex
|
|
858
930
|
},model:selected
|
|
859
931
|
}))
|
|
860
932
|
}
|
|
861
|
-
return _$
|
|
933
|
+
return _$createComponent12(Section,{get api(){return props.api
|
|
862
934
|
},get interaction(){return props.interaction
|
|
863
935
|
},sectionId:`${PLUGIN_ID}.section.limits`,get navigationSection(){return props.navigationSection
|
|
864
|
-
},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
|
+
})
|
|
865
944
|
},get open(){return props.preferences.expanded().limits
|
|
866
|
-
},onToggle:()=>props.preferences.toggleSectionExpanded("limits"),get children(){return _$
|
|
867
|
-
},get fallback(){return(()=>{var _el$=_$
|
|
868
|
-
_$
|
|
869
|
-
_$
|
|
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))
|
|
870
949
|
return _el$
|
|
871
950
|
})()
|
|
872
|
-
},children:(selected)=>(()=>{var _el$3=_$
|
|
873
|
-
_$
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
_$
|
|
877
|
-
_$setProp8(_el$4,"truncate",true)
|
|
878
|
-
_$insert7(_el$4,()=>selected().providerID,_el$5)
|
|
879
|
-
_$insert7(_el$4,()=>selected().modelID,null)
|
|
880
|
-
_$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()
|
|
881
956
|
}})),null)
|
|
882
|
-
_$
|
|
883
|
-
},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
|
|
884
959
|
},get snapshot(){return quota()
|
|
885
960
|
}})
|
|
886
961
|
}),null)
|
|
887
|
-
_$
|
|
888
|
-
},children:(credits)=>[(()=>{var _el$6=_$createElement8("text"),_el$7=_$createTextNode4(`Banked resets: `)
|
|
889
|
-
_$insertNode5(_el$6,_el$7)
|
|
890
|
-
_$insert7(_el$6,()=>credits().availableCount,null)
|
|
891
|
-
_$effect8((_$p)=>_$setProp8(_el$6,"fg",props.api.theme.current.textMuted,_$p))
|
|
892
|
-
return _el$6
|
|
893
|
-
})(),_$createComponent10(Show4,{get when(){return credits().availableCount>0||props.preferences.pendingResetAttempt()
|
|
894
|
-
},get children(){return action("credits",2,`${icons.icon("info")} Review reset credits`,openCredits)
|
|
895
|
-
}})]
|
|
896
|
-
}),null)
|
|
897
|
-
_$insert7(_el$3,_$createComponent10(LimitsStatus,{get api(){return props.api
|
|
962
|
+
_$insert8(_el$3,_$createComponent12(LimitsStatus,{get api(){return props.api
|
|
898
963
|
},get controller(){return props.controller
|
|
899
964
|
}}),null)
|
|
900
|
-
_$insert7(_el$3,_$createComponent10(Show4,{get when(){return props.controller.current().adapter||selected().hostConnection?.status==="unavailable"
|
|
901
|
-
},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))
|
|
902
|
-
}}),null)
|
|
903
|
-
_$insert7(_el$3,()=>action("sources",6,`${icons.icon("info")} Provider sources`,()=>dialogs.open(()=>_$createComponent10(ProviderSupportDialog,{get api(){return props.api
|
|
904
|
-
},get load(){return props.capabilities
|
|
905
|
-
}}))),null)
|
|
906
|
-
_$effect8((_$p)=>_$setProp8(_el$4,"fg",props.api.theme.current.textMuted,_$p))
|
|
907
965
|
return _el$3
|
|
908
966
|
})()
|
|
909
967
|
})
|
|
@@ -1002,6 +1060,26 @@ return{...model,accountID:undefined,accountSource:undefined}
|
|
|
1002
1060
|
const accountID=connection?.accountID??preferences.codexAccountForConnection(model.providerID,connection?.id,model.modelID)
|
|
1003
1061
|
const accountSource=connection?.accountID?"host":"binding"
|
|
1004
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
|
+
}}}
|
|
1005
1083
|
function selectedV2Model(context){const route=context.ui.router.current()
|
|
1006
1084
|
const model=context.ui.model.current()
|
|
1007
1085
|
if(route.type!=="session"||!model)
|
|
@@ -1021,7 +1099,7 @@ native?.onUpdated((providerID,modelID)=>{const selected=selectModel()
|
|
|
1021
1099
|
if(selected?.providerID===providerID&&selected.modelID===modelID)
|
|
1022
1100
|
controller.refresh()
|
|
1023
1101
|
})
|
|
1024
|
-
return{controller,codex,accountSource,selectModel,
|
|
1102
|
+
return{controller,codex,accountSource,selectModel,modelSelection:createLimitsModelSelection(api,selectModel,context)
|
|
1025
1103
|
}}
|
|
1026
1104
|
export{ProviderLimitsSection,bindCodexAccount,createCodexAppServerClient,createCodexQuotaAdapter,createOpenCodeV2AccountSource,createProviderLimitsController,createProviderQuotaIntegration,selectedV1Model
|
|
1027
1105
|
}
|