dsh-opencode-go 0.1.6 → 0.1.8
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 +130 -0
- package/README.md +39 -60
- package/docs/assets/install-via-dsh.gif +0 -0
- package/docs/verification.md +51 -0
- package/lib/client.js +628 -172
- package/lib/index.js +189 -28
- package/lib/types/adapter.d.ts +2 -3
- package/lib/types/catalog.d.ts +5 -0
- package/lib/types/client/ModelEditor.d.ts +13 -0
- package/lib/types/client/locales.d.ts +30 -0
- package/lib/types/client/section-controller.d.ts +41 -3
- package/lib/types/client/settings.d.ts +18 -0
- package/lib/types/client/staged-form.d.ts +11 -1
- package/lib/types/config.d.ts +31 -5
- package/lib/types/index.d.ts +12 -8
- package/lib/types/model-metadata.d.ts +2 -0
- package/lib/types/models-contract.d.ts +23 -0
- package/lib/types/models.d.ts +12 -0
- package/lib/types/remote-contract.d.ts +3 -0
- package/lib/types/remotes.d.ts +3 -0
- package/package.json +27 -23
package/lib/client.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
window.__ModuleLoader__.load({ id: "dsh-opencode-go", factory: (require) => { var module = { exports: {} }; var exports = module.exports;
|
|
2
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __export = (target, all) => {
|
|
8
10
|
for (var name in all)
|
|
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
|
|
21
31
|
// src/client/index.ts
|
|
@@ -28,29 +38,252 @@ __export(index_exports, {
|
|
|
28
38
|
module.exports = __toCommonJS(index_exports);
|
|
29
39
|
|
|
30
40
|
// src/client/Section.tsx
|
|
41
|
+
var import_react2 = require("react");
|
|
42
|
+
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
43
|
+
var primitives = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
|
|
44
|
+
|
|
45
|
+
// src/client/ModelEditor.tsx
|
|
31
46
|
var import_react = require("react");
|
|
32
47
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
48
|
|
|
49
|
+
// src/models-contract.ts
|
|
50
|
+
function validReleaseDate(value) {
|
|
51
|
+
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
|
+
}
|
|
53
|
+
function isNewModel(model, now = Date.now()) {
|
|
54
|
+
if (model.deprecated || !validReleaseDate(model.releaseDate)) return false;
|
|
55
|
+
const days = Math.floor(now / 864e5) - Date.parse(model.releaseDate) / 864e5;
|
|
56
|
+
return days >= 0 && days < 7;
|
|
57
|
+
}
|
|
58
|
+
function sortModels(models, now = Date.now()) {
|
|
59
|
+
const rank = (model) => model.deprecated ? 2 : isNewModel(model, now) ? 0 : 1;
|
|
60
|
+
return [...models].sort((a, b) => rank(a) - rank(b) || (isNewModel(a, now) && isNewModel(b, now) ? b.releaseDate.localeCompare(a.releaseDate) : 0));
|
|
61
|
+
}
|
|
62
|
+
function parseGoModels(value) {
|
|
63
|
+
if (!Array.isArray(value)) throw new Error("Invalid OpenCode Go model list");
|
|
64
|
+
return value.map((entry) => {
|
|
65
|
+
if (!entry || typeof entry !== "object") throw new Error("Invalid OpenCode Go model");
|
|
66
|
+
const row = entry;
|
|
67
|
+
if (typeof row.id !== "string" || !row.id) throw new Error("Missing OpenCode Go model id");
|
|
68
|
+
const model = { id: row.id };
|
|
69
|
+
if (typeof row.name === "string") model.name = row.name;
|
|
70
|
+
for (const key of ["contextWindow", "maxTokens"]) {
|
|
71
|
+
if (typeof row[key] === "number" && Number.isSafeInteger(row[key]) && row[key] > 0) model[key] = row[key];
|
|
72
|
+
}
|
|
73
|
+
if (typeof row.deprecated === "boolean") model.deprecated = row.deprecated;
|
|
74
|
+
if (validReleaseDate(row.releaseDate)) model.releaseDate = row.releaseDate;
|
|
75
|
+
return model;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
var codec = {
|
|
79
|
+
mode: "strict",
|
|
80
|
+
typeSymbol: "dsh-opencode-go#GoModels",
|
|
81
|
+
schema: { parse: parseGoModels },
|
|
82
|
+
create: () => ({ parse: parseGoModels })
|
|
83
|
+
};
|
|
84
|
+
var modelsRemote = {
|
|
85
|
+
package: "dsh-opencode-go",
|
|
86
|
+
descriptors: [{
|
|
87
|
+
id: "dsh-opencode-go#opencodeGoModels/read",
|
|
88
|
+
service: "opencodeGoModels",
|
|
89
|
+
namespace: "opencodeGoModels",
|
|
90
|
+
method: "read",
|
|
91
|
+
invocation: { kind: "direct" },
|
|
92
|
+
parameters: [],
|
|
93
|
+
result: codec
|
|
94
|
+
}]
|
|
95
|
+
};
|
|
96
|
+
|
|
34
97
|
// plugin-css:/Users/tanglei/Desktop/dsh-opencode-go/src/client/Section.module.css
|
|
35
98
|
var id = "dsh-opencode-go/Section.module.css";
|
|
36
99
|
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")) {
|
|
37
100
|
const style = document.createElement("style");
|
|
38
101
|
style.dataset.plugin = "dsh-opencode-go";
|
|
39
102
|
style.dataset.pluginCss = id;
|
|
40
|
-
style.textContent =
|
|
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:100%;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:6px;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}';
|
|
41
104
|
document.head.appendChild(style);
|
|
42
105
|
}
|
|
43
|
-
var Section_default = { "
|
|
106
|
+
var Section_default = { "modelName": "BtKYva_modelName", "modelDetails": "BtKYva_modelDetails", "advanced": "BtKYva_advanced", "limitsEditor": "BtKYva_limitsEditor", "head": "BtKYva_head", "failedNote": "BtKYva_failedNote", "hint": "BtKYva_hint", "actions": "BtKYva_actions", "limitsFilterLabel": "BtKYva_limitsFilterLabel", "limitsId": "BtKYva_limitsId", "limitsToolbar": "BtKYva_limitsToolbar", "modelChoice": "BtKYva_modelChoice", "disclosure": "BtKYva_disclosure", "chevron": "BtKYva_chevron", "chevronOpen": "BtKYva_chevronOpen", "input": "BtKYva_input", "modelHeading": "BtKYva_modelHeading", "filter": "BtKYva_filter", "inputInvalid": "BtKYva_inputInvalid BtKYva_input", "page": "BtKYva_page", "label": "BtKYva_label", "reset": "BtKYva_reset", "badges": "BtKYva_badges", "advancedTrigger": "BtKYva_advancedTrigger BtKYva_disclosure", "visuallyHidden": "BtKYva_visuallyHidden", "keySection": "BtKYva_keySection", "limitsSummary": "BtKYva_limitsSummary", "invalid": "BtKYva_invalid", "field": "BtKYva_field", "pageTop": "BtKYva_pageTop", "modelLayout": "BtKYva_modelLayout", "newBadge": "BtKYva_newBadge", "filters": "BtKYva_filters", "releaseDate": "BtKYva_releaseDate", "chips": "BtKYva_chips", "limitsModelId": "BtKYva_limitsModelId", "pageBody": "BtKYva_pageBody", "modelList": "BtKYva_modelList", "intro": "BtKYva_intro" };
|
|
44
107
|
|
|
45
|
-
// src/client/
|
|
108
|
+
// src/client/ModelEditor.tsx
|
|
46
109
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
47
|
-
function
|
|
48
|
-
return
|
|
110
|
+
function hasCapacityOverride(limit) {
|
|
111
|
+
return limit?.contextWindow != null || limit?.maxTokens != null;
|
|
112
|
+
}
|
|
113
|
+
function ModelEditor({ models, draft, t, disabled, onEdit }) {
|
|
114
|
+
const [query, setQuery] = (0, import_react.useState)("");
|
|
115
|
+
const [filter, setFilter] = (0, import_react.useState)("all");
|
|
116
|
+
const [selected, setSelected] = (0, import_react.useState)();
|
|
117
|
+
const [now, setNow] = (0, import_react.useState)(Date.now);
|
|
118
|
+
(0, import_react.useEffect)(() => {
|
|
119
|
+
const timer = setInterval(() => {
|
|
120
|
+
setNow(Date.now());
|
|
121
|
+
}, 6e4);
|
|
122
|
+
return () => {
|
|
123
|
+
clearInterval(timer);
|
|
124
|
+
};
|
|
125
|
+
}, []);
|
|
126
|
+
const all = sortModels(models.status === "ready" ? models.entries : [], now);
|
|
127
|
+
const normalized = query.trim().toLocaleLowerCase();
|
|
128
|
+
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
|
+
const model = entries.find((entry) => entry.id === selected) ?? entries[0];
|
|
130
|
+
const customized = all.filter((entry) => hasCapacityOverride(draft[entry.id])).length;
|
|
131
|
+
const filters = [
|
|
132
|
+
["all", "filterAll", all.length],
|
|
133
|
+
["new", "filterNew", all.filter((entry) => isNewModel(entry, now)).length],
|
|
134
|
+
["custom", "filterCustom", customized],
|
|
135
|
+
["deprecated", "filterDeprecated", all.filter((entry) => entry.deprecated).length]
|
|
136
|
+
];
|
|
137
|
+
const write = (id3, field, value) => {
|
|
138
|
+
const current = draft[id3] === null ? { contextWindow: null, maxTokens: null } : draft[id3] ?? {};
|
|
139
|
+
onEdit({ ...draft, [id3]: { ...current, [field]: value ?? null } });
|
|
140
|
+
};
|
|
141
|
+
const badges = (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
142
|
+
isNewModel(entry, now) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.newBadge, title: t("newHint"), children: "NEW" }) : null,
|
|
143
|
+
entry.deprecated ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tag, { tone: "warning", children: t("deprecatedBadge") }) : null
|
|
144
|
+
] });
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.limitsEditor, children: [
|
|
146
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: Section_default.visuallyHidden, htmlFor: "opencode-go-model-filter", children: t("limitsFilterLabel") }),
|
|
147
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
148
|
+
"input",
|
|
149
|
+
{
|
|
150
|
+
id: "opencode-go-model-filter",
|
|
151
|
+
className: Section_default.input,
|
|
152
|
+
type: "search",
|
|
153
|
+
autoComplete: "off",
|
|
154
|
+
placeholder: t("limitsFilterPlaceholder"),
|
|
155
|
+
value: query,
|
|
156
|
+
onChange: (event) => {
|
|
157
|
+
setQuery(event.target.value);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
),
|
|
161
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: Section_default.filters, role: "group", "aria-label": t("filterLabel"), children: filters.map(([key, label, count]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
162
|
+
"button",
|
|
163
|
+
{
|
|
164
|
+
type: "button",
|
|
165
|
+
className: Section_default.filter,
|
|
166
|
+
"aria-pressed": filter === key,
|
|
167
|
+
onClick: () => {
|
|
168
|
+
setFilter(key);
|
|
169
|
+
},
|
|
170
|
+
children: [
|
|
171
|
+
t(label),
|
|
172
|
+
" ",
|
|
173
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: count })
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
key
|
|
177
|
+
)) }),
|
|
178
|
+
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
|
+
"button",
|
|
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)(
|
|
210
|
+
"button",
|
|
211
|
+
{
|
|
212
|
+
type: "button",
|
|
213
|
+
className: Section_default.reset,
|
|
214
|
+
disabled,
|
|
215
|
+
onClick: () => {
|
|
216
|
+
onEdit({ ...draft, [model.id]: null });
|
|
217
|
+
},
|
|
218
|
+
children: t("limitsResetModel")
|
|
219
|
+
}
|
|
220
|
+
) : null,
|
|
221
|
+
model.releaseDate ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("releaseSource", { date: model.releaseDate }) }) : null,
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("limitsHint") })
|
|
223
|
+
] })
|
|
224
|
+
] }) : models.status === "ready" && all.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("limitsNoMatches", { query }) }) : null,
|
|
49
225
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.head, children: [
|
|
50
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
226
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.limitsSummary, children: t("limitsSummary", { count: customized }) }),
|
|
227
|
+
Object.values(draft).some(hasCapacityOverride) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
228
|
+
"button",
|
|
229
|
+
{
|
|
230
|
+
type: "button",
|
|
231
|
+
className: Section_default.reset,
|
|
232
|
+
disabled,
|
|
233
|
+
onClick: () => {
|
|
234
|
+
onEdit(Object.fromEntries(Object.keys(draft).map((id3) => [id3, null])));
|
|
235
|
+
},
|
|
236
|
+
children: t("limitsResetAll")
|
|
237
|
+
}
|
|
238
|
+
) : null
|
|
239
|
+
] })
|
|
240
|
+
] });
|
|
241
|
+
}
|
|
242
|
+
function Capacity({ model, field, limit, disabled, t, onChange }) {
|
|
243
|
+
const id3 = `opencode-go-${field}-${encodeURIComponent(model.id)}`;
|
|
244
|
+
const defaultValue = model[field];
|
|
245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.field, children: [
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: Section_default.label, htmlFor: id3, children: t(field === "contextWindow" ? "limitsContext" : "limitsOutput") }),
|
|
247
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
248
|
+
"input",
|
|
249
|
+
{
|
|
250
|
+
id: id3,
|
|
251
|
+
className: Section_default.input,
|
|
252
|
+
type: "number",
|
|
253
|
+
min: 1,
|
|
254
|
+
step: 1,
|
|
255
|
+
inputMode: "numeric",
|
|
256
|
+
"aria-label": t(field === "contextWindow" ? "limitsContextLabel" : "limitsOutputLabel", { name: model.name ?? model.id }),
|
|
257
|
+
"aria-describedby": `${id3}-default`,
|
|
258
|
+
value: limit?.[field] ?? "",
|
|
259
|
+
placeholder: defaultValue === void 0 ? t("capacityMissing") : String(defaultValue),
|
|
260
|
+
disabled,
|
|
261
|
+
onChange: (event) => {
|
|
262
|
+
const text = event.target.value.trim();
|
|
263
|
+
const value = Number(text);
|
|
264
|
+
if (text === "") onChange(model.id, field, void 0);
|
|
265
|
+
else if (Number.isSafeInteger(value) && value > 0) onChange(model.id, field, value);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
),
|
|
269
|
+
/* @__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("en-US") }),
|
|
271
|
+
limit?.[field] != null ? ` \xB7 ${t("overridden")}` : ""
|
|
272
|
+
] })
|
|
273
|
+
] });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/client/Section.tsx
|
|
277
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
278
|
+
var ChevronDown = primitives.IconChevronDownOutlineRegular ?? primitives.IconChevronDownOutline14;
|
|
279
|
+
function ValueField(props) {
|
|
280
|
+
const hintId = `${props.id}-hint`;
|
|
281
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
|
|
282
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
|
|
283
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: Section_default.label, htmlFor: props.id, children: props.label }),
|
|
284
|
+
props.field.overridden ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.badges, children: [
|
|
285
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: "neutral", children: props.overriddenLabel }),
|
|
286
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
54
287
|
"button",
|
|
55
288
|
{
|
|
56
289
|
type: "button",
|
|
@@ -62,12 +295,15 @@ function ValueField(props) {
|
|
|
62
295
|
)
|
|
63
296
|
] }) : null
|
|
64
297
|
] }),
|
|
65
|
-
/* @__PURE__ */ (0,
|
|
298
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
66
299
|
"input",
|
|
67
300
|
{
|
|
68
301
|
id: props.id,
|
|
302
|
+
name: props.id,
|
|
303
|
+
autoComplete: "off",
|
|
304
|
+
"aria-describedby": hintId,
|
|
69
305
|
className: props.field.invalid ? Section_default.inputInvalid : Section_default.input,
|
|
70
|
-
type: "text",
|
|
306
|
+
type: props.numeric === true ? "number" : "text",
|
|
71
307
|
...props.numeric === true ? { inputMode: "numeric" } : {},
|
|
72
308
|
...props.field.invalid ? { "aria-invalid": true } : {},
|
|
73
309
|
value: props.field.text,
|
|
@@ -77,24 +313,24 @@ function ValueField(props) {
|
|
|
77
313
|
}
|
|
78
314
|
}
|
|
79
315
|
),
|
|
80
|
-
/* @__PURE__ */ (0,
|
|
316
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { id: hintId, className: props.field.invalid ? Section_default.invalid : Section_default.hint, children: props.field.invalid ? props.invalidLabel : props.hint })
|
|
81
317
|
] });
|
|
82
318
|
}
|
|
83
319
|
function ModelsBody({ models, t }) {
|
|
84
320
|
if (models.status === "failed") {
|
|
85
|
-
return /* @__PURE__ */ (0,
|
|
86
|
-
/* @__PURE__ */ (0,
|
|
87
|
-
/* @__PURE__ */ (0,
|
|
321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
322
|
+
/* @__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 })
|
|
88
324
|
] });
|
|
89
325
|
}
|
|
90
|
-
if (models.status !== "ready") return /* @__PURE__ */ (0,
|
|
91
|
-
if (models.count === 0) return /* @__PURE__ */ (0,
|
|
92
|
-
return
|
|
326
|
+
if (models.status !== "ready") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, role: "status", "aria-live": "polite", children: t("modelsLoading") });
|
|
327
|
+
if (models.count === 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("modelsEmpty") });
|
|
328
|
+
return null;
|
|
93
329
|
}
|
|
94
330
|
function OpencodeGoSection(props) {
|
|
95
|
-
const { useOpencodeGo, edit, resetField, save, discard, loadModels, setEnabled, t } = props;
|
|
96
|
-
if (useOpencodeGo === void 0 || edit === void 0 || resetField === void 0 || save === void 0 || discard === void 0 || loadModels === void 0 || setEnabled === void 0 || t === void 0) return null;
|
|
97
|
-
return /* @__PURE__ */ (0,
|
|
331
|
+
const { useOpencodeGo, edit, resetField, save, discard, loadModels, setEnabled, setShowDeprecatedModels, t } = props;
|
|
332
|
+
if (useOpencodeGo === void 0 || edit === void 0 || resetField === void 0 || save === void 0 || discard === void 0 || loadModels === void 0 || setEnabled === void 0 || setShowDeprecatedModels === void 0 || t === void 0) return null;
|
|
333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
98
334
|
Loaded,
|
|
99
335
|
{
|
|
100
336
|
state: useOpencodeGo((snapshot) => snapshot),
|
|
@@ -104,18 +340,19 @@ function OpencodeGoSection(props) {
|
|
|
104
340
|
save,
|
|
105
341
|
discard,
|
|
106
342
|
loadModels,
|
|
107
|
-
setEnabled
|
|
343
|
+
setEnabled,
|
|
344
|
+
setShowDeprecatedModels
|
|
108
345
|
}
|
|
109
346
|
);
|
|
110
347
|
}
|
|
111
348
|
function Loaded(props) {
|
|
112
349
|
const { t, state, loadModels } = props;
|
|
113
|
-
const [advanced, setAdvanced] = (0,
|
|
114
|
-
(0,
|
|
350
|
+
const [advanced, setAdvanced] = (0, import_react2.useState)(false);
|
|
351
|
+
(0, import_react2.useEffect)(() => {
|
|
115
352
|
if (state.available && state.models.status === "idle") loadModels();
|
|
116
353
|
}, [state.available, state.models.status, loadModels]);
|
|
117
354
|
if (!state.available) {
|
|
118
|
-
return /* @__PURE__ */ (0,
|
|
355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.intro, children: t("unavailable") });
|
|
119
356
|
}
|
|
120
357
|
const disabled = !state.writable;
|
|
121
358
|
const fieldProps = {
|
|
@@ -125,84 +362,31 @@ function Loaded(props) {
|
|
|
125
362
|
disabled
|
|
126
363
|
};
|
|
127
364
|
const advancedOverridden = state.apiKeyEnv.overridden || state.baseURL.overridden || state.refreshMinutes.overridden || state.streamIdleTimeoutMs.overridden || state.maxRequestImageBytes.overridden || state.requestImagePixelBudget.overridden || state.requestImageMaxBytes.overridden;
|
|
128
|
-
return /* @__PURE__ */ (0,
|
|
129
|
-
/* @__PURE__ */ (0,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
/* @__PURE__ */ (0,
|
|
133
|
-
|
|
134
|
-
import_dsh_client_ui_primitives.Switch,
|
|
365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.page, children: [
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.pageBody, children: [
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.pageTop, children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.intro, children: t("intro") }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
370
|
+
"button",
|
|
135
371
|
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
372
|
+
type: "button",
|
|
373
|
+
className: Section_default.advancedTrigger,
|
|
374
|
+
"aria-expanded": advanced,
|
|
375
|
+
"aria-controls": "opencode-go-advanced",
|
|
376
|
+
onClick: () => {
|
|
377
|
+
setAdvanced(!advanced);
|
|
378
|
+
},
|
|
379
|
+
children: [
|
|
380
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: advanced ? Section_default.chevronOpen : Section_default.chevron }),
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("advancedLabel") }),
|
|
382
|
+
advancedOverridden ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: "neutral", children: t("overridden") }) : null
|
|
383
|
+
]
|
|
140
384
|
}
|
|
141
385
|
)
|
|
142
386
|
] }),
|
|
143
|
-
/* @__PURE__ */ (0,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.head, children: [
|
|
147
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: Section_default.label, htmlFor: "opencode-go-key", children: t("keyLabel") }),
|
|
148
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.badges, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tag, { tone: state.apiKeyConfigured ? "success" : "warning", children: state.apiKeyConfigured ? t("keyConfigured") : t("keyMissing") }) })
|
|
149
|
-
] }),
|
|
150
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
151
|
-
"input",
|
|
152
|
-
{
|
|
153
|
-
id: "opencode-go-key",
|
|
154
|
-
className: Section_default.input,
|
|
155
|
-
type: "password",
|
|
156
|
-
autoComplete: "off",
|
|
157
|
-
value: state.apiKey.text,
|
|
158
|
-
disabled: !state.apiKeyWritable,
|
|
159
|
-
onChange: (event) => {
|
|
160
|
-
props.edit("apiKey", event.target.value);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
),
|
|
164
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: state.apiKeyWritable ? t("keyHint") : t("keyNotWritable") })
|
|
165
|
-
] }),
|
|
166
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.field, children: [
|
|
167
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.head, children: [
|
|
168
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.label, children: t("modelsLabel") }),
|
|
169
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: Section_default.badges, children: [
|
|
170
|
-
state.models.status === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tag, { tone: "neutral", children: t("modelsCount", { count: state.models.count }) }) : null,
|
|
171
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
172
|
-
"button",
|
|
173
|
-
{
|
|
174
|
-
type: "button",
|
|
175
|
-
className: Section_default.reset,
|
|
176
|
-
disabled: state.models.status === "loading",
|
|
177
|
-
onClick: loadModels,
|
|
178
|
-
children: t("modelsRefresh")
|
|
179
|
-
}
|
|
180
|
-
)
|
|
181
|
-
] })
|
|
182
|
-
] }),
|
|
183
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModelsBody, { models: state.models, t })
|
|
184
|
-
] }),
|
|
185
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.field, children: [
|
|
186
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
187
|
-
"button",
|
|
188
|
-
{
|
|
189
|
-
type: "button",
|
|
190
|
-
className: Section_default.disclosure,
|
|
191
|
-
"aria-expanded": advanced,
|
|
192
|
-
"aria-controls": "opencode-go-advanced",
|
|
193
|
-
onClick: () => {
|
|
194
|
-
setAdvanced(!advanced);
|
|
195
|
-
},
|
|
196
|
-
children: [
|
|
197
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconChevronDownOutline14, { className: advanced ? Section_default.chevronOpen : Section_default.chevron }),
|
|
198
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Section_default.label, children: t("advancedLabel") }),
|
|
199
|
-
advancedOverridden ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tag, { tone: "neutral", children: t("overridden") }) : null
|
|
200
|
-
]
|
|
201
|
-
}
|
|
202
|
-
),
|
|
203
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("advancedHint") }),
|
|
204
|
-
advanced ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { id: "opencode-go-advanced", className: Section_default.advanced, children: [
|
|
205
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: advanced ? Section_default.field : void 0, children: advanced ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: "opencode-go-advanced", className: Section_default.advanced, children: [
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("advancedHint") }),
|
|
389
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
206
390
|
ValueField,
|
|
207
391
|
{
|
|
208
392
|
id: "opencode-go-api-key-env",
|
|
@@ -218,7 +402,7 @@ function Loaded(props) {
|
|
|
218
402
|
}
|
|
219
403
|
}
|
|
220
404
|
),
|
|
221
|
-
/* @__PURE__ */ (0,
|
|
405
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
222
406
|
ValueField,
|
|
223
407
|
{
|
|
224
408
|
id: "opencode-go-base-url",
|
|
@@ -234,7 +418,7 @@ function Loaded(props) {
|
|
|
234
418
|
}
|
|
235
419
|
}
|
|
236
420
|
),
|
|
237
|
-
/* @__PURE__ */ (0,
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
238
422
|
ValueField,
|
|
239
423
|
{
|
|
240
424
|
id: "opencode-go-refresh-minutes",
|
|
@@ -251,7 +435,7 @@ function Loaded(props) {
|
|
|
251
435
|
}
|
|
252
436
|
}
|
|
253
437
|
),
|
|
254
|
-
/* @__PURE__ */ (0,
|
|
438
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
255
439
|
ValueField,
|
|
256
440
|
{
|
|
257
441
|
id: "opencode-go-stream-idle",
|
|
@@ -268,7 +452,7 @@ function Loaded(props) {
|
|
|
268
452
|
}
|
|
269
453
|
}
|
|
270
454
|
),
|
|
271
|
-
/* @__PURE__ */ (0,
|
|
455
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
272
456
|
ValueField,
|
|
273
457
|
{
|
|
274
458
|
id: "opencode-go-max-request-image-bytes",
|
|
@@ -285,7 +469,7 @@ function Loaded(props) {
|
|
|
285
469
|
}
|
|
286
470
|
}
|
|
287
471
|
),
|
|
288
|
-
/* @__PURE__ */ (0,
|
|
472
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
289
473
|
ValueField,
|
|
290
474
|
{
|
|
291
475
|
id: "opencode-go-image-pixel-budget",
|
|
@@ -302,7 +486,7 @@ function Loaded(props) {
|
|
|
302
486
|
}
|
|
303
487
|
}
|
|
304
488
|
),
|
|
305
|
-
/* @__PURE__ */ (0,
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
306
490
|
ValueField,
|
|
307
491
|
{
|
|
308
492
|
id: "opencode-go-image-max-bytes",
|
|
@@ -319,14 +503,100 @@ function Loaded(props) {
|
|
|
319
503
|
}
|
|
320
504
|
}
|
|
321
505
|
)
|
|
322
|
-
] }) : null
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
506
|
+
] }) : null }),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("enabledLabel") }),
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
511
|
+
import_dsh_client_ui_primitives2.Switch,
|
|
512
|
+
{
|
|
513
|
+
checked: state.enabled,
|
|
514
|
+
label: t("enabledLabel"),
|
|
515
|
+
disabled,
|
|
516
|
+
onChange: props.setEnabled
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
] }),
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: state.enabled ? t("enabledHint") : t("enabledOff") })
|
|
521
|
+
] }),
|
|
522
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("details", { className: Section_default.keySection, open: !state.apiKeyConfigured || state.apiKey.text.length > 0, children: [
|
|
523
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("summary", { className: Section_default.head, children: [
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("keyLabel") }),
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.badges, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: state.apiKeyConfigured ? "success" : "warning", children: state.apiKeyConfigured ? t("keyConfigured") : t("keyMissing") }) })
|
|
526
|
+
] }),
|
|
527
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
528
|
+
"input",
|
|
529
|
+
{
|
|
530
|
+
id: "opencode-go-key",
|
|
531
|
+
"aria-label": t("keyLabel"),
|
|
532
|
+
name: "api-key",
|
|
533
|
+
className: Section_default.input,
|
|
534
|
+
type: "password",
|
|
535
|
+
autoComplete: "off",
|
|
536
|
+
"aria-describedby": "opencode-go-key-hint",
|
|
537
|
+
value: state.apiKey.text,
|
|
538
|
+
disabled: !state.apiKeyWritable,
|
|
539
|
+
onChange: (event) => {
|
|
540
|
+
props.edit("apiKey", event.target.value);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
),
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { id: "opencode-go-key-hint", className: Section_default.hint, children: state.apiKeyWritable ? t("keyHint") : t("keyNotWritable") })
|
|
545
|
+
] }),
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("modelsLabel") }),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.badges, children: [
|
|
550
|
+
state.models.status === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: "neutral", children: t("modelsCount", { count: state.models.count }) }) : null,
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
552
|
+
"button",
|
|
553
|
+
{
|
|
554
|
+
type: "button",
|
|
555
|
+
className: Section_default.reset,
|
|
556
|
+
disabled: state.models.status === "loading",
|
|
557
|
+
onClick: loadModels,
|
|
558
|
+
children: t("modelsRefresh")
|
|
559
|
+
}
|
|
560
|
+
)
|
|
561
|
+
] })
|
|
562
|
+
] }),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ModelsBody, { models: state.models, t })
|
|
564
|
+
] }),
|
|
565
|
+
/* @__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
|
+
state.pickerFailed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("pickerFailed") }) : null,
|
|
580
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
581
|
+
ModelEditor,
|
|
582
|
+
{
|
|
583
|
+
models: state.models,
|
|
584
|
+
draft: state.modelLimitDraft,
|
|
585
|
+
t,
|
|
586
|
+
disabled: disabled || state.saving,
|
|
587
|
+
onEdit: (next) => {
|
|
588
|
+
props.edit("modelLimits", JSON.stringify(next));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
] }),
|
|
593
|
+
disabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("readOnly") }) : null
|
|
328
594
|
] }),
|
|
329
|
-
|
|
595
|
+
/* @__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") }),
|
|
597
|
+
/* @__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
|
+
state.failed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, children: t("savedFailed") }) : null
|
|
599
|
+
] })
|
|
330
600
|
] });
|
|
331
601
|
}
|
|
332
602
|
|
|
@@ -365,6 +635,21 @@ function textField(field) {
|
|
|
365
635
|
}
|
|
366
636
|
};
|
|
367
637
|
}
|
|
638
|
+
function jsonField(field) {
|
|
639
|
+
return {
|
|
640
|
+
field,
|
|
641
|
+
format: (value) => value === void 0 || value === null ? "" : JSON.stringify(value, void 0, 2),
|
|
642
|
+
parse: (text) => {
|
|
643
|
+
const trimmed = text.trim();
|
|
644
|
+
if (trimmed === "") return { kind: "clear" };
|
|
645
|
+
try {
|
|
646
|
+
return { kind: "set", value: JSON.parse(trimmed) };
|
|
647
|
+
} catch {
|
|
648
|
+
return void 0;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
}
|
|
368
653
|
var StagedForm = class {
|
|
369
654
|
/**
|
|
370
655
|
* @param scope - the bound settings scope for this page's namespace.
|
|
@@ -375,7 +660,7 @@ var StagedForm = class {
|
|
|
375
660
|
this.scope = scope;
|
|
376
661
|
this.specs = new Map(specs.map((spec) => [spec.field, spec]));
|
|
377
662
|
this.secretSpecs = new Map(secrets.map((spec) => [spec.field, spec]));
|
|
378
|
-
scope.subscribe(() => {
|
|
663
|
+
this.unsubscribe = scope.subscribe(() => {
|
|
379
664
|
this.publish();
|
|
380
665
|
});
|
|
381
666
|
}
|
|
@@ -383,8 +668,14 @@ var StagedForm = class {
|
|
|
383
668
|
secretSpecs;
|
|
384
669
|
staged = /* @__PURE__ */ new Map();
|
|
385
670
|
listeners = /* @__PURE__ */ new Set();
|
|
671
|
+
unsubscribe;
|
|
386
672
|
saving = false;
|
|
387
673
|
failed = false;
|
|
674
|
+
/** Shared 0.1.7 forms outlive individual settings pages. */
|
|
675
|
+
dispose() {
|
|
676
|
+
this.unsubscribe();
|
|
677
|
+
this.listeners.clear();
|
|
678
|
+
}
|
|
388
679
|
/**
|
|
389
680
|
* Publish a projection of this form, rebuilt whenever the scope or a draft changes.
|
|
390
681
|
* @param project - build the page state from the form's current reads.
|
|
@@ -515,7 +806,7 @@ var StagedForm = class {
|
|
|
515
806
|
}
|
|
516
807
|
async store(field, value) {
|
|
517
808
|
await this.scope.set(field, value);
|
|
518
|
-
return this.userLayer()?.[field]
|
|
809
|
+
return sameJsonValue(this.userLayer()?.[field], value);
|
|
519
810
|
}
|
|
520
811
|
stage(field, edit) {
|
|
521
812
|
this.staged.set(field, edit);
|
|
@@ -547,6 +838,19 @@ var StagedForm = class {
|
|
|
547
838
|
for (const listener of this.listeners) listener();
|
|
548
839
|
}
|
|
549
840
|
};
|
|
841
|
+
function sameJsonValue(left, right) {
|
|
842
|
+
if (Object.is(left, right)) return true;
|
|
843
|
+
if (left === null || right === null || typeof left !== "object" || typeof right !== "object") return false;
|
|
844
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
845
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
|
|
846
|
+
return left.every((value, index) => sameJsonValue(value, right[index]));
|
|
847
|
+
}
|
|
848
|
+
const leftRecord = left;
|
|
849
|
+
const rightRecord = right;
|
|
850
|
+
const leftKeys = Object.keys(leftRecord);
|
|
851
|
+
const rightKeys = Object.keys(rightRecord);
|
|
852
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(rightRecord, key) && sameJsonValue(leftRecord[key], rightRecord[key]));
|
|
853
|
+
}
|
|
550
854
|
|
|
551
855
|
// src/client/section-controller.ts
|
|
552
856
|
var OPENCODE_GO_NS = "llm-opencode-go";
|
|
@@ -559,9 +863,10 @@ var OpencodeGoSectionController = class {
|
|
|
559
863
|
* @param ctx - the page plugin's context, whose `remote.credentials` namespace
|
|
560
864
|
* answers for the credential the section references.
|
|
561
865
|
*/
|
|
562
|
-
constructor(scope, ctx) {
|
|
866
|
+
constructor(scope, ctx, readModels = () => ctx.remote.llm.discoverModels(OPENCODE_GO_NS, { provider: OPENCODE_GO_PROVIDER })) {
|
|
563
867
|
this.scope = scope;
|
|
564
868
|
this.ctx = ctx;
|
|
869
|
+
this.readModels = readModels;
|
|
565
870
|
this.form = new StagedForm(
|
|
566
871
|
scope,
|
|
567
872
|
[
|
|
@@ -574,12 +879,13 @@ var OpencodeGoSectionController = class {
|
|
|
574
879
|
numberField("streamIdleTimeoutMs"),
|
|
575
880
|
numberField("maxRequestImageBytes"),
|
|
576
881
|
numberField("requestImagePixelBudget"),
|
|
577
|
-
numberField("requestImageMaxBytes")
|
|
882
|
+
numberField("requestImageMaxBytes"),
|
|
883
|
+
jsonField("modelLimits")
|
|
578
884
|
],
|
|
579
885
|
[{ field: API_KEY_FIELD, write: (text) => this.writeKey(text) }]
|
|
580
886
|
);
|
|
581
887
|
this.store = this.form.bind(() => this.projection());
|
|
582
|
-
scope.subscribe(() => {
|
|
888
|
+
this.unsubscribe = scope.subscribe(() => {
|
|
583
889
|
void this.readCredential();
|
|
584
890
|
});
|
|
585
891
|
void this.readCredential();
|
|
@@ -589,11 +895,23 @@ var OpencodeGoSectionController = class {
|
|
|
589
895
|
credential = { ref: "", configured: false, writable: true };
|
|
590
896
|
models = { status: "idle" };
|
|
591
897
|
modelsRequest = 0;
|
|
898
|
+
pickerSaving = false;
|
|
899
|
+
pickerFailed = false;
|
|
592
900
|
face;
|
|
901
|
+
unsubscribe;
|
|
902
|
+
/** Release subscriptions without disposing the host's shared form. */
|
|
903
|
+
dispose() {
|
|
904
|
+
this.modelsRequest++;
|
|
905
|
+
this.unsubscribe();
|
|
906
|
+
this.form.dispose();
|
|
907
|
+
}
|
|
593
908
|
projection() {
|
|
594
909
|
return {
|
|
595
910
|
...this.form.shell(),
|
|
596
911
|
enabled: this.enabled(),
|
|
912
|
+
showDeprecatedModels: this.scope.getSnapshot().value?.showDeprecatedModels ?? false,
|
|
913
|
+
pickerSaving: this.pickerSaving,
|
|
914
|
+
pickerFailed: this.pickerFailed,
|
|
597
915
|
apiKeyEnv: this.form.field("apiKeyEnv"),
|
|
598
916
|
baseURL: this.form.field("baseURL"),
|
|
599
917
|
refreshMinutes: this.form.field("refreshMinutes"),
|
|
@@ -604,9 +922,28 @@ var OpencodeGoSectionController = class {
|
|
|
604
922
|
apiKey: this.form.field(API_KEY_FIELD),
|
|
605
923
|
apiKeyConfigured: this.credential.configured,
|
|
606
924
|
apiKeyWritable: this.credential.writable,
|
|
607
|
-
models: this.models
|
|
925
|
+
models: this.models,
|
|
926
|
+
modelLimits: this.form.field("modelLimits"),
|
|
927
|
+
modelLimitDraft: this.limitDraft()
|
|
608
928
|
};
|
|
609
929
|
}
|
|
930
|
+
/**
|
|
931
|
+
* Read the overrides as the page currently shows them. A staged JSON draft
|
|
932
|
+
* wins while it is valid; malformed text falls back to the last accepted
|
|
933
|
+
* settings value so the table never renders phantom rows.
|
|
934
|
+
*/
|
|
935
|
+
limitDraft() {
|
|
936
|
+
const staged = this.form.field("modelLimits");
|
|
937
|
+
if (staged.invalid) return modelLimitsOf(this.scope.getSnapshot().value?.modelLimits);
|
|
938
|
+
if (staged.overridden || this.form.shell().dirty) {
|
|
939
|
+
try {
|
|
940
|
+
return modelLimitsOf(JSON.parse(staged.text));
|
|
941
|
+
} catch {
|
|
942
|
+
return modelLimitsOf(this.scope.getSnapshot().value?.modelLimits);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return modelLimitsOf(this.scope.getSnapshot().value?.modelLimits);
|
|
946
|
+
}
|
|
610
947
|
/**
|
|
611
948
|
* The adapter's effective switch state: the resolved section's value, over
|
|
612
949
|
* the Host's own default when the section carries none.
|
|
@@ -629,6 +966,22 @@ var OpencodeGoSectionController = class {
|
|
|
629
966
|
setEnabled(next) {
|
|
630
967
|
void this.scope.set("enabled", next);
|
|
631
968
|
}
|
|
969
|
+
/** Visibility is immediate; failed writes leave the committed switch state visible. */
|
|
970
|
+
async setShowDeprecatedModels(next) {
|
|
971
|
+
if (this.pickerSaving || !this.scope.getSnapshot().writable) return;
|
|
972
|
+
this.pickerSaving = true;
|
|
973
|
+
this.pickerFailed = false;
|
|
974
|
+
this.store.set(this.projection());
|
|
975
|
+
try {
|
|
976
|
+
await this.scope.set("showDeprecatedModels", next);
|
|
977
|
+
this.pickerFailed = (this.scope.getSnapshot().value?.showDeprecatedModels ?? false) !== next;
|
|
978
|
+
} catch {
|
|
979
|
+
this.pickerFailed = true;
|
|
980
|
+
} finally {
|
|
981
|
+
this.pickerSaving = false;
|
|
982
|
+
this.store.set(this.projection());
|
|
983
|
+
}
|
|
984
|
+
}
|
|
632
985
|
/**
|
|
633
986
|
* Read the gateway's model listing through the Host's discovery for this
|
|
634
987
|
* adapter. Called when the page mounts and again from its refresh control.
|
|
@@ -640,12 +993,13 @@ var OpencodeGoSectionController = class {
|
|
|
640
993
|
const request = ++this.modelsRequest;
|
|
641
994
|
this.models = { status: "loading" };
|
|
642
995
|
this.store.set(this.projection());
|
|
643
|
-
void this.
|
|
996
|
+
void this.readModels().then((response) => {
|
|
644
997
|
if (request !== this.modelsRequest) return;
|
|
645
998
|
this.models = response.ok ? {
|
|
646
999
|
status: "ready",
|
|
647
1000
|
count: response.value.length,
|
|
648
|
-
preview: response.value.map((model) => model.name ?? model.id)
|
|
1001
|
+
preview: response.value.map((model) => model.name ?? model.id),
|
|
1002
|
+
entries: response.value
|
|
649
1003
|
} : { status: "failed", message: response.error.message };
|
|
650
1004
|
this.store.set(this.projection());
|
|
651
1005
|
}).catch((error) => {
|
|
@@ -708,6 +1062,9 @@ var OpencodeGoSectionController = class {
|
|
|
708
1062
|
setEnabled: (next) => {
|
|
709
1063
|
this.setEnabled(next);
|
|
710
1064
|
},
|
|
1065
|
+
setShowDeprecatedModels: (next) => {
|
|
1066
|
+
void this.setShowDeprecatedModels(next);
|
|
1067
|
+
},
|
|
711
1068
|
...this.form.actions()
|
|
712
1069
|
};
|
|
713
1070
|
return this.face;
|
|
@@ -723,6 +1080,29 @@ var OpencodeGoSectionController = class {
|
|
|
723
1080
|
return this.credential.configured;
|
|
724
1081
|
}
|
|
725
1082
|
};
|
|
1083
|
+
function modelLimitsOf(value) {
|
|
1084
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1085
|
+
const limits = {};
|
|
1086
|
+
for (const [id3, entry] of Object.entries(value)) {
|
|
1087
|
+
if (entry === null) {
|
|
1088
|
+
limits[id3] = null;
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
if (typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
1092
|
+
const fields = entry;
|
|
1093
|
+
const limit = {};
|
|
1094
|
+
if (fields.contextWindow === null) limit.contextWindow = null;
|
|
1095
|
+
if (fields.maxTokens === null) limit.maxTokens = null;
|
|
1096
|
+
if (typeof fields.contextWindow === "number" && Number.isSafeInteger(fields.contextWindow) && fields.contextWindow > 0) {
|
|
1097
|
+
limit.contextWindow = fields.contextWindow;
|
|
1098
|
+
}
|
|
1099
|
+
if (typeof fields.maxTokens === "number" && Number.isSafeInteger(fields.maxTokens) && fields.maxTokens > 0) {
|
|
1100
|
+
limit.maxTokens = fields.maxTokens;
|
|
1101
|
+
}
|
|
1102
|
+
if (limit.contextWindow !== void 0 || limit.maxTokens !== void 0) limits[id3] = limit;
|
|
1103
|
+
}
|
|
1104
|
+
return limits;
|
|
1105
|
+
}
|
|
726
1106
|
function refOf(snapshot) {
|
|
727
1107
|
const declared = snapshot.value?.apiKeyEnv;
|
|
728
1108
|
return declared !== void 0 && declared.length > 0 ? declared : DEFAULT_API_KEY_REF;
|
|
@@ -742,7 +1122,7 @@ var en = {
|
|
|
742
1122
|
usageUnavailable: "Unavailable",
|
|
743
1123
|
nav: "OpenCode Go",
|
|
744
1124
|
title: "OpenCode Go",
|
|
745
|
-
intro: "
|
|
1125
|
+
intro: "Manage your OpenCode Go subscription models and their capacities.",
|
|
746
1126
|
enabledLabel: "Enable OpenCode Go",
|
|
747
1127
|
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.",
|
|
748
1128
|
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.",
|
|
@@ -758,6 +1138,36 @@ var en = {
|
|
|
758
1138
|
modelsFailed: "Could not read the gateway model list.",
|
|
759
1139
|
modelsEmpty: "The gateway currently serves no model this adapter can route.",
|
|
760
1140
|
modelsCount: "{count} models",
|
|
1141
|
+
limitsLabel: "Model capacities",
|
|
1142
|
+
limitsHint: "Capacities come from the model API. Leave blank to use the default; save to apply your overrides.",
|
|
1143
|
+
limitsFilterLabel: "Find a model",
|
|
1144
|
+
limitsFilterPlaceholder: "Search by model name or id\u2026",
|
|
1145
|
+
limitsSummary: "{count} customized",
|
|
1146
|
+
limitsModel: "Model",
|
|
1147
|
+
limitsContext: "Context window",
|
|
1148
|
+
limitsOutput: "Max output",
|
|
1149
|
+
capacityDefault: "Default: {value} tokens",
|
|
1150
|
+
capacityMissing: "API did not provide a value",
|
|
1151
|
+
showDeprecatedLabel: "Show deprecated models in conversations",
|
|
1152
|
+
showDeprecatedHint: "Off by default. Turning this on immediately adds deprecated models still served by the gateway to conversation model pickers.",
|
|
1153
|
+
pickerFailed: "Could not update model visibility. Please retry.",
|
|
1154
|
+
deprecatedBadge: "Deprecated",
|
|
1155
|
+
deprecatedHint: "Marked deprecated by models.dev, but still provided by this gateway.",
|
|
1156
|
+
newHint: "Released within the last seven UTC calendar days, according to models.dev.",
|
|
1157
|
+
releasedOn: "Released {date}",
|
|
1158
|
+
releaseSource: "Release date: {date} \xB7 models.dev",
|
|
1159
|
+
modelDetails: "Model configuration",
|
|
1160
|
+
filterLabel: "Filter models",
|
|
1161
|
+
filterAll: "All",
|
|
1162
|
+
filterNew: "New in 7 days",
|
|
1163
|
+
filterCustom: "Customized",
|
|
1164
|
+
filterDeprecated: "Deprecated",
|
|
1165
|
+
limitsResetModel: "Use catalog",
|
|
1166
|
+
limitsResetAll: "Clear all overrides",
|
|
1167
|
+
limitsNoMatches: "No models match \u201C{query}\u201D. Try a different name or id.",
|
|
1168
|
+
limitsEmpty: "Read the model list first; capacities are edited per model the gateway serves.",
|
|
1169
|
+
limitsContextLabel: "Context window for {name}",
|
|
1170
|
+
limitsOutputLabel: "Max output for {name}",
|
|
761
1171
|
advancedLabel: "Advanced settings",
|
|
762
1172
|
advancedHint: "Credential name, gateway URL, and adapter tuning. The inherited values work as they are; change them only if you know you need to.",
|
|
763
1173
|
apiKeyEnvLabel: "Credential reference",
|
|
@@ -797,7 +1207,7 @@ var zh = {
|
|
|
797
1207
|
usageUnavailable: "\u6682\u4E0D\u53EF\u7528",
|
|
798
1208
|
nav: "OpenCode Go",
|
|
799
1209
|
title: "OpenCode Go",
|
|
800
|
-
intro: "\
|
|
1210
|
+
intro: "\u7BA1\u7406 OpenCode Go \u8BA2\u9605\u6A21\u578B\u53CA\u5176\u5BB9\u91CF\u3002",
|
|
801
1211
|
enabledLabel: "\u542F\u7528 OpenCode Go",
|
|
802
1212
|
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",
|
|
803
1213
|
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",
|
|
@@ -813,6 +1223,36 @@ var zh = {
|
|
|
813
1223
|
modelsFailed: "\u672A\u80FD\u8BFB\u53D6\u7F51\u5173\u6A21\u578B\u5217\u8868\u3002",
|
|
814
1224
|
modelsEmpty: "\u7F51\u5173\u5F53\u524D\u6CA1\u6709\u672C\u9002\u914D\u5668\u53EF\u8DEF\u7531\u7684\u6A21\u578B\u3002",
|
|
815
1225
|
modelsCount: "{count} \u4E2A\u6A21\u578B",
|
|
1226
|
+
limitsLabel: "\u6A21\u578B\u5BB9\u91CF",
|
|
1227
|
+
limitsHint: "\u5BB9\u91CF\u6765\u81EA\u6A21\u578B API\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u503C\uFF0C\u4FEE\u6539\u540E\u4FDD\u5B58\u751F\u6548\u3002",
|
|
1228
|
+
limitsFilterLabel: "\u67E5\u627E\u6A21\u578B",
|
|
1229
|
+
limitsFilterPlaceholder: "\u6309\u6A21\u578B\u540D\u79F0\u6216 ID \u641C\u7D22\u2026",
|
|
1230
|
+
limitsSummary: "{count} \u4E2A\u5DF2\u81EA\u5B9A\u4E49",
|
|
1231
|
+
limitsModel: "\u6A21\u578B",
|
|
1232
|
+
limitsContext: "\u4E0A\u4E0B\u6587\u7A97\u53E3",
|
|
1233
|
+
limitsOutput: "\u6700\u5927\u8F93\u51FA",
|
|
1234
|
+
capacityDefault: "\u9ED8\u8BA4\uFF1A{value} tokens",
|
|
1235
|
+
capacityMissing: "API \u672A\u63D0\u4F9B",
|
|
1236
|
+
showDeprecatedLabel: "\u5728\u4F1A\u8BDD\u4E2D\u663E\u793A\u8FC7\u65F6\u6A21\u578B",
|
|
1237
|
+
showDeprecatedHint: "\u9ED8\u8BA4\u5173\u95ED\u3002\u5F00\u542F\u540E\uFF0C\u7F51\u5173\u4ECD\u63D0\u4F9B\u7684\u8FC7\u65F6\u6A21\u578B\u4F1A\u7ACB\u5373\u52A0\u5165\u4F1A\u8BDD\u6A21\u578B\u5217\u8868\u3002",
|
|
1238
|
+
pickerFailed: "\u6A21\u578B\u663E\u793A\u8BBE\u7F6E\u672A\u66F4\u65B0\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
1239
|
+
deprecatedBadge: "\u5DF2\u5F03\u7528",
|
|
1240
|
+
deprecatedHint: "models.dev \u6807\u8BB0\u4E3A\u5DF2\u5F03\u7528\uFF0C\u5F53\u524D\u7F51\u5173\u4ECD\u63D0\u4F9B\u6B64\u6A21\u578B\u3002",
|
|
1241
|
+
newHint: "\u4F9D\u636E models.dev \u53D1\u5E03\u65E5\u671F\uFF0C\u8FD1\u4E03\u4E2A UTC \u65E5\u5386\u65E5\u5185\u53D1\u5E03\u3002",
|
|
1242
|
+
releasedOn: "{date} \u53D1\u5E03",
|
|
1243
|
+
releaseSource: "\u53D1\u5E03\u65E5\u671F\uFF1A{date} \xB7 models.dev",
|
|
1244
|
+
modelDetails: "\u6A21\u578B\u914D\u7F6E",
|
|
1245
|
+
filterLabel: "\u7B5B\u9009\u6A21\u578B",
|
|
1246
|
+
filterAll: "\u5168\u90E8",
|
|
1247
|
+
filterNew: "\u8FD1 7 \u5929\u53D1\u5E03",
|
|
1248
|
+
filterCustom: "\u5DF2\u81EA\u5B9A\u4E49",
|
|
1249
|
+
filterDeprecated: "\u8FC7\u65F6\u6A21\u578B",
|
|
1250
|
+
limitsResetModel: "\u4F7F\u7528\u76EE\u5F55\u503C",
|
|
1251
|
+
limitsResetAll: "\u6E05\u9664\u5168\u90E8\u8986\u76D6",
|
|
1252
|
+
limitsNoMatches: "\u6CA1\u6709\u5339\u914D\u201C{query}\u201D\u7684\u6A21\u578B\u3002\u8BF7\u5C1D\u8BD5\u5176\u4ED6\u540D\u79F0\u6216 ID\u3002",
|
|
1253
|
+
limitsEmpty: "\u8BF7\u5148\u8BFB\u53D6\u6A21\u578B\u5217\u8868\uFF1B\u5BB9\u91CF\u6309\u7F51\u5173\u63D0\u4F9B\u7684\u6A21\u578B\u9010\u4E2A\u7F16\u8F91\u3002",
|
|
1254
|
+
limitsContextLabel: "{name} \u7684\u4E0A\u4E0B\u6587\u7A97\u53E3",
|
|
1255
|
+
limitsOutputLabel: "{name} \u7684\u6700\u5927\u8F93\u51FA",
|
|
816
1256
|
advancedLabel: "\u9AD8\u7EA7\u8BBE\u7F6E",
|
|
817
1257
|
advancedHint: "\u51ED\u8BC1\u540D\u79F0\u3001\u7F51\u5173\u5730\u5740\u4E0E\u9002\u914D\u5668\u8C03\u4F18\u53C2\u6570\u3002\u7EE7\u627F\u6765\u7684\u53D6\u503C\u5373\u53EF\u6B63\u5E38\u4F7F\u7528\uFF0C\u9664\u975E\u4F60\u660E\u786E\u77E5\u9053\u9700\u8981\u4FEE\u6539\uFF0C\u5426\u5219\u4E0D\u5FC5\u52A8\u8FD9\u91CC\u3002",
|
|
818
1258
|
apiKeyEnvLabel: "\u51ED\u8BC1\u5F15\u7528\u540D",
|
|
@@ -873,8 +1313,14 @@ var usageRemote = {
|
|
|
873
1313
|
}]
|
|
874
1314
|
};
|
|
875
1315
|
|
|
1316
|
+
// src/remote-contract.ts
|
|
1317
|
+
var goRemote = {
|
|
1318
|
+
package: "dsh-opencode-go",
|
|
1319
|
+
descriptors: [...usageRemote.descriptors, ...modelsRemote.descriptors]
|
|
1320
|
+
};
|
|
1321
|
+
|
|
876
1322
|
// src/client/UsagePill.tsx
|
|
877
|
-
var
|
|
1323
|
+
var import_react3 = require("react");
|
|
878
1324
|
|
|
879
1325
|
// plugin-css:/Users/tanglei/Desktop/dsh-opencode-go/src/client/UsagePill.module.css
|
|
880
1326
|
var id2 = "dsh-opencode-go/UsagePill.module.css";
|
|
@@ -885,20 +1331,20 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
|
|
|
885
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}";
|
|
886
1332
|
document.head.appendChild(style);
|
|
887
1333
|
}
|
|
888
|
-
var UsagePill_default = { "
|
|
1334
|
+
var UsagePill_default = { "window": "dmPm3q_window", "row": "dmPm3q_row", "panel": "dmPm3q_panel", "hint": "dmPm3q_hint", "root": "dmPm3q_root", "trigger": "dmPm3q_trigger" };
|
|
889
1335
|
|
|
890
1336
|
// src/client/UsagePill.tsx
|
|
891
|
-
var
|
|
1337
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
892
1338
|
function UsagePill({ directory, ...props }) {
|
|
893
|
-
const state = (0,
|
|
894
|
-
return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0,
|
|
1339
|
+
const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
|
|
1340
|
+
return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActiveUsage, { ...props }) : null;
|
|
895
1341
|
}
|
|
896
1342
|
function ActiveUsage({ readUsage, t }) {
|
|
897
|
-
const [usage, setUsage] = (0,
|
|
898
|
-
const [failed, setFailed] = (0,
|
|
899
|
-
const [open, setOpen] = (0,
|
|
900
|
-
const root = (0,
|
|
901
|
-
(0,
|
|
1343
|
+
const [usage, setUsage] = (0, import_react3.useState)(null);
|
|
1344
|
+
const [failed, setFailed] = (0, import_react3.useState)(false);
|
|
1345
|
+
const [open, setOpen] = (0, import_react3.useState)(false);
|
|
1346
|
+
const root = (0, import_react3.useRef)(null);
|
|
1347
|
+
(0, import_react3.useEffect)(() => {
|
|
902
1348
|
let alive = true;
|
|
903
1349
|
let busy = false;
|
|
904
1350
|
const refresh = async () => {
|
|
@@ -933,7 +1379,7 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
933
1379
|
document.removeEventListener("visibilitychange", visible);
|
|
934
1380
|
};
|
|
935
1381
|
}, [readUsage]);
|
|
936
|
-
(0,
|
|
1382
|
+
(0, import_react3.useEffect)(() => {
|
|
937
1383
|
if (!open) return;
|
|
938
1384
|
const click = (event) => {
|
|
939
1385
|
if (!root.current?.contains(event.target)) setOpen(false);
|
|
@@ -949,8 +1395,8 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
949
1395
|
};
|
|
950
1396
|
}, [open]);
|
|
951
1397
|
const label = usage ? `Go \xB7 5h ${usage.rolling.percent}% \xB7 ${t("usageWeekShort")} ${usage.weekly.percent}%` : `Go \xB7 ${failed ? t("usageUnavailable") : "\u2026"}`;
|
|
952
|
-
return /* @__PURE__ */ (0,
|
|
953
|
-
/* @__PURE__ */ (0,
|
|
1398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
954
1400
|
"button",
|
|
955
1401
|
{
|
|
956
1402
|
type: "button",
|
|
@@ -964,25 +1410,25 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
964
1410
|
children: label
|
|
965
1411
|
}
|
|
966
1412
|
),
|
|
967
|
-
open && /* @__PURE__ */ (0,
|
|
968
|
-
/* @__PURE__ */ (0,
|
|
969
|
-
/* @__PURE__ */ (0,
|
|
970
|
-
usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0,
|
|
971
|
-
/* @__PURE__ */ (0,
|
|
972
|
-
/* @__PURE__ */ (0,
|
|
973
|
-
/* @__PURE__ */ (0,
|
|
1413
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), children: [
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageTitle") }),
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: UsagePill_default.hint, children: t("usageHint") }),
|
|
1416
|
+
usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.window, children: [
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.row, children: [
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t(`usage_${key}`) }),
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("strong", { children: [
|
|
974
1420
|
usage[key].percent,
|
|
975
1421
|
"%"
|
|
976
1422
|
] })
|
|
977
1423
|
] }),
|
|
978
|
-
/* @__PURE__ */ (0,
|
|
979
|
-
/* @__PURE__ */ (0,
|
|
1424
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("progress", { "aria-label": t(`usage_${key}`), max: 100, value: Math.min(100, usage[key].percent) }),
|
|
1425
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.hint, children: [
|
|
980
1426
|
t("usageResets"),
|
|
981
1427
|
" ",
|
|
982
1428
|
new Date(usage[key].resetsAt).toLocaleString()
|
|
983
1429
|
] }),
|
|
984
|
-
usage[key].status === "rate-limited" && /* @__PURE__ */ (0,
|
|
985
|
-
] }, key)) : /* @__PURE__ */ (0,
|
|
1430
|
+
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: failed ? t("usageUnavailable") : t("usageLoading") })
|
|
986
1432
|
] })
|
|
987
1433
|
] });
|
|
988
1434
|
}
|
|
@@ -990,42 +1436,52 @@ function ActiveUsage({ readUsage, t }) {
|
|
|
990
1436
|
// src/client/usage.ts
|
|
991
1437
|
function registerUsagePill(ctx) {
|
|
992
1438
|
ctx.inject(["modelDirectories", "sessions", "remote.session"], (scope) => {
|
|
993
|
-
scope.
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
})
|
|
1011
|
-
}, UsagePill));
|
|
1012
|
-
});
|
|
1013
|
-
return unmount;
|
|
1439
|
+
scope.inject(["remote.opencodeGoUsage"], (ready) => {
|
|
1440
|
+
const readUsage = async () => {
|
|
1441
|
+
const result = await ready.remote.opencodeGoUsage.read();
|
|
1442
|
+
if (!result.ok) throw new Error("OpenCode Go usage unavailable");
|
|
1443
|
+
return result.value;
|
|
1444
|
+
};
|
|
1445
|
+
const translate = ready.locale.bind("settings.opencode-go");
|
|
1446
|
+
ready.slots.inject("conversation.input.right", () => ready.slots.register({
|
|
1447
|
+
name: "conversation.input.right",
|
|
1448
|
+
id: "opencode-go-usage",
|
|
1449
|
+
order: 1e3,
|
|
1450
|
+
inject: (sessionId) => ({
|
|
1451
|
+
directory: ready.modelDirectories.directoryFor(sessionId).store,
|
|
1452
|
+
readUsage,
|
|
1453
|
+
t: (key) => translate(key)
|
|
1454
|
+
})
|
|
1455
|
+
}, UsagePill));
|
|
1014
1456
|
});
|
|
1015
1457
|
});
|
|
1016
1458
|
}
|
|
1017
1459
|
|
|
1018
1460
|
// src/client/index.ts
|
|
1019
1461
|
var NS = "settings.opencode-go";
|
|
1020
|
-
var inject = ["slots", "locale", "remote", "remote.credentials", "remote.llm"
|
|
1462
|
+
var inject = ["slots", "locale", "remote", "remote.credentials", "remote.llm"];
|
|
1021
1463
|
function apply(ctx) {
|
|
1022
1464
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "llm-opencode-go: copy dictionaries");
|
|
1023
1465
|
registerUsagePill(ctx);
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
|
|
1466
|
+
const modelsReady = ctx.remote.$mount(goRemote);
|
|
1467
|
+
ctx.effect(async () => await modelsReady);
|
|
1468
|
+
ctx.inject(["configForms", "remote.opencodeGoModels"], (child) => {
|
|
1469
|
+
const forms = child.get("configForms");
|
|
1470
|
+
mountSettings(child, forms.get("opencode-go"), modelsReady);
|
|
1471
|
+
});
|
|
1472
|
+
ctx.inject(["settingsScope", "remote.opencodeGoModels"], (child) => {
|
|
1473
|
+
mountSettings(child, child.settingsScope.bind({
|
|
1474
|
+
namespace: "llm-opencode-go",
|
|
1475
|
+
decode: (section) => typeof section === "object" && section !== null ? section : void 0
|
|
1476
|
+
}), modelsReady);
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
function mountSettings(ctx, scope, modelsReady) {
|
|
1480
|
+
const controller = new OpencodeGoSectionController(scope, ctx, async () => {
|
|
1481
|
+
await modelsReady;
|
|
1482
|
+
return ctx.remote.opencodeGoModels.read();
|
|
1027
1483
|
});
|
|
1028
|
-
|
|
1484
|
+
ctx.effect(() => () => controller.dispose());
|
|
1029
1485
|
const t = ctx.locale.bind(NS);
|
|
1030
1486
|
const injected = () => ({ ...controller.inject(), t });
|
|
1031
1487
|
ctx.effect(() => {
|