dsh-opencode-go 0.1.9 → 0.1.11
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/README.en.md +36 -7
- package/README.md +36 -7
- package/docs/verification.md +77 -1
- package/lib/client.js +258 -114
- package/lib/index.js +257 -49
- package/lib/types/catalog.d.ts +5 -3
- package/lib/types/client/ModelEditor.d.ts +6 -2
- package/lib/types/client/Section.d.ts +2 -0
- package/lib/types/client/UsagePill.d.ts +1 -0
- package/lib/types/client/locales.d.ts +14 -2
- package/lib/types/client/section-controller.d.ts +16 -11
- package/lib/types/config.d.ts +5 -5
- package/lib/types/json-response.d.ts +11 -0
- package/lib/types/models-contract.d.ts +12 -1
- package/lib/types/models.d.ts +3 -2
- package/lib/types/usage-contract.d.ts +9 -0
- package/lib/types/usage.d.ts +1 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -47,6 +47,11 @@ var import_react = require("react");
|
|
|
47
47
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
48
48
|
|
|
49
49
|
// src/models-contract.ts
|
|
50
|
+
function isModelEnabled(model, modelVisibility) {
|
|
51
|
+
if (model.configurationMissing) return false;
|
|
52
|
+
const enabled = modelVisibility && Object.hasOwn(modelVisibility, model.id) ? modelVisibility[model.id] : void 0;
|
|
53
|
+
return typeof enabled === "boolean" ? enabled : !model.deprecated;
|
|
54
|
+
}
|
|
50
55
|
function validReleaseDate(value) {
|
|
51
56
|
return typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(value)) && new Date(value).toISOString().slice(0, 10) === value;
|
|
52
57
|
}
|
|
@@ -71,15 +76,28 @@ function parseGoModels(value) {
|
|
|
71
76
|
if (typeof row[key] === "number" && Number.isSafeInteger(row[key]) && row[key] > 0) model[key] = row[key];
|
|
72
77
|
}
|
|
73
78
|
if (typeof row.deprecated === "boolean") model.deprecated = row.deprecated;
|
|
79
|
+
if (typeof row.configurationMissing === "boolean") model.configurationMissing = row.configurationMissing;
|
|
74
80
|
if (validReleaseDate(row.releaseDate)) model.releaseDate = row.releaseDate;
|
|
75
81
|
return model;
|
|
76
82
|
});
|
|
77
83
|
}
|
|
84
|
+
function parseGoModelCatalog(value) {
|
|
85
|
+
if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go model catalog");
|
|
86
|
+
const catalog = value;
|
|
87
|
+
if (typeof catalog.stale !== "boolean" || catalog.error !== void 0 && typeof catalog.error !== "string") {
|
|
88
|
+
throw new Error("Invalid OpenCode Go model catalog status");
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
models: parseGoModels(catalog.models),
|
|
92
|
+
stale: catalog.stale,
|
|
93
|
+
...catalog.error === void 0 ? {} : { error: catalog.error }
|
|
94
|
+
};
|
|
95
|
+
}
|
|
78
96
|
var codec = {
|
|
79
97
|
mode: "strict",
|
|
80
|
-
typeSymbol: "dsh-opencode-go#
|
|
81
|
-
schema: { parse:
|
|
82
|
-
create: () => ({ parse:
|
|
98
|
+
typeSymbol: "dsh-opencode-go#GoModelCatalog",
|
|
99
|
+
schema: { parse: parseGoModelCatalog },
|
|
100
|
+
create: () => ({ parse: parseGoModelCatalog })
|
|
83
101
|
};
|
|
84
102
|
var modelsRemote = {
|
|
85
103
|
package: "dsh-opencode-go",
|
|
@@ -100,17 +118,17 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
|
|
|
100
118
|
const style = document.createElement("style");
|
|
101
119
|
style.dataset.plugin = "dsh-opencode-go";
|
|
102
120
|
style.dataset.pluginCss = id;
|
|
103
|
-
style.textContent = '.BtKYva_page{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;container-type:size}.BtKYva_pageBody{scrollbar-gutter:stable;flex:1;min-height:0;padding-right:4px;overflow-y:auto}.BtKYva_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.BtKYva_field+.BtKYva_field{border-top:.5px solid var(--dsw-alias-border-l2)}.BtKYva_head{align-items:center;gap:8px;display:flex}.BtKYva_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.BtKYva_badges{align-items:center;gap:8px;display:inline-flex}.BtKYva_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.BtKYva_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BtKYva_reset:disabled{cursor:default}.BtKYva_reset:focus-visible,.BtKYva_disclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.BtKYva_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.BtKYva_input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-color:var(--dsw-alias-brand-primary)}.BtKYva_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.BtKYva_inputInvalid{border-color:var(--dsw-alias-label-error);}.BtKYva_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.BtKYva_intro{color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-size:13px;line-height:1.5}.BtKYva_disclosure{font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;margin:0;padding:0;display:flex}.BtKYva_disclosure:hover .BtKYva_label{color:var(--dsw-alias-brand-primary)}.BtKYva_chevron,.BtKYva_chevronOpen{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none}.BtKYva_chevron{transform:rotate(-90deg)}.BtKYva_advanced{flex-direction:column;gap:4px;padding:4px 0 0 22px;display:flex}.BtKYva_advanced .BtKYva_field+.BtKYva_field{border-top:none}.BtKYva_chips{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_limitsEditor{flex-direction:column;gap:10px;padding-top:4px;display:flex}.BtKYva_limitsToolbar{grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:6px 10px;display:grid}.BtKYva_limitsFilterLabel{color:var(--dsw-alias-label-secondary);grid-column:1/-1;font-size:12px;font-weight:500;line-height:1.5}.BtKYva_limitsSummary{color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-bottom:8px;font-size:12px;line-height:1.5}.BtKYva_limitsId,.BtKYva_limitsModelId{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.BtKYva_limitsId{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.4}.BtKYva_limitsModelId{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.4}.BtKYva_visuallyHidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (width<=560px){.BtKYva_limitsToolbar{grid-template-columns:1fr}.BtKYva_limitsSummary{padding-bottom:0}}.BtKYva_actions{border-top:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:12px 0;display:flex}.BtKYva_failedNote{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_pageTop{align-items:flex-start;gap:16px;display:flex}.BtKYva_pageTop .BtKYva_intro{flex:1}.BtKYva_advancedTrigger{flex-shrink:0;margin-left:auto;}.BtKYva_advancedTrigger .BtKYva_label{color:var(--dsw-alias-label-tertiary);font-size:12px}.BtKYva_filters{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_filter{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;padding:6px 9px;font-size:12px}.BtKYva_filter[aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.BtKYva_filter span{color:var(--dsw-alias-label-tertiary);margin-left:4px}.BtKYva_modelLayout{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;grid-template-columns:minmax(0,43fr) minmax(0,57fr);height:clamp(240px,100cqh - 460px,480px);display:grid;overflow:hidden}.BtKYva_modelList{border-right:.5px solid var(--dsw-alias-border-l2);min-height:0;padding:6px;overflow-y:auto}.BtKYva_modelChoice{text-align:left;width:
|
|
121
|
+
style.textContent = '.BtKYva_page{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;container-type:size}.BtKYva_pageBody{scrollbar-gutter:stable;flex:1;min-height:0;padding-right:4px;overflow-y:auto}.BtKYva_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.BtKYva_field+.BtKYva_field{border-top:.5px solid var(--dsw-alias-border-l2)}.BtKYva_head{align-items:center;gap:8px;display:flex}.BtKYva_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.BtKYva_badges{align-items:center;gap:8px;display:inline-flex}.BtKYva_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.BtKYva_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BtKYva_reset:disabled{cursor:default}.BtKYva_reset:focus-visible,.BtKYva_disclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.BtKYva_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.BtKYva_input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-color:var(--dsw-alias-brand-primary)}.BtKYva_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.BtKYva_inputInvalid{border-color:var(--dsw-alias-label-error);}.BtKYva_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.BtKYva_intro{color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-size:13px;line-height:1.5}.BtKYva_disclosure{font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;margin:0;padding:0;display:flex}.BtKYva_disclosure:hover .BtKYva_label{color:var(--dsw-alias-brand-primary)}.BtKYva_chevron,.BtKYva_chevronOpen{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none}.BtKYva_chevron{transform:rotate(-90deg)}.BtKYva_advanced{flex-direction:column;gap:4px;padding:4px 0 0 22px;display:flex}.BtKYva_advanced .BtKYva_field+.BtKYva_field{border-top:none}.BtKYva_chips{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_limitsEditor{flex-direction:column;gap:10px;padding-top:4px;display:flex}.BtKYva_limitsToolbar{grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:6px 10px;display:grid}.BtKYva_limitsFilterLabel{color:var(--dsw-alias-label-secondary);grid-column:1/-1;font-size:12px;font-weight:500;line-height:1.5}.BtKYva_limitsSummary{color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-bottom:8px;font-size:12px;line-height:1.5}.BtKYva_limitsId,.BtKYva_limitsModelId{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.BtKYva_limitsId{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.4}.BtKYva_limitsModelId{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.4}.BtKYva_visuallyHidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (width<=560px){.BtKYva_limitsToolbar{grid-template-columns:1fr}.BtKYva_limitsSummary{padding-bottom:0}}.BtKYva_actions{border-top:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:12px 0;display:flex}.BtKYva_failedNote{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_pageTop{align-items:flex-start;gap:16px;display:flex}.BtKYva_pageTop .BtKYva_intro{flex:1}.BtKYva_advancedTrigger{flex-shrink:0;margin-left:auto;}.BtKYva_advancedTrigger .BtKYva_label{color:var(--dsw-alias-label-tertiary);font-size:12px}.BtKYva_filters{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_filter{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;padding:6px 9px;font-size:12px}.BtKYva_filter[aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.BtKYva_filter span{color:var(--dsw-alias-label-tertiary);margin-left:4px}.BtKYva_modelLayout{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;grid-template-columns:minmax(0,43fr) minmax(0,57fr);height:clamp(240px,100cqh - 460px,480px);display:grid;overflow:hidden}.BtKYva_modelList{border-right:.5px solid var(--dsw-alias-border-l2);min-height:0;padding:6px;overflow-y:auto}.BtKYva_modelRow{align-items:center;gap:8px;padding-right:6px;display:flex}.BtKYva_modelRow>[role=switch]{flex-shrink:0}.BtKYva_modelChoice{text-align:left;min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:1;padding:12px 9px;display:block}.BtKYva_modelChoice[aria-pressed=true],.BtKYva_modelChoice:hover{background:var(--dsw-alias-bg-layer-3)}.BtKYva_modelName{overflow-wrap:anywhere;flex-wrap:wrap;align-items:center;gap:5px;font-size:13px;display:flex}.BtKYva_modelDetails{flex-direction:column;align-items:stretch;gap:10px;min-width:0;padding:18px;display:flex;overflow-y:auto}.BtKYva_modelDetails h3{overflow-wrap:anywhere;margin:0;font-size:16px}.BtKYva_modelHeading{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.BtKYva_modelDetails .BtKYva_field{border:0;padding:8px 0}.BtKYva_modelDetails .BtKYva_input{box-sizing:border-box;width:100%;min-width:0}.BtKYva_modelDetails .BtKYva_reset{align-self:flex-start}.BtKYva_newBadge{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:4px;padding:2px 4px;font-size:9px}.BtKYva_releaseDate{color:var(--dsw-alias-label-tertiary);margin-top:4px;font-size:10px;display:block}.BtKYva_modelChoice:focus-visible,.BtKYva_filter:focus-visible,.BtKYva_advancedTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}@container (width<=440px){.BtKYva_pageTop{flex-wrap:wrap}.BtKYva_modelLayout{grid-template-columns:minmax(0,1fr);height:auto}.BtKYva_modelList{border-right:0;border-bottom:.5px solid var(--dsw-alias-border-l2);max-height:240px}.BtKYva_modelDetails{max-height:460px}}.BtKYva_keySection{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px 0}.BtKYva_keySection summary{cursor:pointer;list-style:none}.BtKYva_keySection summary:after{content:"\u2304";color:var(--dsw-alias-label-tertiary)}.BtKYva_keySection summary::-webkit-details-marker{display:none}.BtKYva_keySection>.BtKYva_input{box-sizing:border-box;width:100%;margin:10px 0 6px}.BtKYva_keySection summary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}';
|
|
104
122
|
document.head.appendChild(style);
|
|
105
123
|
}
|
|
106
|
-
var Section_default = { "
|
|
124
|
+
var Section_default = { "limitsId": "BtKYva_limitsId", "limitsFilterLabel": "BtKYva_limitsFilterLabel", "filter": "BtKYva_filter", "limitsSummary": "BtKYva_limitsSummary", "newBadge": "BtKYva_newBadge", "modelLayout": "BtKYva_modelLayout", "limitsToolbar": "BtKYva_limitsToolbar", "limitsModelId": "BtKYva_limitsModelId", "modelChoice": "BtKYva_modelChoice", "chevron": "BtKYva_chevron", "label": "BtKYva_label", "chevronOpen": "BtKYva_chevronOpen", "chips": "BtKYva_chips", "actions": "BtKYva_actions", "modelName": "BtKYva_modelName", "pageBody": "BtKYva_pageBody", "modelRow": "BtKYva_modelRow", "invalid": "BtKYva_invalid", "advancedTrigger": "BtKYva_advancedTrigger BtKYva_disclosure", "modelHeading": "BtKYva_modelHeading", "reset": "BtKYva_reset", "field": "BtKYva_field", "badges": "BtKYva_badges", "head": "BtKYva_head", "input": "BtKYva_input", "disclosure": "BtKYva_disclosure", "intro": "BtKYva_intro", "advanced": "BtKYva_advanced", "releaseDate": "BtKYva_releaseDate", "modelList": "BtKYva_modelList", "page": "BtKYva_page", "limitsEditor": "BtKYva_limitsEditor", "keySection": "BtKYva_keySection", "pageTop": "BtKYva_pageTop", "hint": "BtKYva_hint", "failedNote": "BtKYva_failedNote", "visuallyHidden": "BtKYva_visuallyHidden", "inputInvalid": "BtKYva_inputInvalid BtKYva_input", "modelDetails": "BtKYva_modelDetails", "filters": "BtKYva_filters" };
|
|
107
125
|
|
|
108
126
|
// src/client/ModelEditor.tsx
|
|
109
127
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
110
128
|
function hasCapacityOverride(limit) {
|
|
111
129
|
return limit?.contextWindow != null || limit?.maxTokens != null;
|
|
112
130
|
}
|
|
113
|
-
function ModelEditor({ models, draft, t, disabled, onEdit }) {
|
|
131
|
+
function ModelEditor({ models, draft, modelVisibility, t, locale, disabled, visibilitySaving, onEdit, onModelEnabled }) {
|
|
114
132
|
const [query, setQuery] = (0, import_react.useState)("");
|
|
115
133
|
const [filter, setFilter] = (0, import_react.useState)("all");
|
|
116
134
|
const [selected, setSelected] = (0, import_react.useState)();
|
|
@@ -127,6 +145,7 @@ function ModelEditor({ models, draft, t, disabled, onEdit }) {
|
|
|
127
145
|
const normalized = query.trim().toLocaleLowerCase();
|
|
128
146
|
const entries = all.filter((model2) => `${model2.name ?? ""} ${model2.id}`.toLocaleLowerCase().includes(normalized) && (filter === "all" || filter === "new" && isNewModel(model2, now) || filter === "custom" && hasCapacityOverride(draft[model2.id]) || filter === "deprecated" && model2.deprecated));
|
|
129
147
|
const model = entries.find((entry) => entry.id === selected) ?? entries[0];
|
|
148
|
+
const visibilityDisabled = disabled || visibilitySaving;
|
|
130
149
|
const customized = all.filter((entry) => hasCapacityOverride(draft[entry.id])).length;
|
|
131
150
|
const filters = [
|
|
132
151
|
["all", "filterAll", all.length],
|
|
@@ -139,10 +158,12 @@ function ModelEditor({ models, draft, t, disabled, onEdit }) {
|
|
|
139
158
|
onEdit({ ...draft, [id3]: { ...current, [field]: value ?? null } });
|
|
140
159
|
};
|
|
141
160
|
const badges = (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
142
|
-
|
|
161
|
+
entry.configurationMissing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tag, { tone: "warning", children: t("configurationMissing") }) : null,
|
|
162
|
+
isNewModel(entry, now) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.newBadge, title: t("newHint"), children: t("newBadge") }) : null,
|
|
143
163
|
entry.deprecated ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tag, { tone: "warning", children: t("deprecatedBadge") }) : null
|
|
144
164
|
] });
|
|
145
165
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.limitsEditor, children: [
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("visibilityHint") }),
|
|
146
167
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: Section_default.visuallyHidden, htmlFor: "opencode-go-model-filter", children: t("limitsFilterLabel") }),
|
|
147
168
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
148
169
|
"input",
|
|
@@ -176,50 +197,64 @@ function ModelEditor({ models, draft, t, disabled, onEdit }) {
|
|
|
176
197
|
key
|
|
177
198
|
)) }),
|
|
178
199
|
model ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.modelLayout, children: [
|
|
179
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { className: Section_default.modelList, "aria-label": t("modelsLabel"), children: entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
180
|
-
|
|
181
|
-
{
|
|
182
|
-
type: "button",
|
|
183
|
-
className: Section_default.modelChoice,
|
|
184
|
-
"aria-pressed": entry.id === model.id,
|
|
185
|
-
onClick: () => {
|
|
186
|
-
setSelected(entry.id);
|
|
187
|
-
},
|
|
188
|
-
children: [
|
|
189
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: Section_default.modelName, children: [
|
|
190
|
-
entry.name ?? entry.id,
|
|
191
|
-
" ",
|
|
192
|
-
badges(entry)
|
|
193
|
-
] }),
|
|
194
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: Section_default.limitsModelId, translate: "no", children: entry.id }),
|
|
195
|
-
isNewModel(entry, now) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.releaseDate, children: t("releasedOn", { date: entry.releaseDate }) }) : null
|
|
196
|
-
]
|
|
197
|
-
},
|
|
198
|
-
entry.id
|
|
199
|
-
)) }),
|
|
200
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: Section_default.modelDetails, "aria-label": t("modelDetails"), children: [
|
|
201
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.modelHeading, children: [
|
|
202
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: model.name ?? model.id }),
|
|
203
|
-
badges(model)
|
|
204
|
-
] }),
|
|
205
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: Section_default.limitsModelId, translate: "no", children: model.id }),
|
|
206
|
-
model.deprecated ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("deprecatedHint") }) : null,
|
|
207
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Capacity, { model, field: "contextWindow", limit: draft[model.id], t, disabled, onChange: write }),
|
|
208
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Capacity, { model, field: "maxTokens", limit: draft[model.id], t, disabled, onChange: write }),
|
|
209
|
-
hasCapacityOverride(draft[model.id]) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
200
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { className: Section_default.modelList, "aria-label": t("modelsLabel"), children: entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.modelRow, children: [
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
210
202
|
"button",
|
|
211
203
|
{
|
|
212
204
|
type: "button",
|
|
213
|
-
className: Section_default.
|
|
214
|
-
|
|
205
|
+
className: Section_default.modelChoice,
|
|
206
|
+
"aria-pressed": entry.id === model.id,
|
|
215
207
|
onClick: () => {
|
|
216
|
-
|
|
208
|
+
setSelected(entry.id);
|
|
217
209
|
},
|
|
218
|
-
children:
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: Section_default.modelName, children: [
|
|
212
|
+
entry.name ?? entry.id,
|
|
213
|
+
" ",
|
|
214
|
+
badges(entry)
|
|
215
|
+
] }),
|
|
216
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: Section_default.limitsModelId, translate: "no", children: entry.id }),
|
|
217
|
+
isNewModel(entry, now) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.releaseDate, children: t("releasedOn", { date: entry.releaseDate }) }) : null
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
),
|
|
221
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
222
|
+
import_dsh_client_ui_primitives.Switch,
|
|
223
|
+
{
|
|
224
|
+
label: t("modelVisibleLabel", { name: entry.name ?? entry.id }),
|
|
225
|
+
checked: isModelEnabled(entry, modelVisibility),
|
|
226
|
+
disabled: visibilityDisabled || entry.configurationMissing,
|
|
227
|
+
onChange: (enabled) => {
|
|
228
|
+
onModelEnabled(entry.id, enabled);
|
|
229
|
+
}
|
|
219
230
|
}
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
|
|
231
|
+
)
|
|
232
|
+
] }, entry.id)) }),
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: Section_default.modelDetails, "aria-label": t("modelDetails"), children: [
|
|
234
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.modelHeading, children: [
|
|
235
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: model.name ?? model.id }),
|
|
236
|
+
badges(model)
|
|
237
|
+
] }),
|
|
238
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: Section_default.limitsModelId, translate: "no", children: model.id }),
|
|
239
|
+
model.configurationMissing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("configurationMissingHint") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
240
|
+
model.deprecated ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("deprecatedHint") }) : null,
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Capacity, { model, field: "contextWindow", limit: draft[model.id], t, locale, disabled, onChange: write }),
|
|
242
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Capacity, { model, field: "maxTokens", limit: draft[model.id], t, locale, disabled, onChange: write }),
|
|
243
|
+
hasCapacityOverride(draft[model.id]) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
244
|
+
"button",
|
|
245
|
+
{
|
|
246
|
+
type: "button",
|
|
247
|
+
className: Section_default.reset,
|
|
248
|
+
disabled,
|
|
249
|
+
onClick: () => {
|
|
250
|
+
onEdit({ ...draft, [model.id]: null });
|
|
251
|
+
},
|
|
252
|
+
children: t("limitsResetModel")
|
|
253
|
+
}
|
|
254
|
+
) : null,
|
|
255
|
+
model.releaseDate ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("releaseSource", { date: model.releaseDate }) }) : null,
|
|
256
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("limitsHint") })
|
|
257
|
+
] })
|
|
223
258
|
] })
|
|
224
259
|
] }) : models.status === "ready" && all.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("limitsNoMatches", { query }) }) : null,
|
|
225
260
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.head, children: [
|
|
@@ -239,7 +274,7 @@ function ModelEditor({ models, draft, t, disabled, onEdit }) {
|
|
|
239
274
|
] })
|
|
240
275
|
] });
|
|
241
276
|
}
|
|
242
|
-
function Capacity({ model, field, limit, disabled, t, onChange }) {
|
|
277
|
+
function Capacity({ model, field, limit, disabled, t, locale, onChange }) {
|
|
243
278
|
const id3 = `opencode-go-${field}-${encodeURIComponent(model.id)}`;
|
|
244
279
|
const defaultValue = model[field];
|
|
245
280
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.field, children: [
|
|
@@ -267,7 +302,7 @@ function Capacity({ model, field, limit, disabled, t, onChange }) {
|
|
|
267
302
|
}
|
|
268
303
|
),
|
|
269
304
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { id: `${id3}-default`, className: Section_default.hint, children: [
|
|
270
|
-
t("capacityDefault", { value: defaultValue === void 0 ? t("capacityMissing") : defaultValue.toLocaleString(
|
|
305
|
+
t("capacityDefault", { value: defaultValue === void 0 ? t("capacityMissing") : defaultValue.toLocaleString(locale) }),
|
|
271
306
|
limit?.[field] != null ? ` \xB7 ${t("overridden")}` : ""
|
|
272
307
|
] })
|
|
273
308
|
] });
|
|
@@ -320,28 +355,34 @@ function ModelsBody({ models, t }) {
|
|
|
320
355
|
if (models.status === "failed") {
|
|
321
356
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
322
357
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("modelsFailed") }),
|
|
323
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: models.message })
|
|
358
|
+
models.message ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: models.message }) : null
|
|
324
359
|
] });
|
|
325
360
|
}
|
|
326
361
|
if (models.status !== "ready") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, role: "status", "aria-live": "polite", children: t("modelsLoading") });
|
|
362
|
+
if (models.refreshing) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, role: "status", children: t("modelsRefreshing") });
|
|
363
|
+
if (models.stale) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("modelsStale") }),
|
|
365
|
+
models.message ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: models.message }) : null
|
|
366
|
+
] });
|
|
327
367
|
if (models.count === 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("modelsEmpty") });
|
|
328
368
|
return null;
|
|
329
369
|
}
|
|
330
370
|
function OpencodeGoSection(props) {
|
|
331
|
-
const { useOpencodeGo, edit, resetField, save, discard, loadModels, setEnabled,
|
|
332
|
-
if (useOpencodeGo === void 0 || edit === void 0 || resetField === void 0 || save === void 0 || discard === void 0 || loadModels === void 0 || setEnabled === void 0 ||
|
|
371
|
+
const { useOpencodeGo, edit, resetField, save, discard, loadModels, setEnabled, setModelEnabled, t } = props;
|
|
372
|
+
if (useOpencodeGo === void 0 || edit === void 0 || resetField === void 0 || save === void 0 || discard === void 0 || loadModels === void 0 || setEnabled === void 0 || setModelEnabled === void 0 || t === void 0) return null;
|
|
333
373
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
334
374
|
Loaded,
|
|
335
375
|
{
|
|
336
376
|
state: useOpencodeGo((snapshot) => snapshot),
|
|
337
377
|
t,
|
|
378
|
+
locale: props.getLocale?.(),
|
|
338
379
|
edit,
|
|
339
380
|
resetField,
|
|
340
381
|
save,
|
|
341
382
|
discard,
|
|
342
383
|
loadModels,
|
|
343
384
|
setEnabled,
|
|
344
|
-
|
|
385
|
+
setModelEnabled
|
|
345
386
|
}
|
|
346
387
|
);
|
|
347
388
|
}
|
|
@@ -512,7 +553,7 @@ function Loaded(props) {
|
|
|
512
553
|
{
|
|
513
554
|
checked: state.enabled,
|
|
514
555
|
label: t("enabledLabel"),
|
|
515
|
-
disabled,
|
|
556
|
+
disabled: disabled || state.saving || state.pickerSaving,
|
|
516
557
|
onChange: props.setEnabled
|
|
517
558
|
}
|
|
518
559
|
)
|
|
@@ -553,7 +594,7 @@ function Loaded(props) {
|
|
|
553
594
|
{
|
|
554
595
|
type: "button",
|
|
555
596
|
className: Section_default.reset,
|
|
556
|
-
disabled: state.models.status === "loading",
|
|
597
|
+
disabled: state.models.status === "loading" || state.models.status === "ready" && state.models.refreshing,
|
|
557
598
|
onClick: loadModels,
|
|
558
599
|
children: t("modelsRefresh")
|
|
559
600
|
}
|
|
@@ -563,19 +604,6 @@ function Loaded(props) {
|
|
|
563
604
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ModelsBody, { models: state.models, t })
|
|
564
605
|
] }),
|
|
565
606
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
|
|
566
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
|
|
567
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("showDeprecatedLabel") }),
|
|
568
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
569
|
-
import_dsh_client_ui_primitives2.Switch,
|
|
570
|
-
{
|
|
571
|
-
checked: state.showDeprecatedModels,
|
|
572
|
-
label: t("showDeprecatedLabel"),
|
|
573
|
-
disabled: disabled || state.pickerSaving,
|
|
574
|
-
onChange: props.setShowDeprecatedModels
|
|
575
|
-
}
|
|
576
|
-
)
|
|
577
|
-
] }),
|
|
578
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("showDeprecatedHint") }),
|
|
579
607
|
state.pickerFailed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("pickerFailed") }) : null,
|
|
580
608
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
581
609
|
ModelEditor,
|
|
@@ -583,7 +611,11 @@ function Loaded(props) {
|
|
|
583
611
|
models: state.models,
|
|
584
612
|
draft: state.modelLimitDraft,
|
|
585
613
|
t,
|
|
614
|
+
locale: props.locale,
|
|
586
615
|
disabled: disabled || state.saving,
|
|
616
|
+
modelVisibility: state.modelVisibility,
|
|
617
|
+
visibilitySaving: state.pickerSaving,
|
|
618
|
+
onModelEnabled: props.setModelEnabled,
|
|
587
619
|
onEdit: (next) => {
|
|
588
620
|
props.edit("modelLimits", JSON.stringify(next));
|
|
589
621
|
}
|
|
@@ -593,7 +625,7 @@ function Loaded(props) {
|
|
|
593
625
|
disabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("readOnly") }) : null
|
|
594
626
|
] }),
|
|
595
627
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.actions, children: [
|
|
596
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", size: "md", disabled: disabled || !state.dirty || state.invalid || state.saving, onClick: props.save, children: state.saving ? t("saving") : t("save") }),
|
|
628
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", size: "md", disabled: disabled || !state.dirty || state.invalid || state.saving || state.pickerSaving, onClick: props.save, children: state.saving ? t("saving") : t("save") }),
|
|
597
629
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "md", disabled: disabled || !state.dirty || state.saving, onClick: props.discard, children: t("discard") }),
|
|
598
630
|
state.failed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, children: t("savedFailed") }) : null
|
|
599
631
|
] })
|
|
@@ -863,7 +895,10 @@ var OpencodeGoSectionController = class {
|
|
|
863
895
|
* @param ctx - the page plugin's context, whose `remote.credentials` namespace
|
|
864
896
|
* answers for the credential the section references.
|
|
865
897
|
*/
|
|
866
|
-
constructor(scope, ctx, readModels = () =>
|
|
898
|
+
constructor(scope, ctx, readModels = async () => {
|
|
899
|
+
const result = await ctx.remote.llm.discoverModels(OPENCODE_GO_NS, { provider: OPENCODE_GO_PROVIDER });
|
|
900
|
+
return result.ok ? { ok: true, value: { models: result.value, stale: false } } : result;
|
|
901
|
+
}) {
|
|
867
902
|
this.scope = scope;
|
|
868
903
|
this.ctx = ctx;
|
|
869
904
|
this.readModels = readModels;
|
|
@@ -885,7 +920,15 @@ var OpencodeGoSectionController = class {
|
|
|
885
920
|
[{ field: API_KEY_FIELD, write: (text) => this.writeKey(text) }]
|
|
886
921
|
);
|
|
887
922
|
this.store = this.form.bind(() => this.projection());
|
|
923
|
+
let modelsEndpoint = scope.getSnapshot().value?.baseURL;
|
|
888
924
|
this.unsubscribe = scope.subscribe(() => {
|
|
925
|
+
const endpoint = scope.getSnapshot().value?.baseURL;
|
|
926
|
+
if (endpoint !== modelsEndpoint) {
|
|
927
|
+
modelsEndpoint = endpoint;
|
|
928
|
+
this.modelsRequest++;
|
|
929
|
+
this.models = { status: "idle" };
|
|
930
|
+
this.store.set(this.projection());
|
|
931
|
+
}
|
|
889
932
|
void this.readCredential();
|
|
890
933
|
});
|
|
891
934
|
void this.readCredential();
|
|
@@ -909,7 +952,7 @@ var OpencodeGoSectionController = class {
|
|
|
909
952
|
return {
|
|
910
953
|
...this.form.shell(),
|
|
911
954
|
enabled: this.enabled(),
|
|
912
|
-
|
|
955
|
+
modelVisibility: this.scope.getSnapshot().value?.modelVisibility ?? {},
|
|
913
956
|
pickerSaving: this.pickerSaving,
|
|
914
957
|
pickerFailed: this.pickerFailed,
|
|
915
958
|
apiKeyEnv: this.form.field("apiKeyEnv"),
|
|
@@ -955,7 +998,7 @@ var OpencodeGoSectionController = class {
|
|
|
955
998
|
/**
|
|
956
999
|
* Flip the switch by writing the field on the click itself.
|
|
957
1000
|
*
|
|
958
|
-
*
|
|
1001
|
+
* Like the per-model switches, this control does not wait for Save: the point
|
|
959
1002
|
* of turning it off is to watch the models leave the pickers, and the point
|
|
960
1003
|
* of turning it back on is to use the route again — staging either behind a
|
|
961
1004
|
* second gesture would report a state the Host does not hold. The write is
|
|
@@ -963,18 +1006,27 @@ var OpencodeGoSectionController = class {
|
|
|
963
1006
|
* failed save through the shared shell rather than a silent revert.
|
|
964
1007
|
* @param next - the state the switch asks for.
|
|
965
1008
|
*/
|
|
966
|
-
setEnabled(next) {
|
|
967
|
-
|
|
1009
|
+
async setEnabled(next) {
|
|
1010
|
+
await this.writePickerSetting("enabled", next, () => this.enabled() === next);
|
|
968
1011
|
}
|
|
969
|
-
/**
|
|
970
|
-
async
|
|
971
|
-
if (this.
|
|
1012
|
+
/** Each model switch has one committed value and takes effect without Save. */
|
|
1013
|
+
async setModelEnabled(id3, next) {
|
|
1014
|
+
if (this.models.status === "ready" && this.models.entries.some((model) => model.id === id3 && model.configurationMissing)) return;
|
|
1015
|
+
await this.writePickerSetting(
|
|
1016
|
+
"modelVisibility",
|
|
1017
|
+
{ ...this.scope.getSnapshot().value?.modelVisibility, [id3]: next },
|
|
1018
|
+
() => this.scope.getSnapshot().value?.modelVisibility?.[id3] === next
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
/** Serialize immediate switches with form saves; refused writes retain committed values. */
|
|
1022
|
+
async writePickerSetting(field, value, accepted) {
|
|
1023
|
+
if (this.pickerSaving || this.form.shell().saving || !this.scope.getSnapshot().writable) return;
|
|
972
1024
|
this.pickerSaving = true;
|
|
973
1025
|
this.pickerFailed = false;
|
|
974
1026
|
this.store.set(this.projection());
|
|
975
1027
|
try {
|
|
976
|
-
await this.scope.set(
|
|
977
|
-
this.pickerFailed = (
|
|
1028
|
+
await this.scope.set(field, value);
|
|
1029
|
+
this.pickerFailed = !accepted();
|
|
978
1030
|
} catch {
|
|
979
1031
|
this.pickerFailed = true;
|
|
980
1032
|
} finally {
|
|
@@ -991,20 +1043,31 @@ var OpencodeGoSectionController = class {
|
|
|
991
1043
|
*/
|
|
992
1044
|
loadModels() {
|
|
993
1045
|
const request = ++this.modelsRequest;
|
|
994
|
-
this.models
|
|
1046
|
+
const previous = this.models.status === "ready" ? this.models : void 0;
|
|
1047
|
+
this.models = previous ? { ...previous, refreshing: true } : { status: "loading" };
|
|
995
1048
|
this.store.set(this.projection());
|
|
1049
|
+
const failed = (message) => {
|
|
1050
|
+
this.models = previous ? { ...previous, refreshing: false, stale: true, message } : { status: "failed", message };
|
|
1051
|
+
};
|
|
996
1052
|
void this.readModels().then((response) => {
|
|
997
1053
|
if (request !== this.modelsRequest) return;
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1054
|
+
if (!response.ok) failed(response.error.message);
|
|
1055
|
+
else if (response.value.stale && response.value.models.length === 0) {
|
|
1056
|
+
this.models = { status: "failed", ...response.value.error ? { message: response.value.error } : {} };
|
|
1057
|
+
} else {
|
|
1058
|
+
this.models = {
|
|
1059
|
+
status: "ready",
|
|
1060
|
+
count: response.value.models.length,
|
|
1061
|
+
preview: response.value.models.map((model) => model.name ?? model.id),
|
|
1062
|
+
entries: response.value.models,
|
|
1063
|
+
stale: response.value.stale,
|
|
1064
|
+
...response.value.error ? { message: response.value.error } : {}
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1004
1067
|
this.store.set(this.projection());
|
|
1005
1068
|
}).catch((error) => {
|
|
1006
1069
|
if (request !== this.modelsRequest) return;
|
|
1007
|
-
|
|
1070
|
+
failed(error instanceof Error ? error.message : String(error));
|
|
1008
1071
|
this.store.set(this.projection());
|
|
1009
1072
|
});
|
|
1010
1073
|
}
|
|
@@ -1060,10 +1123,10 @@ var OpencodeGoSectionController = class {
|
|
|
1060
1123
|
this.loadModels();
|
|
1061
1124
|
},
|
|
1062
1125
|
setEnabled: (next) => {
|
|
1063
|
-
this.setEnabled(next);
|
|
1126
|
+
void this.setEnabled(next);
|
|
1064
1127
|
},
|
|
1065
|
-
|
|
1066
|
-
void this.
|
|
1128
|
+
setModelEnabled: (id3, next) => {
|
|
1129
|
+
void this.setModelEnabled(id3, next);
|
|
1067
1130
|
},
|
|
1068
1131
|
...this.form.actions()
|
|
1069
1132
|
};
|
|
@@ -1111,6 +1174,7 @@ function refOf(snapshot) {
|
|
|
1111
1174
|
// src/client/locales.ts
|
|
1112
1175
|
var en = {
|
|
1113
1176
|
usageTitle: "OpenCode Go usage",
|
|
1177
|
+
usageRollingShort: "5h",
|
|
1114
1178
|
usageHint: "Account usage \xB7 used percentage \xB7 refreshes every minute",
|
|
1115
1179
|
usageWeekShort: "week",
|
|
1116
1180
|
usage_rolling: "5 hours",
|
|
@@ -1120,9 +1184,15 @@ var en = {
|
|
|
1120
1184
|
usageLimited: "Limit reached",
|
|
1121
1185
|
usageLoading: "Loading usage\u2026",
|
|
1122
1186
|
usageUnavailable: "Unavailable",
|
|
1187
|
+
usageStaleShort: "Last data",
|
|
1188
|
+
usageStaleHint: "Showing the last successful usage reading. Current usage may have changed.",
|
|
1189
|
+
usageRefreshFailed: "Refresh failed",
|
|
1190
|
+
usageLastUpdated: "Last updated",
|
|
1191
|
+
usageRetry: "Retry now",
|
|
1192
|
+
usageRefreshing: "Refreshing\u2026",
|
|
1123
1193
|
nav: "OpenCode Go",
|
|
1124
1194
|
title: "OpenCode Go",
|
|
1125
|
-
intro: "
|
|
1195
|
+
intro: "Choose the OpenCode Go models shown in conversations and adjust their capacities.",
|
|
1126
1196
|
enabledLabel: "Enable OpenCode Go",
|
|
1127
1197
|
enabledHint: "While this is on, OpenCode Go appears in every model picker and can serve requests. Turning it off withdraws the provider and its models immediately; this page stays reachable so you can turn it back on.",
|
|
1128
1198
|
enabledOff: "OpenCode Go is off. Its models are withdrawn from every picker and no request reaches the gateway. Turn the switch back on to use it again.",
|
|
@@ -1136,6 +1206,8 @@ var en = {
|
|
|
1136
1206
|
modelsRefresh: "Refresh",
|
|
1137
1207
|
modelsLoading: "Reading the gateway model list\u2026",
|
|
1138
1208
|
modelsFailed: "Could not read the gateway model list.",
|
|
1209
|
+
modelsStale: "Refresh failed. Showing the last fetched models, also used by conversation pickers. Their current availability could not be confirmed.",
|
|
1210
|
+
modelsRefreshing: "Refreshing\u2026 Keeping the last fetched models visible.",
|
|
1139
1211
|
modelsEmpty: "The gateway currently serves no model this adapter can route.",
|
|
1140
1212
|
modelsCount: "{count} models",
|
|
1141
1213
|
limitsLabel: "Model capacities",
|
|
@@ -1148,12 +1220,15 @@ var en = {
|
|
|
1148
1220
|
limitsOutput: "Max output",
|
|
1149
1221
|
capacityDefault: "Default: {value} tokens",
|
|
1150
1222
|
capacityMissing: "API did not provide a value",
|
|
1151
|
-
|
|
1152
|
-
|
|
1223
|
+
visibilityHint: "Only enabled models appear in conversation pickers. Changes apply immediately. Deprecated models are off by default and can be enabled individually.",
|
|
1224
|
+
modelVisibleLabel: "Show {name} in conversations",
|
|
1225
|
+
configurationMissing: "Configuration missing",
|
|
1226
|
+
configurationMissingHint: "The gateway lists this model, but its OpenCode Go configuration is missing. It cannot be enabled.",
|
|
1153
1227
|
pickerFailed: "Could not update model visibility. Please retry.",
|
|
1154
1228
|
deprecatedBadge: "Deprecated",
|
|
1155
1229
|
deprecatedHint: "Marked deprecated by models.dev, but still provided by this gateway.",
|
|
1156
1230
|
newHint: "Released within the last seven UTC calendar days, according to models.dev.",
|
|
1231
|
+
newBadge: "NEW",
|
|
1157
1232
|
releasedOn: "Released {date}",
|
|
1158
1233
|
releaseSource: "Release date: {date} \xB7 models.dev",
|
|
1159
1234
|
modelDetails: "Model configuration",
|
|
@@ -1175,7 +1250,7 @@ var en = {
|
|
|
1175
1250
|
baseURLLabel: "Gateway URL",
|
|
1176
1251
|
baseURLHint: "The endpoint that serves requests and the live model list.",
|
|
1177
1252
|
refreshMinutesLabel: "Catalog refresh (minutes)",
|
|
1178
|
-
refreshMinutesHint: "
|
|
1253
|
+
refreshMinutesHint: "Catalog cache lifetime for conversations and model pickers. Opening this settings page or clicking Refresh checks the gateway and online model metadata immediately.",
|
|
1179
1254
|
streamIdleTimeoutMsLabel: "Stream idle timeout (ms)",
|
|
1180
1255
|
streamIdleTimeoutMsHint: "Largest quiet gap between stream events before the request fails.",
|
|
1181
1256
|
maxRequestImageBytesLabel: "Request image payload cap (bytes)",
|
|
@@ -1196,6 +1271,7 @@ var en = {
|
|
|
1196
1271
|
};
|
|
1197
1272
|
var zh = {
|
|
1198
1273
|
usageTitle: "OpenCode Go \u7528\u91CF",
|
|
1274
|
+
usageRollingShort: "5\u5C0F\u65F6",
|
|
1199
1275
|
usageHint: "\u8D26\u53F7\u989D\u5EA6 \xB7 \u5DF2\u7528\u767E\u5206\u6BD4 \xB7 \u6BCF\u5206\u949F\u5237\u65B0",
|
|
1200
1276
|
usageWeekShort: "\u5468",
|
|
1201
1277
|
usage_rolling: "5 \u5C0F\u65F6",
|
|
@@ -1205,9 +1281,15 @@ var zh = {
|
|
|
1205
1281
|
usageLimited: "\u5DF2\u8FBE\u9650\u989D",
|
|
1206
1282
|
usageLoading: "\u6B63\u5728\u8BFB\u53D6\u7528\u91CF\u2026",
|
|
1207
1283
|
usageUnavailable: "\u6682\u4E0D\u53EF\u7528",
|
|
1284
|
+
usageStaleShort: "\u4E0A\u6B21\u6570\u636E",
|
|
1285
|
+
usageStaleHint: "\u5F53\u524D\u663E\u793A\u4E0A\u6B21\u6210\u529F\u8BFB\u53D6\u7684\u7528\u91CF\uFF0C\u5B9E\u9645\u7528\u91CF\u53EF\u80FD\u5DF2\u53D8\u5316\u3002",
|
|
1286
|
+
usageRefreshFailed: "\u5237\u65B0\u5931\u8D25",
|
|
1287
|
+
usageLastUpdated: "\u66F4\u65B0\u4E8E",
|
|
1288
|
+
usageRetry: "\u7ACB\u5373\u91CD\u8BD5",
|
|
1289
|
+
usageRefreshing: "\u6B63\u5728\u5237\u65B0\u2026",
|
|
1208
1290
|
nav: "OpenCode Go",
|
|
1209
1291
|
title: "OpenCode Go",
|
|
1210
|
-
intro: "\
|
|
1292
|
+
intro: "\u9009\u62E9\u4F1A\u8BDD\u4E2D\u663E\u793A\u7684 OpenCode Go \u6A21\u578B\uFF0C\u5E76\u8C03\u6574\u5176\u5BB9\u91CF\u3002",
|
|
1211
1293
|
enabledLabel: "\u542F\u7528 OpenCode Go",
|
|
1212
1294
|
enabledHint: "\u5F00\u542F\u65F6\uFF0COpenCode Go \u4F1A\u51FA\u73B0\u5728\u6240\u6709\u6A21\u578B\u9009\u62E9\u5668\u4E2D\u5E76\u53EF\u5904\u7406\u8BF7\u6C42\u3002\u5173\u95ED\u540E\u5C06\u7ACB\u5373\u64A4\u4E0B\u8BE5\u63D0\u4F9B\u65B9\u53CA\u5176\u6A21\u578B\uFF1B\u672C\u9875\u4ECD\u53EF\u8BBF\u95EE\uFF0C\u65B9\u4FBF\u4F60\u968F\u65F6\u91CD\u65B0\u5F00\u542F\u3002",
|
|
1213
1295
|
enabledOff: "OpenCode Go \u5DF2\u5173\u95ED\u3002\u5176\u6A21\u578B\u5DF2\u4ECE\u6240\u6709\u9009\u62E9\u5668\u4E2D\u64A4\u4E0B\uFF0C\u4E5F\u4E0D\u4F1A\u6709\u8BF7\u6C42\u53D1\u5F80\u7F51\u5173\u3002\u9700\u8981\u65F6\u628A\u5F00\u5173\u91CD\u65B0\u6253\u5F00\u5373\u53EF\u3002",
|
|
@@ -1221,6 +1303,8 @@ var zh = {
|
|
|
1221
1303
|
modelsRefresh: "\u5237\u65B0",
|
|
1222
1304
|
modelsLoading: "\u6B63\u5728\u8BFB\u53D6\u7F51\u5173\u6A21\u578B\u5217\u8868\u2026",
|
|
1223
1305
|
modelsFailed: "\u672A\u80FD\u8BFB\u53D6\u7F51\u5173\u6A21\u578B\u5217\u8868\u3002",
|
|
1306
|
+
modelsStale: "\u5237\u65B0\u5931\u8D25\uFF0C\u6B63\u5728\u663E\u793A\u4E0A\u6B21\u83B7\u53D6\u7684\u6A21\u578B\uFF1B\u4F1A\u8BDD\u9009\u62E9\u5668\u4E5F\u4F7F\u7528\u8FD9\u4EFD\u7F13\u5B58\uFF0C\u5F53\u524D\u53EF\u7528\u6027\u5C1A\u672A\u786E\u8BA4\u3002",
|
|
1307
|
+
modelsRefreshing: "\u6B63\u5728\u5237\u65B0\uFF0C\u6682\u65F6\u4FDD\u7559\u4E0A\u6B21\u83B7\u53D6\u7684\u6A21\u578B\u3002",
|
|
1224
1308
|
modelsEmpty: "\u7F51\u5173\u5F53\u524D\u6CA1\u6709\u672C\u9002\u914D\u5668\u53EF\u8DEF\u7531\u7684\u6A21\u578B\u3002",
|
|
1225
1309
|
modelsCount: "{count} \u4E2A\u6A21\u578B",
|
|
1226
1310
|
limitsLabel: "\u6A21\u578B\u5BB9\u91CF",
|
|
@@ -1233,12 +1317,15 @@ var zh = {
|
|
|
1233
1317
|
limitsOutput: "\u6700\u5927\u8F93\u51FA",
|
|
1234
1318
|
capacityDefault: "\u9ED8\u8BA4\uFF1A{value} tokens",
|
|
1235
1319
|
capacityMissing: "API \u672A\u63D0\u4F9B",
|
|
1236
|
-
|
|
1237
|
-
|
|
1320
|
+
visibilityHint: "\u5F00\u542F\u7684\u6A21\u578B\u624D\u4F1A\u663E\u793A\u5728\u4F1A\u8BDD\u9009\u62E9\u5668\u4E2D\uFF0C\u4FEE\u6539\u7ACB\u5373\u751F\u6548\u3002\u8FC7\u65F6\u6A21\u578B\u9ED8\u8BA4\u5173\u95ED\uFF0C\u53EF\u5355\u72EC\u5F00\u542F\u3002",
|
|
1321
|
+
modelVisibleLabel: "\u5728\u4F1A\u8BDD\u4E2D\u663E\u793A {name}",
|
|
1322
|
+
configurationMissing: "\u914D\u7F6E\u7F3A\u5931",
|
|
1323
|
+
configurationMissingHint: "\u7F51\u5173\u5DF2\u5217\u51FA\u6B64\u6A21\u578B\uFF0C\u4F46\u7F3A\u5C11\u5BF9\u5E94\u7684 OpenCode Go \u914D\u7F6E\uFF0C\u6682\u4E0D\u53EF\u5F00\u542F\u3002",
|
|
1238
1324
|
pickerFailed: "\u6A21\u578B\u663E\u793A\u8BBE\u7F6E\u672A\u66F4\u65B0\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
1239
1325
|
deprecatedBadge: "\u5DF2\u5F03\u7528",
|
|
1240
1326
|
deprecatedHint: "models.dev \u6807\u8BB0\u4E3A\u5DF2\u5F03\u7528\uFF0C\u5F53\u524D\u7F51\u5173\u4ECD\u63D0\u4F9B\u6B64\u6A21\u578B\u3002",
|
|
1241
1327
|
newHint: "\u4F9D\u636E models.dev \u53D1\u5E03\u65E5\u671F\uFF0C\u8FD1\u4E03\u4E2A UTC \u65E5\u5386\u65E5\u5185\u53D1\u5E03\u3002",
|
|
1328
|
+
newBadge: "\u65B0",
|
|
1242
1329
|
releasedOn: "{date} \u53D1\u5E03",
|
|
1243
1330
|
releaseSource: "\u53D1\u5E03\u65E5\u671F\uFF1A{date} \xB7 models.dev",
|
|
1244
1331
|
modelDetails: "\u6A21\u578B\u914D\u7F6E",
|
|
@@ -1260,7 +1347,7 @@ var zh = {
|
|
|
1260
1347
|
baseURLLabel: "\u7F51\u5173\u5730\u5740",
|
|
1261
1348
|
baseURLHint: "\u540C\u65F6\u63D0\u4F9B\u6A21\u578B\u8BF7\u6C42\u4E0E\u5B9E\u65F6\u6A21\u578B\u5217\u8868\u7684\u7AEF\u70B9\u3002",
|
|
1262
1349
|
refreshMinutesLabel: "\u76EE\u5F55\u5237\u65B0\uFF08\u5206\u949F\uFF09",
|
|
1263
|
-
refreshMinutesHint: "\
|
|
1350
|
+
refreshMinutesHint: "\u4F1A\u8BDD\u8BF7\u6C42\u548C\u6A21\u578B\u9009\u62E9\u5668\u7684\u76EE\u5F55\u7F13\u5B58\u65F6\u957F\u3002\u6253\u5F00\u672C\u8BBE\u7F6E\u9875\u6216\u70B9\u51FB\u5237\u65B0\u65F6\uFF0C\u4F1A\u7ACB\u5373\u6838\u5BF9\u7F51\u5173\u4E0E\u5728\u7EBF\u6A21\u578B\u914D\u7F6E\u3002",
|
|
1264
1351
|
streamIdleTimeoutMsLabel: "\u6D41\u7A7A\u95F2\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",
|
|
1265
1352
|
streamIdleTimeoutMsHint: "\u6D41\u4E8B\u4EF6\u95F4\u5141\u8BB8\u7684\u6700\u5927\u9759\u9ED8\u95F4\u9694\uFF0C\u8D85\u51FA\u540E\u8BF7\u6C42\u5931\u8D25\u3002",
|
|
1266
1353
|
maxRequestImageBytesLabel: "\u8BF7\u6C42\u56FE\u7247\u8F7D\u8377\u4E0A\u9650\uFF08\u5B57\u8282\uFF09",
|
|
@@ -1285,6 +1372,12 @@ function parseGoUsage(value) {
|
|
|
1285
1372
|
if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go usage response");
|
|
1286
1373
|
const source = value;
|
|
1287
1374
|
const result = {};
|
|
1375
|
+
if (source.source !== void 0) {
|
|
1376
|
+
if (typeof source.source !== "string" || source.source.length === 0 || source.source.length > 128) {
|
|
1377
|
+
throw new Error("Invalid OpenCode Go usage source");
|
|
1378
|
+
}
|
|
1379
|
+
result.source = source.source;
|
|
1380
|
+
}
|
|
1288
1381
|
for (const key of ["rolling", "weekly", "monthly"]) {
|
|
1289
1382
|
const row = source[key];
|
|
1290
1383
|
if (!row || row.status !== "ok" && row.status !== "rate-limited" || typeof row.percent !== "number" || !Number.isFinite(row.percent) || row.percent < 0 || typeof row.resetsAt !== "string" || !Number.isFinite(Date.parse(row.resetsAt))) {
|
|
@@ -1328,43 +1421,66 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
|
|
|
1328
1421
|
const style = document.createElement("style");
|
|
1329
1422
|
style.dataset.plugin = "dsh-opencode-go";
|
|
1330
1423
|
style.dataset.pluginCss = id2;
|
|
1331
|
-
style.textContent = ".dmPm3q_root{min-width:0;display:inline-flex;position:relative}.dmPm3q_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.dmPm3q_trigger:hover,.dmPm3q_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.dmPm3q_panel{z-index:100;border:1px solid color-mix(in srgb, currentColor 18%, transparent);width:280px;max-width:calc(100vw - 32px);color:var(--dsw-alias-label-primary,CanvasText);background:var(--dsw-specific-menu,Canvas);border-radius:12px;padding:16px;font-size:12px;position:absolute;bottom:calc(100% + 12px);right:0;box-shadow:0 8px 30px #0002}.dmPm3q_hint{opacity:.65;font-size:11px;line-height:1.6}.dmPm3q_window{margin-top:14px}.dmPm3q_row{justify-content:space-between;margin-bottom:5px;display:flex}.dmPm3q_window progress{accent-color:#39a878;width:100%;height:5px;margin-bottom:5px;display:block}.dmPm3q_window progress::-webkit-progress-bar{background:color-mix(in srgb, currentColor 15%, transparent);border-radius:4px}.dmPm3q_window progress::-webkit-progress-value{background:#39a878;border-radius:4px}.dmPm3q_window progress::-moz-progress-bar{background:#39a878;border-radius:4px}";
|
|
1424
|
+
style.textContent = ".dmPm3q_root{min-width:0;display:inline-flex;position:relative}.dmPm3q_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.dmPm3q_trigger:hover,.dmPm3q_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.dmPm3q_panel{z-index:100;box-sizing:border-box;border:1px solid color-mix(in srgb, currentColor 18%, transparent);width:280px;max-width:calc(100vw - 32px);max-height:70vh;color:var(--dsw-alias-label-primary,CanvasText);background:var(--dsw-specific-menu,Canvas);border-radius:12px;padding:16px;font-size:12px;position:absolute;bottom:calc(100% + 12px);right:0;overflow-y:auto;box-shadow:0 8px 30px #0002}.dmPm3q_hint{opacity:.65;font-size:11px;line-height:1.6}.dmPm3q_warning{background:color-mix(in srgb, currentColor 6%, transparent);overflow-wrap:anywhere;border-radius:6px;margin:10px 0;padding:10px;line-height:1.5}.dmPm3q_warning p{margin:5px 0 0}.dmPm3q_retry{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:5px 9px}.dmPm3q_retry:disabled{opacity:.6;cursor:default}.dmPm3q_retry:focus-visible{outline-offset:2px;outline:2px solid}.dmPm3q_window{margin-top:14px}.dmPm3q_row{justify-content:space-between;margin-bottom:5px;display:flex}.dmPm3q_window progress{accent-color:#39a878;width:100%;height:5px;margin-bottom:5px;display:block}.dmPm3q_window progress::-webkit-progress-bar{background:color-mix(in srgb, currentColor 15%, transparent);border-radius:4px}.dmPm3q_window progress::-webkit-progress-value{background:#39a878;border-radius:4px}.dmPm3q_window progress::-moz-progress-bar{background:#39a878;border-radius:4px}";
|
|
1332
1425
|
document.head.appendChild(style);
|
|
1333
1426
|
}
|
|
1334
|
-
var UsagePill_default = { "
|
|
1427
|
+
var UsagePill_default = { "panel": "dmPm3q_panel", "row": "dmPm3q_row", "root": "dmPm3q_root", "window": "dmPm3q_window", "trigger": "dmPm3q_trigger", "retry": "dmPm3q_retry", "warning": "dmPm3q_warning", "hint": "dmPm3q_hint" };
|
|
1335
1428
|
|
|
1336
1429
|
// src/client/UsagePill.tsx
|
|
1337
1430
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1431
|
+
function usageFailure(error) {
|
|
1432
|
+
if (error && typeof error === "object" && "code" in error && error.code === "opencode-go/usage-unavailable" && "details" in error && error.details && typeof error.details === "object") {
|
|
1433
|
+
const details = error.details;
|
|
1434
|
+
return {
|
|
1435
|
+
..."message" in error && typeof error.message === "string" ? { message: error.message } : {},
|
|
1436
|
+
retainPrevious: details.retryable === true && details.retainPrevious === true,
|
|
1437
|
+
...typeof details.source === "string" ? { source: details.source } : {}
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
return { retainPrevious: false };
|
|
1441
|
+
}
|
|
1338
1442
|
function UsagePill({ directory, ...props }) {
|
|
1339
1443
|
const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
|
|
1340
1444
|
return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActiveUsage, { ...props }) : null;
|
|
1341
1445
|
}
|
|
1342
|
-
function ActiveUsage({ readUsage, t }) {
|
|
1343
|
-
const [
|
|
1344
|
-
const [failed, setFailed] = (0, import_react3.useState)(
|
|
1446
|
+
function ActiveUsage({ readUsage, t, getLocale }) {
|
|
1447
|
+
const [snapshot, setSnapshot] = (0, import_react3.useState)(null);
|
|
1448
|
+
const [failed, setFailed] = (0, import_react3.useState)(null);
|
|
1449
|
+
const [refreshing, setRefreshing] = (0, import_react3.useState)(false);
|
|
1345
1450
|
const [open, setOpen] = (0, import_react3.useState)(false);
|
|
1346
1451
|
const root = (0, import_react3.useRef)(null);
|
|
1452
|
+
const retry = (0, import_react3.useRef)(() => {
|
|
1453
|
+
});
|
|
1347
1454
|
(0, import_react3.useEffect)(() => {
|
|
1348
1455
|
let alive = true;
|
|
1349
1456
|
let busy = false;
|
|
1350
|
-
|
|
1351
|
-
|
|
1457
|
+
setSnapshot(null);
|
|
1458
|
+
setFailed(null);
|
|
1459
|
+
setRefreshing(false);
|
|
1460
|
+
const refresh = async (manual = false) => {
|
|
1461
|
+
if (busy || !manual && document.visibilityState === "hidden") return;
|
|
1352
1462
|
busy = true;
|
|
1463
|
+
setRefreshing(true);
|
|
1353
1464
|
try {
|
|
1354
1465
|
const value = await readUsage();
|
|
1355
1466
|
if (alive) {
|
|
1356
|
-
|
|
1357
|
-
setFailed(
|
|
1467
|
+
setSnapshot({ reader: readUsage, usage: value, updatedAt: Date.now() });
|
|
1468
|
+
setFailed(null);
|
|
1358
1469
|
}
|
|
1359
|
-
} catch {
|
|
1470
|
+
} catch (error) {
|
|
1360
1471
|
if (alive) {
|
|
1361
|
-
|
|
1362
|
-
setFailed(
|
|
1472
|
+
const failure2 = usageFailure(error);
|
|
1473
|
+
setFailed({ reader: readUsage, failure: failure2 });
|
|
1474
|
+
setSnapshot((previous) => previous?.reader === readUsage && failure2.retainPrevious && typeof previous.usage.source === "string" && previous.usage.source.length > 0 && previous.usage.source === failure2.source ? previous : null);
|
|
1363
1475
|
}
|
|
1364
1476
|
} finally {
|
|
1365
1477
|
busy = false;
|
|
1478
|
+
if (alive) setRefreshing(false);
|
|
1366
1479
|
}
|
|
1367
1480
|
};
|
|
1481
|
+
retry.current = () => {
|
|
1482
|
+
void refresh(true);
|
|
1483
|
+
};
|
|
1368
1484
|
void refresh();
|
|
1369
1485
|
const timer = setInterval(() => {
|
|
1370
1486
|
void refresh();
|
|
@@ -1375,6 +1491,8 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
1375
1491
|
document.addEventListener("visibilitychange", visible);
|
|
1376
1492
|
return () => {
|
|
1377
1493
|
alive = false;
|
|
1494
|
+
retry.current = () => {
|
|
1495
|
+
};
|
|
1378
1496
|
clearInterval(timer);
|
|
1379
1497
|
document.removeEventListener("visibilitychange", visible);
|
|
1380
1498
|
};
|
|
@@ -1394,7 +1512,10 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
1394
1512
|
document.removeEventListener("keydown", key);
|
|
1395
1513
|
};
|
|
1396
1514
|
}, [open]);
|
|
1397
|
-
const
|
|
1515
|
+
const current = snapshot?.reader === readUsage ? snapshot : null;
|
|
1516
|
+
const usage = current?.usage;
|
|
1517
|
+
const failure = failed?.reader === readUsage ? failed.failure : null;
|
|
1518
|
+
const label = usage ? `Go \xB7 ${t("usageRollingShort")} ${usage.rolling.percent}% \xB7 ${t("usageWeekShort")} ${usage.weekly.percent}%${failure ? ` \xB7 ${t("usageStaleShort")}` : ""}` : `Go \xB7 ${failure ? t("usageUnavailable") : "\u2026"}`;
|
|
1398
1519
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
|
|
1399
1520
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1400
1521
|
"button",
|
|
@@ -1410,9 +1531,31 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
1410
1531
|
children: label
|
|
1411
1532
|
}
|
|
1412
1533
|
),
|
|
1413
|
-
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), children: [
|
|
1534
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
|
|
1414
1535
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageTitle") }),
|
|
1415
1536
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: UsagePill_default.hint, children: t("usageHint") }),
|
|
1537
|
+
failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.warning, role: "alert", children: [
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageRefreshFailed") }),
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: failure.message ?? t("usageUnavailable") }),
|
|
1540
|
+
usage ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageStaleHint") }) : null
|
|
1541
|
+
] }) : null,
|
|
1542
|
+
failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1543
|
+
"button",
|
|
1544
|
+
{
|
|
1545
|
+
type: "button",
|
|
1546
|
+
className: UsagePill_default.retry,
|
|
1547
|
+
disabled: refreshing,
|
|
1548
|
+
onClick: () => {
|
|
1549
|
+
retry.current();
|
|
1550
|
+
},
|
|
1551
|
+
children: t(refreshing ? "usageRefreshing" : "usageRetry")
|
|
1552
|
+
}
|
|
1553
|
+
) : null,
|
|
1554
|
+
current ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: UsagePill_default.hint, children: [
|
|
1555
|
+
t("usageLastUpdated"),
|
|
1556
|
+
" ",
|
|
1557
|
+
new Date(current.updatedAt).toLocaleString(getLocale?.())
|
|
1558
|
+
] }) : null,
|
|
1416
1559
|
usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.window, children: [
|
|
1417
1560
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.row, children: [
|
|
1418
1561
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t(`usage_${key}`) }),
|
|
@@ -1425,10 +1568,10 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
1425
1568
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.hint, children: [
|
|
1426
1569
|
t("usageResets"),
|
|
1427
1570
|
" ",
|
|
1428
|
-
new Date(usage[key].resetsAt).toLocaleString()
|
|
1571
|
+
new Date(usage[key].resetsAt).toLocaleString(getLocale?.())
|
|
1429
1572
|
] }),
|
|
1430
1573
|
usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: t("usageLimited") })
|
|
1431
|
-
] }, key)) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children:
|
|
1574
|
+
] }, key)) : failure ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageLoading") })
|
|
1432
1575
|
] })
|
|
1433
1576
|
] });
|
|
1434
1577
|
}
|
|
@@ -1439,7 +1582,7 @@ function registerUsagePill(ctx) {
|
|
|
1439
1582
|
scope.inject(["remote.opencodeGoUsage"], (ready) => {
|
|
1440
1583
|
const readUsage = async () => {
|
|
1441
1584
|
const result = await ready.remote.opencodeGoUsage.read();
|
|
1442
|
-
if (!result.ok) throw
|
|
1585
|
+
if (!result.ok) throw result.error;
|
|
1443
1586
|
return result.value;
|
|
1444
1587
|
};
|
|
1445
1588
|
const translate = ready.locale.bind("settings.opencode-go");
|
|
@@ -1450,6 +1593,7 @@ function registerUsagePill(ctx) {
|
|
|
1450
1593
|
inject: (sessionId) => ({
|
|
1451
1594
|
directory: ready.modelDirectories.directoryFor(sessionId).store,
|
|
1452
1595
|
readUsage,
|
|
1596
|
+
getLocale: () => ready.locale.getLocale().active,
|
|
1453
1597
|
t: (key) => translate(key)
|
|
1454
1598
|
})
|
|
1455
1599
|
}, UsagePill));
|
|
@@ -1483,7 +1627,7 @@ function mountSettings(ctx, scope, modelsReady) {
|
|
|
1483
1627
|
});
|
|
1484
1628
|
ctx.effect(() => () => controller.dispose());
|
|
1485
1629
|
const t = ctx.locale.bind(NS);
|
|
1486
|
-
const injected = () => ({ ...controller.inject(), t });
|
|
1630
|
+
const injected = () => ({ ...controller.inject(), t, getLocale: () => ctx.locale.getLocale().active });
|
|
1487
1631
|
ctx.effect(() => {
|
|
1488
1632
|
const refresh = (ref) => {
|
|
1489
1633
|
controller.refreshCredential(ref);
|