@dan-ai-studio/dshopencodego 0.1.5
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/LICENSE +21 -0
- package/README.en.md +156 -0
- package/README.md +156 -0
- package/cordis.patch.yml +3 -0
- package/lib/build-info.json +11 -0
- package/lib/client.js +1215 -0
- package/lib/index.js +2036 -0
- package/lib/types/adapter.d.ts +84 -0
- package/lib/types/adapter.js +311 -0
- package/lib/types/catalog/constants.d.ts +16 -0
- package/lib/types/catalog/constants.js +16 -0
- package/lib/types/catalog/contract.d.ts +26 -0
- package/lib/types/catalog/contract.js +131 -0
- package/lib/types/catalog/gateway.d.ts +20 -0
- package/lib/types/catalog/gateway.js +59 -0
- package/lib/types/catalog/index.d.ts +108 -0
- package/lib/types/catalog/index.js +288 -0
- package/lib/types/catalog/json-response.d.ts +19 -0
- package/lib/types/catalog/json-response.js +72 -0
- package/lib/types/catalog/metadata.d.ts +73 -0
- package/lib/types/catalog/metadata.js +259 -0
- package/lib/types/catalog/protocol.d.ts +65 -0
- package/lib/types/catalog/protocol.js +87 -0
- package/lib/types/catalog/reading.d.ts +41 -0
- package/lib/types/catalog/reading.js +68 -0
- package/lib/types/catalog/service.d.ts +32 -0
- package/lib/types/catalog/service.js +45 -0
- package/lib/types/config.d.ts +93 -0
- package/lib/types/config.js +76 -0
- package/lib/types/conversion/context.d.ts +55 -0
- package/lib/types/conversion/context.js +202 -0
- package/lib/types/conversion/index.d.ts +9 -0
- package/lib/types/conversion/index.js +7 -0
- package/lib/types/conversion/replay.d.ts +56 -0
- package/lib/types/conversion/replay.js +242 -0
- package/lib/types/conversion/stream.d.ts +46 -0
- package/lib/types/conversion/stream.js +203 -0
- package/lib/types/go-limits.d.ts +41 -0
- package/lib/types/go-limits.js +79 -0
- package/lib/types/index.d.ts +54 -0
- package/lib/types/index.js +195 -0
- package/lib/types/models.d.ts +90 -0
- package/lib/types/models.js +86 -0
- package/lib/types/remotes.d.ts +12 -0
- package/lib/types/remotes.js +28 -0
- package/lib/types/session-header.d.ts +36 -0
- package/lib/types/session-header.js +45 -0
- package/lib/types/usage/contract.d.ts +39 -0
- package/lib/types/usage/contract.js +106 -0
- package/lib/types/usage/index.d.ts +11 -0
- package/lib/types/usage/index.js +8 -0
- package/lib/types/usage/meter.d.ts +53 -0
- package/lib/types/usage/meter.js +65 -0
- package/lib/types/usage/service.d.ts +48 -0
- package/lib/types/usage/service.js +74 -0
- package/lib/types/usage/windows.d.ts +51 -0
- package/lib/types/usage/windows.js +84 -0
- package/package.json +147 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,1215 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: "@dan-ai-studio/dshopencodego", factory: (require) => { var module = { exports: {} }; var exports = module.exports;
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/client/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
apply: () => apply,
|
|
25
|
+
inject: () => inject
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/catalog/contract.ts
|
|
30
|
+
function parseGoQuota(value) {
|
|
31
|
+
if (value === null || typeof value !== "object") throw new Error("invalid go quota");
|
|
32
|
+
const row = value;
|
|
33
|
+
const usd = row["monthlyUsd"];
|
|
34
|
+
if (usd !== "unlimited" && (typeof usd !== "number" || !Number.isFinite(usd))) {
|
|
35
|
+
throw new Error("invalid go quota monthlyUsd");
|
|
36
|
+
}
|
|
37
|
+
const requests = row["monthlyRequests"];
|
|
38
|
+
if (requests !== void 0 && requests !== "unlimited" && (typeof requests !== "number" || !Number.isFinite(requests))) {
|
|
39
|
+
throw new Error("invalid go quota monthlyRequests");
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
monthlyUsd: usd,
|
|
43
|
+
...requests === void 0 ? {} : { monthlyRequests: requests }
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function parseCost(value) {
|
|
47
|
+
if (value === null || typeof value !== "object") throw new Error("invalid model cost");
|
|
48
|
+
const row = value;
|
|
49
|
+
const rate = (key) => {
|
|
50
|
+
const entry = row[key];
|
|
51
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) throw new Error(`invalid model cost "${key}"`);
|
|
52
|
+
return entry;
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
input: rate("input"),
|
|
56
|
+
output: rate("output"),
|
|
57
|
+
...typeof row["cacheRead"] === "number" ? { cacheRead: rate("cacheRead") } : {},
|
|
58
|
+
...typeof row["cacheWrite"] === "number" ? { cacheWrite: rate("cacheWrite") } : {}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function parseModel(value) {
|
|
62
|
+
if (value === null || typeof value !== "object") throw new Error("invalid catalog model");
|
|
63
|
+
const row = value;
|
|
64
|
+
if (typeof row["id"] !== "string" || row["id"].length === 0) throw new Error("invalid catalog model id");
|
|
65
|
+
return {
|
|
66
|
+
id: row["id"],
|
|
67
|
+
name: typeof row["name"] === "string" ? row["name"] : row["id"],
|
|
68
|
+
...typeof row["contextWindow"] === "number" ? { contextWindow: row["contextWindow"] } : {},
|
|
69
|
+
...typeof row["maxInputTokens"] === "number" ? { maxInputTokens: row["maxInputTokens"] } : {},
|
|
70
|
+
...typeof row["maxTokens"] === "number" ? { maxTokens: row["maxTokens"] } : {},
|
|
71
|
+
...typeof row["deprecated"] === "boolean" ? { deprecated: row["deprecated"] } : {},
|
|
72
|
+
...typeof row["releaseDate"] === "string" ? { releaseDate: row["releaseDate"] } : {},
|
|
73
|
+
...row["goQuota"] === void 0 ? {} : { goQuota: parseGoQuota(row["goQuota"]) },
|
|
74
|
+
...row["cost"] === void 0 ? {} : { cost: parseCost(row["cost"]) },
|
|
75
|
+
...row["protocolSource"] === "builtin" || row["protocolSource"] === "online" || row["protocolSource"] === "inferred" || row["protocolSource"] === "override" ? { protocolSource: row["protocolSource"] } : {},
|
|
76
|
+
...typeof row["assumedLimits"] === "boolean" ? { assumedLimits: row["assumedLimits"] } : {},
|
|
77
|
+
...typeof row["configurationMissing"] === "string" ? { configurationMissing: row["configurationMissing"] } : {}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function parseCatalogReading(value) {
|
|
81
|
+
if (value === null || typeof value !== "object") throw new Error("invalid catalog reading");
|
|
82
|
+
const row = value;
|
|
83
|
+
const counts = row["counts"];
|
|
84
|
+
if (!Array.isArray(row["models"]) || typeof row["stale"] !== "boolean" || typeof row["fetchedAtMs"] !== "number" || counts === null || typeof counts !== "object") {
|
|
85
|
+
throw new Error("invalid catalog reading");
|
|
86
|
+
}
|
|
87
|
+
const numbers = counts;
|
|
88
|
+
const count = (key) => {
|
|
89
|
+
const entry = numbers[key];
|
|
90
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) throw new Error(`invalid catalog count "${key}"`);
|
|
91
|
+
return entry;
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
models: row["models"].map(parseModel),
|
|
95
|
+
stale: row["stale"],
|
|
96
|
+
...typeof row["error"] === "string" ? { error: row["error"] } : {},
|
|
97
|
+
fetchedAtMs: row["fetchedAtMs"],
|
|
98
|
+
counts: {
|
|
99
|
+
total: count("total"),
|
|
100
|
+
enabled: count("enabled"),
|
|
101
|
+
deprecated: count("deprecated"),
|
|
102
|
+
unconfigured: count("unconfigured"),
|
|
103
|
+
inferred: count("inferred")
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
var codec = {
|
|
108
|
+
mode: "strict",
|
|
109
|
+
typeSymbol: "@dan-ai-studio/dshopencodego#CatalogReading",
|
|
110
|
+
schema: { parse: parseCatalogReading },
|
|
111
|
+
create: () => ({ parse: parseCatalogReading })
|
|
112
|
+
};
|
|
113
|
+
var catalogRemote = {
|
|
114
|
+
package: "@dan-ai-studio/dshopencodego",
|
|
115
|
+
descriptors: [
|
|
116
|
+
{
|
|
117
|
+
id: "@dan-ai-studio/dshopencodego#opencodeGoCatalog/read",
|
|
118
|
+
service: "opencodeGoCatalog",
|
|
119
|
+
namespace: "opencodeGoCatalog",
|
|
120
|
+
method: "read",
|
|
121
|
+
invocation: { kind: "direct" },
|
|
122
|
+
parameters: [],
|
|
123
|
+
result: codec
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "@dan-ai-studio/dshopencodego#opencodeGoCatalog/refresh",
|
|
127
|
+
service: "opencodeGoCatalog",
|
|
128
|
+
namespace: "opencodeGoCatalog",
|
|
129
|
+
method: "refresh",
|
|
130
|
+
invocation: { kind: "direct" },
|
|
131
|
+
parameters: [],
|
|
132
|
+
result: codec
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// src/usage/contract.ts
|
|
138
|
+
function parseWindow(value, key) {
|
|
139
|
+
if (value === null || typeof value !== "object") throw new Error(`invalid usage window "${key}"`);
|
|
140
|
+
const row = value;
|
|
141
|
+
if (row["status"] !== "ok" && row["status"] !== "rate-limited" || typeof row["percent"] !== "number" || !Number.isFinite(row["percent"]) || typeof row["resetsAt"] !== "string") {
|
|
142
|
+
throw new Error(`invalid usage window "${key}"`);
|
|
143
|
+
}
|
|
144
|
+
return { status: row["status"], percent: row["percent"], resetsAt: row["resetsAt"] };
|
|
145
|
+
}
|
|
146
|
+
function parseUsageWindows(value) {
|
|
147
|
+
if (value === null || typeof value !== "object") throw new Error("invalid usage reading");
|
|
148
|
+
const row = value;
|
|
149
|
+
return {
|
|
150
|
+
...typeof row["source"] === "string" ? { source: row["source"] } : {},
|
|
151
|
+
rolling: parseWindow(row["rolling"], "rolling"),
|
|
152
|
+
weekly: parseWindow(row["weekly"], "weekly"),
|
|
153
|
+
monthly: parseWindow(row["monthly"], "monthly")
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function parseTotals(value) {
|
|
157
|
+
if (value === null || typeof value !== "object") throw new Error("invalid meter totals");
|
|
158
|
+
const row = value;
|
|
159
|
+
const count = (key) => {
|
|
160
|
+
const entry = row[key];
|
|
161
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) throw new Error(`invalid meter field "${key}"`);
|
|
162
|
+
return entry;
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
calls: count("calls"),
|
|
166
|
+
inputTokens: count("inputTokens"),
|
|
167
|
+
outputTokens: count("outputTokens"),
|
|
168
|
+
cacheReadTokens: count("cacheReadTokens"),
|
|
169
|
+
cacheWriteTokens: count("cacheWriteTokens"),
|
|
170
|
+
totalTokens: count("totalTokens")
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function parseGoMeter(value) {
|
|
174
|
+
if (value === null || typeof value !== "object") throw new Error("invalid meter reading");
|
|
175
|
+
const row = value;
|
|
176
|
+
if (typeof row["sinceMs"] !== "number" || typeof row["atMs"] !== "number" || !Array.isArray(row["models"])) {
|
|
177
|
+
throw new Error("invalid meter reading");
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
sinceMs: row["sinceMs"],
|
|
181
|
+
atMs: row["atMs"],
|
|
182
|
+
totals: parseTotals(row["totals"]),
|
|
183
|
+
models: row["models"].map((entry) => {
|
|
184
|
+
if (entry === null || typeof entry !== "object") throw new Error("invalid meter model entry");
|
|
185
|
+
const model = entry["model"];
|
|
186
|
+
if (typeof model !== "string") throw new Error("invalid meter model entry");
|
|
187
|
+
return { model, ...parseTotals(entry) };
|
|
188
|
+
})
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
var codec2 = (typeSymbol, parse) => ({
|
|
192
|
+
mode: "strict",
|
|
193
|
+
typeSymbol,
|
|
194
|
+
schema: { parse },
|
|
195
|
+
create: () => ({ parse })
|
|
196
|
+
});
|
|
197
|
+
var usageRemote = {
|
|
198
|
+
package: "@dan-ai-studio/dshopencodego",
|
|
199
|
+
descriptors: [
|
|
200
|
+
{
|
|
201
|
+
id: "@dan-ai-studio/dshopencodego#opencodeGoUsage/readWindows",
|
|
202
|
+
service: "opencodeGoUsage",
|
|
203
|
+
namespace: "opencodeGoUsage",
|
|
204
|
+
method: "readWindows",
|
|
205
|
+
invocation: { kind: "direct" },
|
|
206
|
+
parameters: [],
|
|
207
|
+
result: codec2("@dan-ai-studio/dshopencodego#GoUsageWindows", parseUsageWindows)
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: "@dan-ai-studio/dshopencodego#opencodeGoUsage/readMeter",
|
|
211
|
+
service: "opencodeGoUsage",
|
|
212
|
+
namespace: "opencodeGoUsage",
|
|
213
|
+
method: "readMeter",
|
|
214
|
+
invocation: { kind: "direct" },
|
|
215
|
+
parameters: [],
|
|
216
|
+
result: codec2("@dan-ai-studio/dshopencodego#GoMeter", parseGoMeter)
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// src/client/locales.ts
|
|
222
|
+
var en = {
|
|
223
|
+
nav: "OpenCode Go",
|
|
224
|
+
intro: "OpenCode Go models come from the gateway itself, and every request carries a per-conversation session id.",
|
|
225
|
+
keyTitle: "API key",
|
|
226
|
+
keyHint: "Stored write-only in the Harness credential store under OPENCODE_GO_API_KEY.",
|
|
227
|
+
keyConfigured: "Configured",
|
|
228
|
+
keyMissing: "Not configured",
|
|
229
|
+
keyPlaceholder: "Paste the OpenCode Go API key",
|
|
230
|
+
keySave: "Save key",
|
|
231
|
+
keyClear: "Remove key",
|
|
232
|
+
keySaved: "Saved",
|
|
233
|
+
catalogTitle: "Models",
|
|
234
|
+
catalogRefresh: "Refresh",
|
|
235
|
+
catalogSelectAll: "Select all",
|
|
236
|
+
catalogSelectNone: "Select none",
|
|
237
|
+
catalogStale: "Showing the last successful listing",
|
|
238
|
+
catalogCountUnit: "models",
|
|
239
|
+
catalogInferred: "protocol inferred",
|
|
240
|
+
catalogAssumed: "default capacities",
|
|
241
|
+
catalogDeprecated: "deprecated",
|
|
242
|
+
catalogUnconfigured: "not configurable",
|
|
243
|
+
refreshLabel: "Catalog refresh (minutes)",
|
|
244
|
+
refreshHint: "How long requests and the model picker reuse one listing.",
|
|
245
|
+
writeRejected: "The settings write was rejected (the namespace was reloaded) \u2014 try again",
|
|
246
|
+
writeFailed: "The settings write failed",
|
|
247
|
+
filterPlaceholder: "Filter by name or id",
|
|
248
|
+
filterOnlyEnabled: "Enabled only",
|
|
249
|
+
filterShowDeprecated: "Show deprecated",
|
|
250
|
+
filterHidden: "hidden",
|
|
251
|
+
sortLabel: "Sort",
|
|
252
|
+
sortDefault: "New first",
|
|
253
|
+
sortReleased: "Release date",
|
|
254
|
+
sortName: "Name",
|
|
255
|
+
sortContext: "Context window",
|
|
256
|
+
sortEnabled: "Enabled first",
|
|
257
|
+
sortQuota: "Monthly requests",
|
|
258
|
+
sortPrice: "Input price",
|
|
259
|
+
viewList: "List",
|
|
260
|
+
viewTable: "Table",
|
|
261
|
+
headerModel: "Model",
|
|
262
|
+
headerId: "ID",
|
|
263
|
+
headerReleased: "Released",
|
|
264
|
+
headerCapacity: "Context",
|
|
265
|
+
headerIo: "In / Out",
|
|
266
|
+
headerPrice: "Price /1M",
|
|
267
|
+
headerQuota: "Go quota",
|
|
268
|
+
headerNotes: "Notes",
|
|
269
|
+
iosInput: "in",
|
|
270
|
+
iosOutput: "out",
|
|
271
|
+
iosContext: "ctx",
|
|
272
|
+
quotaPerMonth: "req/mo",
|
|
273
|
+
quotaUnlimited: "unlimited",
|
|
274
|
+
usageTitle: "OpenCode Go usage",
|
|
275
|
+
usageRolling: "5 hours",
|
|
276
|
+
usageWeekly: "Week",
|
|
277
|
+
usageMonthly: "Month",
|
|
278
|
+
usageResets: "Resets",
|
|
279
|
+
usageLimited: "rate limited",
|
|
280
|
+
usageUnavailable: "unavailable",
|
|
281
|
+
usageStale: "stale",
|
|
282
|
+
usageRetry: "Retry",
|
|
283
|
+
usageRefreshing: "Refreshing\u2026",
|
|
284
|
+
usageLastUpdated: "Updated",
|
|
285
|
+
usageSinceBoot: "Since this Harness started",
|
|
286
|
+
usageCallsUnit: "calls",
|
|
287
|
+
usageTokensUnit: "tokens",
|
|
288
|
+
usageCached: "cached read",
|
|
289
|
+
usageLocalHint: "The gateway publishes quota percentages only; token counts are what this process actually spent.",
|
|
290
|
+
usageLoading: "Loading\u2026"
|
|
291
|
+
};
|
|
292
|
+
var zh = {
|
|
293
|
+
nav: "OpenCode Go",
|
|
294
|
+
intro: "OpenCode Go \u7684\u6A21\u578B\u5217\u8868\u76F4\u63A5\u6765\u81EA\u7F51\u5173\uFF0C\u4E14\u6BCF\u4E2A\u8BF7\u6C42\u90FD\u4F1A\u643A\u5E26\u6309\u4F1A\u8BDD\u7A33\u5B9A\u7684\u4F1A\u8BDD ID\u3002",
|
|
295
|
+
keyTitle: "API Key",
|
|
296
|
+
keyHint: "\u4EE5\u53EA\u5199\u65B9\u5F0F\u4FDD\u5B58\u5728 Harness \u51ED\u8BC1\u5E93\u4E2D\uFF0C\u5F15\u7528\u540D\u4E3A OPENCODE_GO_API_KEY\u3002",
|
|
297
|
+
keyConfigured: "\u5DF2\u914D\u7F6E",
|
|
298
|
+
keyMissing: "\u672A\u914D\u7F6E",
|
|
299
|
+
keyPlaceholder: "\u7C98\u8D34 OpenCode Go API Key",
|
|
300
|
+
keySave: "\u4FDD\u5B58 Key",
|
|
301
|
+
keyClear: "\u79FB\u9664 Key",
|
|
302
|
+
keySaved: "\u5DF2\u4FDD\u5B58",
|
|
303
|
+
catalogTitle: "\u6A21\u578B",
|
|
304
|
+
catalogRefresh: "\u5237\u65B0",
|
|
305
|
+
catalogSelectAll: "\u5168\u9009",
|
|
306
|
+
catalogSelectNone: "\u5168\u4E0D\u9009",
|
|
307
|
+
catalogStale: "\u5F53\u524D\u663E\u793A\u7684\u662F\u4E0A\u6B21\u6210\u529F\u83B7\u53D6\u7684\u5217\u8868",
|
|
308
|
+
catalogCountUnit: "\u4E2A\u6A21\u578B",
|
|
309
|
+
catalogInferred: "\u534F\u8BAE\u4E3A\u63A8\u65AD",
|
|
310
|
+
catalogAssumed: "\u5BB9\u91CF\u4E3A\u9ED8\u8BA4\u503C",
|
|
311
|
+
catalogDeprecated: "\u5DF2\u5F03\u7528",
|
|
312
|
+
catalogUnconfigured: "\u65E0\u6CD5\u914D\u7F6E",
|
|
313
|
+
refreshLabel: "\u76EE\u5F55\u5237\u65B0\uFF08\u5206\u949F\uFF09",
|
|
314
|
+
refreshHint: "\u8BF7\u6C42\u4E0E\u6A21\u578B\u9009\u62E9\u5668\u590D\u7528\u540C\u4E00\u4EFD\u5217\u8868\u7684\u65F6\u957F\u3002",
|
|
315
|
+
writeRejected: "\u8BBE\u7F6E\u5199\u5165\u88AB\u62D2\u7EDD\uFF08\u5DF2\u91CD\u65B0\u8F7D\u5165\uFF09\uFF0C\u8BF7\u91CD\u8BD5",
|
|
316
|
+
writeFailed: "\u8BBE\u7F6E\u5199\u5165\u5931\u8D25",
|
|
317
|
+
filterPlaceholder: "\u6309\u540D\u79F0\u6216 ID \u7B5B\u9009",
|
|
318
|
+
filterOnlyEnabled: "\u4EC5\u663E\u793A\u5DF2\u542F\u7528",
|
|
319
|
+
filterShowDeprecated: "\u663E\u793A\u5DF2\u5F03\u7528",
|
|
320
|
+
filterHidden: "\u5DF2\u9690\u85CF",
|
|
321
|
+
sortLabel: "\u6392\u5E8F",
|
|
322
|
+
sortDefault: "\u65B0\u53D1\u5E03\u4F18\u5148",
|
|
323
|
+
sortReleased: "\u53D1\u5E03\u65F6\u95F4",
|
|
324
|
+
sortName: "\u540D\u79F0",
|
|
325
|
+
sortContext: "\u4E0A\u4E0B\u6587\u7A97\u53E3",
|
|
326
|
+
sortEnabled: "\u5DF2\u542F\u7528\u4F18\u5148",
|
|
327
|
+
sortQuota: "\u6BCF\u6708\u9884\u4F30\u6B21\u6570",
|
|
328
|
+
sortPrice: "\u8F93\u5165\u5355\u4EF7",
|
|
329
|
+
viewList: "\u5217\u8868",
|
|
330
|
+
viewTable: "\u8868\u683C",
|
|
331
|
+
headerModel: "\u6A21\u578B",
|
|
332
|
+
headerId: "ID",
|
|
333
|
+
headerReleased: "\u53D1\u5E03",
|
|
334
|
+
headerCapacity: "\u4E0A\u4E0B\u6587",
|
|
335
|
+
headerIo: "\u8F93\u5165 / \u8F93\u51FA",
|
|
336
|
+
headerPrice: "\u5355\u4EF7 /1M",
|
|
337
|
+
headerQuota: "Go \u989D\u5EA6",
|
|
338
|
+
headerNotes: "\u5907\u6CE8",
|
|
339
|
+
iosInput: "\u5165",
|
|
340
|
+
iosOutput: "\u51FA",
|
|
341
|
+
iosContext: "\u4E0A\u4E0B\u6587",
|
|
342
|
+
quotaPerMonth: "\u6B21/\u6708",
|
|
343
|
+
quotaUnlimited: "\u65E0\u9650\u5236",
|
|
344
|
+
usageTitle: "OpenCode Go \u7528\u91CF",
|
|
345
|
+
usageRolling: "5 \u5C0F\u65F6",
|
|
346
|
+
usageWeekly: "\u672C\u5468",
|
|
347
|
+
usageMonthly: "\u672C\u6708",
|
|
348
|
+
usageResets: "\u91CD\u7F6E",
|
|
349
|
+
usageLimited: "\u5DF2\u9650\u6D41",
|
|
350
|
+
usageUnavailable: "\u4E0D\u53EF\u7528",
|
|
351
|
+
usageStale: "\u9648\u65E7",
|
|
352
|
+
usageRetry: "\u91CD\u8BD5",
|
|
353
|
+
usageRefreshing: "\u5237\u65B0\u4E2D\u2026",
|
|
354
|
+
usageLastUpdated: "\u66F4\u65B0\u4E8E",
|
|
355
|
+
usageSinceBoot: "\u81EA\u672C\u6B21 Harness \u542F\u52A8\u4EE5\u6765",
|
|
356
|
+
usageCallsUnit: "\u6B21\u8C03\u7528",
|
|
357
|
+
usageTokensUnit: "tokens",
|
|
358
|
+
usageCached: "\u7F13\u5B58\u8BFB\u53D6",
|
|
359
|
+
usageLocalHint: "\u7F51\u5173\u53EA\u516C\u5E03\u989D\u5EA6\u767E\u5206\u6BD4\uFF1Btoken \u6570\u4E3A\u672C\u8FDB\u7A0B\u5B9E\u9645\u6D88\u8017\u3002",
|
|
360
|
+
usageLoading: "\u52A0\u8F7D\u4E2D\u2026"
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// src/client/Section.tsx
|
|
364
|
+
var import_react = require("react");
|
|
365
|
+
|
|
366
|
+
// src/go-limits.ts
|
|
367
|
+
function monthlyRequestsRank(quota) {
|
|
368
|
+
if (quota === void 0) return -1;
|
|
369
|
+
const requests = quota.monthlyRequests;
|
|
370
|
+
if (requests === "unlimited") return Number.MAX_SAFE_INTEGER;
|
|
371
|
+
if (requests === void 0) return quota.monthlyUsd === "unlimited" ? Number.MAX_SAFE_INTEGER : -1;
|
|
372
|
+
return requests;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/models.ts
|
|
376
|
+
function isModelEnabled(model, visibility) {
|
|
377
|
+
if (model.configurationMissing !== void 0) return false;
|
|
378
|
+
const explicit = visibility !== void 0 && Object.hasOwn(visibility, model.id) ? visibility[model.id] : void 0;
|
|
379
|
+
if (typeof explicit === "boolean") return explicit;
|
|
380
|
+
return typeof model.recommended === "boolean" ? model.recommended : model.deprecated !== true;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/client/model-view.ts
|
|
384
|
+
var INITIAL_FILTER = {
|
|
385
|
+
query: "",
|
|
386
|
+
showDeprecated: false,
|
|
387
|
+
onlyEnabled: false,
|
|
388
|
+
sort: "quota",
|
|
389
|
+
view: "list"
|
|
390
|
+
};
|
|
391
|
+
function compactCount(value) {
|
|
392
|
+
if (value >= 1e6) return `${(value / 1e6).toFixed(value >= 1e7 ? 0 : 1)}M`;
|
|
393
|
+
if (value >= 1e3) return `${Math.round(value / 1e3)}K`;
|
|
394
|
+
return String(value);
|
|
395
|
+
}
|
|
396
|
+
function compareDateDesc(left, right) {
|
|
397
|
+
const a = left ?? "";
|
|
398
|
+
const b = right ?? "";
|
|
399
|
+
if (a === b) return 0;
|
|
400
|
+
if (a === "") return 1;
|
|
401
|
+
if (b === "") return -1;
|
|
402
|
+
return b.localeCompare(a);
|
|
403
|
+
}
|
|
404
|
+
function sortRows(rows, sort, visibility, locale) {
|
|
405
|
+
if (sort === "default") return [...rows];
|
|
406
|
+
const byName = (left, right) => left.name.localeCompare(right.name, locale);
|
|
407
|
+
const copy = [...rows];
|
|
408
|
+
switch (sort) {
|
|
409
|
+
case "released":
|
|
410
|
+
return copy.sort((left, right) => compareDateDesc(left.releaseDate, right.releaseDate) || byName(left, right));
|
|
411
|
+
case "name":
|
|
412
|
+
return copy.sort(byName);
|
|
413
|
+
case "context":
|
|
414
|
+
return copy.sort((left, right) => (right.contextWindow ?? -1) - (left.contextWindow ?? -1) || byName(left, right));
|
|
415
|
+
case "enabled":
|
|
416
|
+
return copy.sort((left, right) => Number(isModelEnabled(right, visibility)) - Number(isModelEnabled(left, visibility)) || byName(left, right));
|
|
417
|
+
case "quota":
|
|
418
|
+
return copy.sort((left, right) => monthlyRequestsRank(right.goQuota) - monthlyRequestsRank(left.goQuota) || byName(left, right));
|
|
419
|
+
case "price":
|
|
420
|
+
return copy.sort((left, right) => (left.cost?.input ?? Number.MAX_SAFE_INTEGER) - (right.cost?.input ?? Number.MAX_SAFE_INTEGER) || (left.cost?.output ?? 0) - (right.cost?.output ?? 0) || byName(left, right));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function visibleModels(models, filter, visibility, locale) {
|
|
424
|
+
const needle = filter.query.trim().toLowerCase();
|
|
425
|
+
const rows = models.filter((model) => {
|
|
426
|
+
if (!filter.showDeprecated && model.deprecated === true) return false;
|
|
427
|
+
if (filter.onlyEnabled && !isModelEnabled(model, visibility)) return false;
|
|
428
|
+
if (needle.length === 0) return true;
|
|
429
|
+
return model.id.toLowerCase().includes(needle) || model.name.toLowerCase().includes(needle);
|
|
430
|
+
});
|
|
431
|
+
return sortRows(rows, filter.sort, visibility, locale);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// plugin-css:D:\prj\dshopencodego\src\client\section.module.css
|
|
435
|
+
var id = "@dan-ai-studio/dshopencodego/section.module.css";
|
|
436
|
+
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")) {
|
|
437
|
+
const style = document.createElement("style");
|
|
438
|
+
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
439
|
+
style.dataset.pluginCss = id;
|
|
440
|
+
style.textContent = "._6tq0da_root{color:var(--dsw-alias-label-primary);flex-direction:column;gap:1.25rem;display:flex}._6tq0da_title{margin:0;font-size:1.05rem}._6tq0da_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:.8rem}._6tq0da_warn{color:var(--dsw-alias-state-warn-primary);margin:0;font-size:.8rem}._6tq0da_ok{color:var(--dsw-alias-state-success-primary);font-size:.8rem}._6tq0da_block{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:.6rem;flex-direction:column;gap:.5rem;padding:.85rem;display:flex}._6tq0da_row{flex-wrap:wrap;align-items:center;gap:.5rem;display:flex}._6tq0da_row>strong{margin-right:auto}._6tq0da_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);min-width:10rem;color:var(--dsw-alias-label-primary);font:inherit;border-radius:.35rem;flex:14rem;padding:.35rem .5rem;font-size:.85rem}._6tq0da_button{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:.35rem;padding:.35rem .7rem;font-size:.8rem}._6tq0da_button:disabled{color:var(--dsw-alias-state-idle-primary);cursor:default}._6tq0da_number{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:5rem;color:var(--dsw-alias-label-primary);font:inherit;border-radius:.35rem;padding:.25rem .4rem;font-size:.8rem}._6tq0da_select{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:100%;color:var(--dsw-alias-label-primary);font:inherit;border-radius:.35rem;padding:.25rem .4rem;font-size:.8rem}._6tq0da_segmented{border:1px solid var(--dsw-alias-border-l1);border-radius:.35rem;display:inline-flex;overflow:hidden}._6tq0da_segment,._6tq0da_segmentActive{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;border:0;padding:.25rem .6rem;font-size:.8rem}._6tq0da_segmentActive{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}._6tq0da_tableWrap{overflow-x:auto}._6tq0da_table{border-collapse:collapse;width:100%;min-width:62rem;font-size:.78rem}._6tq0da_table th{color:var(--dsw-alias-label-secondary);text-align:left;white-space:nowrap;padding:.25rem .45rem;font-weight:500}._6tq0da_table td{border-top:1px solid var(--dsw-alias-border-l1);vertical-align:middle;white-space:nowrap;padding:.28rem .45rem}._6tq0da_toggle{width:2rem}._6tq0da_toggle input{accent-color:var(--dsw-alias-brand-primary)}._6tq0da_list{flex-direction:column;display:flex}._6tq0da_item{border-top:1px solid var(--dsw-alias-border-l1);align-items:flex-start;gap:.5rem;padding:.45rem .15rem;display:flex}._6tq0da_item input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);margin-top:.15rem}._6tq0da_itemBody{flex-direction:column;gap:.15rem;min-width:0;display:flex}._6tq0da_itemMain{flex-wrap:wrap;align-items:baseline;gap:.6rem;display:flex}._6tq0da_itemMeta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:.75rem;font-size:.75rem;display:flex}._6tq0da_name{color:var(--dsw-alias-label-primary)}._6tq0da_mono{color:var(--dsw-alias-label-secondary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}._6tq0da_badge{color:var(--dsw-alias-brand-primary)}";
|
|
441
|
+
document.head.appendChild(style);
|
|
442
|
+
}
|
|
443
|
+
var section_default = { "row": "_6tq0da_row", "mono": "_6tq0da_mono", "tableWrap": "_6tq0da_tableWrap", "title": "_6tq0da_title", "warn": "_6tq0da_warn", "select": "_6tq0da_select", "segmented": "_6tq0da_segmented", "table": "_6tq0da_table", "hint": "_6tq0da_hint", "toggle": "_6tq0da_toggle", "list": "_6tq0da_list", "itemBody": "_6tq0da_itemBody", "itemMain": "_6tq0da_itemMain", "number": "_6tq0da_number", "itemMeta": "_6tq0da_itemMeta", "name": "_6tq0da_name", "segmentActive": "_6tq0da_segmentActive", "item": "_6tq0da_item", "input": "_6tq0da_input", "block": "_6tq0da_block", "button": "_6tq0da_button", "segment": "_6tq0da_segment", "root": "_6tq0da_root", "badge": "_6tq0da_badge", "ok": "_6tq0da_ok" };
|
|
444
|
+
|
|
445
|
+
// src/client/Section.tsx
|
|
446
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
447
|
+
var API_KEY_REF = "OPENCODE_GO_API_KEY";
|
|
448
|
+
var VISIBILITY_WRITE_DELAY_MS = 250;
|
|
449
|
+
var INITIAL = {
|
|
450
|
+
loading: true,
|
|
451
|
+
reading: void 0,
|
|
452
|
+
keyConfigured: void 0,
|
|
453
|
+
failure: void 0,
|
|
454
|
+
writeFailure: void 0,
|
|
455
|
+
saved: void 0,
|
|
456
|
+
settings: void 0,
|
|
457
|
+
writable: false,
|
|
458
|
+
saving: false,
|
|
459
|
+
filter: INITIAL_FILTER
|
|
460
|
+
};
|
|
461
|
+
function settingsOf(value) {
|
|
462
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
463
|
+
const record = value;
|
|
464
|
+
const visibility = record["modelVisibility"];
|
|
465
|
+
const minutes = record["refreshMinutes"];
|
|
466
|
+
if (visibility === null || typeof visibility !== "object" || typeof minutes !== "number") return void 0;
|
|
467
|
+
const entries = Object.entries(visibility).filter(([, enabled]) => typeof enabled === "boolean");
|
|
468
|
+
return {
|
|
469
|
+
modelVisibility: Object.fromEntries(entries),
|
|
470
|
+
refreshMinutes: minutes
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
var SectionController = class {
|
|
474
|
+
state = INITIAL;
|
|
475
|
+
listeners = /* @__PURE__ */ new Set();
|
|
476
|
+
services;
|
|
477
|
+
disposers = [];
|
|
478
|
+
/** Latest visibility dict awaiting its coalesced write. */
|
|
479
|
+
pendingVisibility;
|
|
480
|
+
/** Timer of the coalescing window, when one is armed. */
|
|
481
|
+
visibilityTimer;
|
|
482
|
+
constructor(services) {
|
|
483
|
+
this.services = services;
|
|
484
|
+
const scope = services.scope;
|
|
485
|
+
if (scope !== void 0) {
|
|
486
|
+
const sync = () => {
|
|
487
|
+
const snapshot = scope.getSnapshot();
|
|
488
|
+
this.set({ settings: settingsOf(snapshot.value), writable: snapshot.writable });
|
|
489
|
+
};
|
|
490
|
+
sync();
|
|
491
|
+
this.disposers.push(scope.subscribe(sync));
|
|
492
|
+
}
|
|
493
|
+
void this.load(false);
|
|
494
|
+
void this.loadKey();
|
|
495
|
+
}
|
|
496
|
+
subscribe = (listener) => {
|
|
497
|
+
this.listeners.add(listener);
|
|
498
|
+
return () => {
|
|
499
|
+
this.listeners.delete(listener);
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
snapshot = () => this.state;
|
|
503
|
+
/** Drop every listener and scope subscription; the slot's effect calls this. */
|
|
504
|
+
dispose() {
|
|
505
|
+
this.listeners.clear();
|
|
506
|
+
for (const dispose of this.disposers.splice(0)) dispose();
|
|
507
|
+
const scope = this.services.scope;
|
|
508
|
+
if (this.visibilityTimer !== void 0 && scope !== void 0) void this.flushVisibility(scope);
|
|
509
|
+
}
|
|
510
|
+
set(next) {
|
|
511
|
+
this.state = { ...this.state, ...next };
|
|
512
|
+
for (const listener of this.listeners) listener();
|
|
513
|
+
}
|
|
514
|
+
/** Read the catalog, or revalidate it when `refresh` is set. */
|
|
515
|
+
async load(refresh) {
|
|
516
|
+
this.set({ loading: true, failure: void 0 });
|
|
517
|
+
try {
|
|
518
|
+
const result = refresh ? await this.services.remote.opencodeGoCatalog.refresh() : await this.services.remote.opencodeGoCatalog.read();
|
|
519
|
+
if (!result.ok) throw result.error;
|
|
520
|
+
this.set({ loading: false, reading: result.value, failure: void 0 });
|
|
521
|
+
} catch (error) {
|
|
522
|
+
this.set({
|
|
523
|
+
loading: false,
|
|
524
|
+
failure: error instanceof Error ? error.message : "the catalog is unavailable"
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async loadKey() {
|
|
529
|
+
try {
|
|
530
|
+
const described = await this.services.remote.credentials.describe([API_KEY_REF]);
|
|
531
|
+
if (!described.ok) throw described.error;
|
|
532
|
+
this.set({ keyConfigured: described.value[API_KEY_REF]?.configured === true });
|
|
533
|
+
} catch {
|
|
534
|
+
this.set({ keyConfigured: void 0 });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
async saveKey(value) {
|
|
538
|
+
const trimmed = value.trim();
|
|
539
|
+
if (trimmed.length === 0) return;
|
|
540
|
+
const result = await this.services.remote.credentials.set(API_KEY_REF, trimmed);
|
|
541
|
+
if (!result.ok) throw result.error;
|
|
542
|
+
this.set({ saved: true });
|
|
543
|
+
await this.loadKey();
|
|
544
|
+
}
|
|
545
|
+
async clearKey() {
|
|
546
|
+
const result = await this.services.remote.credentials.unset(API_KEY_REF);
|
|
547
|
+
if (!result.ok) throw result.error;
|
|
548
|
+
this.set({ saved: false });
|
|
549
|
+
await this.loadKey();
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Flip one model's switch.
|
|
553
|
+
*
|
|
554
|
+
* The switch is published immediately and the write itself is coalesced, so
|
|
555
|
+
* the UI never waits on the Host round trip and a burst of clicks becomes a
|
|
556
|
+
* single write of the final dict.
|
|
557
|
+
*/
|
|
558
|
+
setVisibility(id3, enabled) {
|
|
559
|
+
this.mergeVisibility({ [id3]: enabled });
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Set every configurable model at once (select-all / select-none).
|
|
563
|
+
*
|
|
564
|
+
* Select-all leaves deprecated models alone — they arrive switched off, and
|
|
565
|
+
* a bulk action must not quietly re-enable a discontinued model. Select-none
|
|
566
|
+
* clears everything, deprecated included.
|
|
567
|
+
* @param enabled - the state the affected models should take.
|
|
568
|
+
*/
|
|
569
|
+
setAllVisibility(enabled) {
|
|
570
|
+
const reading = this.state.reading;
|
|
571
|
+
if (reading === void 0) return;
|
|
572
|
+
const patch = {};
|
|
573
|
+
for (const model of reading.models) {
|
|
574
|
+
if (model.configurationMissing !== void 0) continue;
|
|
575
|
+
if (enabled && model.deprecated === true) continue;
|
|
576
|
+
patch[model.id] = enabled;
|
|
577
|
+
}
|
|
578
|
+
this.mergeVisibility(patch);
|
|
579
|
+
}
|
|
580
|
+
/** Publish the merged dict locally, then schedule one coalesced write. */
|
|
581
|
+
mergeVisibility(patch) {
|
|
582
|
+
const scope = this.services.scope;
|
|
583
|
+
const current = this.state.settings;
|
|
584
|
+
if (scope === void 0 || current === void 0 || !this.state.writable) return;
|
|
585
|
+
const modelVisibility = { ...current.modelVisibility, ...patch };
|
|
586
|
+
this.set({ settings: { ...current, modelVisibility }, writeFailure: void 0 });
|
|
587
|
+
this.pendingVisibility = modelVisibility;
|
|
588
|
+
if (this.visibilityTimer !== void 0) clearTimeout(this.visibilityTimer);
|
|
589
|
+
this.visibilityTimer = setTimeout(() => {
|
|
590
|
+
void this.flushVisibility(scope);
|
|
591
|
+
}, VISIBILITY_WRITE_DELAY_MS);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Write the pending dict once.
|
|
595
|
+
*
|
|
596
|
+
* A refusal is usually a revision conflict with another client — the form
|
|
597
|
+
* has already reloaded the namespace by then — so one immediate retry
|
|
598
|
+
* settles a lost race before the page tells a human something went wrong.
|
|
599
|
+
* A persistent refusal, or a thrown call, surfaces as a failure and rolls
|
|
600
|
+
* the optimistic dict back to what the Host reports.
|
|
601
|
+
*/
|
|
602
|
+
async flushVisibility(scope) {
|
|
603
|
+
if (this.visibilityTimer !== void 0) {
|
|
604
|
+
clearTimeout(this.visibilityTimer);
|
|
605
|
+
this.visibilityTimer = void 0;
|
|
606
|
+
}
|
|
607
|
+
const value = this.pendingVisibility;
|
|
608
|
+
this.pendingVisibility = void 0;
|
|
609
|
+
if (value === void 0) return;
|
|
610
|
+
this.set({ saving: true });
|
|
611
|
+
try {
|
|
612
|
+
let result = await scope.set("modelVisibility", value);
|
|
613
|
+
if (result === false) result = await scope.set("modelVisibility", value);
|
|
614
|
+
if (result === false) this.set({ writeFailure: { kind: "rejected" } });
|
|
615
|
+
} catch (error) {
|
|
616
|
+
this.set({
|
|
617
|
+
writeFailure: { kind: "failed", message: error instanceof Error ? error.message : "" }
|
|
618
|
+
});
|
|
619
|
+
this.set({ settings: settingsOf(scope.getSnapshot().value) });
|
|
620
|
+
} finally {
|
|
621
|
+
this.set({ saving: false });
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
/** Narrow or reorder the model table; a view preference, never a write. */
|
|
625
|
+
setFilter(patch) {
|
|
626
|
+
this.set({ filter: { ...this.state.filter, ...patch } });
|
|
627
|
+
}
|
|
628
|
+
/** Set the catalog cache lifetime, clamped to the schema's own bounds. */
|
|
629
|
+
async setRefreshMinutes(minutes) {
|
|
630
|
+
const scope = this.services.scope;
|
|
631
|
+
const current = this.state.settings;
|
|
632
|
+
if (scope === void 0 || current === void 0 || !this.state.writable) return;
|
|
633
|
+
if (!Number.isSafeInteger(minutes) || minutes < 1 || minutes > 7 * 24 * 60) return;
|
|
634
|
+
await this.write(
|
|
635
|
+
() => scope.set("refreshMinutes", minutes),
|
|
636
|
+
() => this.set({ settings: { ...current, refreshMinutes: minutes } })
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
async write(operation, onAccepted) {
|
|
640
|
+
this.set({ saving: true });
|
|
641
|
+
try {
|
|
642
|
+
const result = await operation();
|
|
643
|
+
if (result === false) this.set({ failure: "the settings write was rejected" });
|
|
644
|
+
else onAccepted?.();
|
|
645
|
+
} finally {
|
|
646
|
+
this.set({ saving: false });
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
function badgeFor(model, t) {
|
|
651
|
+
if (model.configurationMissing !== void 0) return `${t("catalogUnconfigured")}: ${model.configurationMissing}`;
|
|
652
|
+
if (model.protocolSource === "inferred") return t("catalogInferred");
|
|
653
|
+
if (model.assumedLimits === true) return t("catalogAssumed");
|
|
654
|
+
if (model.deprecated === true) return t("catalogDeprecated");
|
|
655
|
+
return "";
|
|
656
|
+
}
|
|
657
|
+
function isOffered(model, visibility) {
|
|
658
|
+
return isModelEnabled(model, visibility);
|
|
659
|
+
}
|
|
660
|
+
function ioLabel(model, t) {
|
|
661
|
+
const parts = [];
|
|
662
|
+
if (model.maxInputTokens !== void 0) parts.push(`${t("iosInput")} ${compactCount(model.maxInputTokens)}`);
|
|
663
|
+
if (model.maxTokens !== void 0) parts.push(`${t("iosOutput")} ${compactCount(model.maxTokens)}`);
|
|
664
|
+
return parts.length === 0 ? "\u2014" : parts.join(" \xB7 ");
|
|
665
|
+
}
|
|
666
|
+
function priceLabel(model) {
|
|
667
|
+
if (model.cost === void 0) return "\u2014";
|
|
668
|
+
return `$${model.cost.input} / $${model.cost.output}`;
|
|
669
|
+
}
|
|
670
|
+
function quotaLabel(model, t) {
|
|
671
|
+
const quota = model.goQuota;
|
|
672
|
+
if (quota === void 0) return "\u2014";
|
|
673
|
+
const usd = quota.monthlyUsd === "unlimited" ? t("quotaUnlimited") : `$${quota.monthlyUsd}`;
|
|
674
|
+
if (quota.monthlyRequests === void 0) return usd;
|
|
675
|
+
const requests = quota.monthlyRequests === "unlimited" ? t("quotaUnlimited") : `${compactCount(quota.monthlyRequests)} ${t("quotaPerMonth")}`;
|
|
676
|
+
return `${usd} \xB7 ${requests}`;
|
|
677
|
+
}
|
|
678
|
+
function Section({ controller, t, getLocale }) {
|
|
679
|
+
const state = (0, import_react.useSyncExternalStore)(controller.subscribe, controller.snapshot, controller.snapshot);
|
|
680
|
+
const [keyDraft, setKeyDraft] = (0, import_react.useState)("");
|
|
681
|
+
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
682
|
+
const act = (0, import_react.useCallback)(async (operation) => {
|
|
683
|
+
setBusy(true);
|
|
684
|
+
try {
|
|
685
|
+
await operation();
|
|
686
|
+
} finally {
|
|
687
|
+
setBusy(false);
|
|
688
|
+
}
|
|
689
|
+
}, []);
|
|
690
|
+
(0, import_react.useEffect)(() => {
|
|
691
|
+
setKeyDraft("");
|
|
692
|
+
}, [state.saved]);
|
|
693
|
+
const reading = state.reading;
|
|
694
|
+
const visibility = state.settings?.modelVisibility ?? {};
|
|
695
|
+
const editable = state.writable && state.settings !== void 0;
|
|
696
|
+
const rows = reading === void 0 ? [] : visibleModels(reading.models, state.filter, visibility, getLocale?.());
|
|
697
|
+
const hidden = reading === void 0 ? 0 : reading.models.length - rows.length;
|
|
698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: section_default.root, children: [
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: section_default.title, children: t("nav") }),
|
|
700
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.hint, children: t("intro") }),
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.block, children: [
|
|
702
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("keyTitle") }),
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: state.keyConfigured === true ? section_default.ok : state.keyConfigured === false ? section_default.warn : section_default.hint, children: state.keyConfigured === true ? t("keyConfigured") : state.keyConfigured === false ? t("keyMissing") : "\u2014" })
|
|
705
|
+
] }),
|
|
706
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.hint, children: t("keyHint") }),
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
709
|
+
"input",
|
|
710
|
+
{
|
|
711
|
+
className: section_default.input,
|
|
712
|
+
type: "password",
|
|
713
|
+
"aria-label": t("keyTitle"),
|
|
714
|
+
placeholder: t("keyPlaceholder"),
|
|
715
|
+
value: keyDraft,
|
|
716
|
+
onChange: (event) => {
|
|
717
|
+
setKeyDraft(event.target.value);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
),
|
|
721
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
722
|
+
"button",
|
|
723
|
+
{
|
|
724
|
+
type: "button",
|
|
725
|
+
className: section_default.button,
|
|
726
|
+
disabled: busy || keyDraft.trim().length === 0,
|
|
727
|
+
onClick: () => {
|
|
728
|
+
void act(async () => {
|
|
729
|
+
await controller.saveKey(keyDraft);
|
|
730
|
+
});
|
|
731
|
+
},
|
|
732
|
+
children: state.saved === true ? t("keySaved") : t("keySave")
|
|
733
|
+
}
|
|
734
|
+
),
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
736
|
+
"button",
|
|
737
|
+
{
|
|
738
|
+
type: "button",
|
|
739
|
+
className: section_default.button,
|
|
740
|
+
disabled: busy || state.keyConfigured !== true,
|
|
741
|
+
onClick: () => {
|
|
742
|
+
void act(async () => {
|
|
743
|
+
await controller.clearKey();
|
|
744
|
+
});
|
|
745
|
+
},
|
|
746
|
+
children: t("keyClear")
|
|
747
|
+
}
|
|
748
|
+
)
|
|
749
|
+
] })
|
|
750
|
+
] }),
|
|
751
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.block, children: [
|
|
752
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("catalogTitle") }),
|
|
754
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: reading === void 0 ? "\u2014" : `${reading.counts.total} ${t("catalogCountUnit")} \xB7 ${reading.counts.enabled} \u2713` + (reading.counts.inferred === 0 ? "" : ` \xB7 ${reading.counts.inferred} ${t("catalogInferred")}`) + (reading.counts.unconfigured === 0 ? "" : ` \xB7 ${reading.counts.unconfigured} ${t("catalogUnconfigured")}`) }),
|
|
755
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
756
|
+
"button",
|
|
757
|
+
{
|
|
758
|
+
type: "button",
|
|
759
|
+
className: section_default.button,
|
|
760
|
+
disabled: !editable || reading === void 0,
|
|
761
|
+
onClick: () => {
|
|
762
|
+
controller.setAllVisibility(true);
|
|
763
|
+
},
|
|
764
|
+
children: t("catalogSelectAll")
|
|
765
|
+
}
|
|
766
|
+
),
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
768
|
+
"button",
|
|
769
|
+
{
|
|
770
|
+
type: "button",
|
|
771
|
+
className: section_default.button,
|
|
772
|
+
disabled: !editable || reading === void 0,
|
|
773
|
+
onClick: () => {
|
|
774
|
+
controller.setAllVisibility(false);
|
|
775
|
+
},
|
|
776
|
+
children: t("catalogSelectNone")
|
|
777
|
+
}
|
|
778
|
+
),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
780
|
+
"button",
|
|
781
|
+
{
|
|
782
|
+
type: "button",
|
|
783
|
+
className: section_default.button,
|
|
784
|
+
disabled: busy || state.loading,
|
|
785
|
+
onClick: () => {
|
|
786
|
+
void act(async () => {
|
|
787
|
+
await controller.load(true);
|
|
788
|
+
});
|
|
789
|
+
},
|
|
790
|
+
children: state.loading ? t("usageRefreshing") : t("catalogRefresh")
|
|
791
|
+
}
|
|
792
|
+
)
|
|
793
|
+
] }),
|
|
794
|
+
state.failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: section_default.warn, children: [
|
|
795
|
+
t("catalogStale"),
|
|
796
|
+
": ",
|
|
797
|
+
state.failure
|
|
798
|
+
] }),
|
|
799
|
+
reading !== void 0 && reading.stale && state.failure === void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.warn, children: t("catalogStale") }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: section_default.hint, htmlFor: "dshopencodego-refresh", children: t("refreshLabel") }),
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
803
|
+
"input",
|
|
804
|
+
{
|
|
805
|
+
id: "dshopencodego-refresh",
|
|
806
|
+
className: section_default.number,
|
|
807
|
+
type: "number",
|
|
808
|
+
min: 1,
|
|
809
|
+
max: 7 * 24 * 60,
|
|
810
|
+
disabled: !editable || state.saving,
|
|
811
|
+
value: state.settings?.refreshMinutes ?? "",
|
|
812
|
+
onChange: (event) => {
|
|
813
|
+
void controller.setRefreshMinutes(Number(event.target.value));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
),
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: t("refreshHint") })
|
|
818
|
+
] }),
|
|
819
|
+
state.writeFailure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.warn, children: state.writeFailure.kind === "rejected" ? t("writeRejected") : state.writeFailure.message.length === 0 ? t("writeFailed") : `${t("writeFailed")}: ${state.writeFailure.message}` }),
|
|
820
|
+
reading !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
822
|
+
"input",
|
|
823
|
+
{
|
|
824
|
+
className: section_default.input,
|
|
825
|
+
type: "search",
|
|
826
|
+
"aria-label": t("filterPlaceholder"),
|
|
827
|
+
placeholder: t("filterPlaceholder"),
|
|
828
|
+
value: state.filter.query,
|
|
829
|
+
onChange: (event) => {
|
|
830
|
+
controller.setFilter({ query: event.target.value });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
),
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: section_default.hint, children: [
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
836
|
+
"input",
|
|
837
|
+
{
|
|
838
|
+
type: "checkbox",
|
|
839
|
+
checked: state.filter.onlyEnabled,
|
|
840
|
+
onChange: (event) => {
|
|
841
|
+
controller.setFilter({ onlyEnabled: event.target.checked });
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
),
|
|
845
|
+
` ${t("filterOnlyEnabled")}`
|
|
846
|
+
] }),
|
|
847
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: section_default.hint, children: [
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
849
|
+
"input",
|
|
850
|
+
{
|
|
851
|
+
type: "checkbox",
|
|
852
|
+
checked: state.filter.showDeprecated,
|
|
853
|
+
onChange: (event) => {
|
|
854
|
+
controller.setFilter({ showDeprecated: event.target.checked });
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
),
|
|
858
|
+
` ${t("filterShowDeprecated")}`
|
|
859
|
+
] }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: section_default.hint, children: [
|
|
861
|
+
`${t("sortLabel")} `,
|
|
862
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
863
|
+
"select",
|
|
864
|
+
{
|
|
865
|
+
className: section_default.select,
|
|
866
|
+
"aria-label": t("sortLabel"),
|
|
867
|
+
value: state.filter.sort,
|
|
868
|
+
onChange: (event) => {
|
|
869
|
+
controller.setFilter({ sort: event.target.value });
|
|
870
|
+
},
|
|
871
|
+
children: [
|
|
872
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "default", children: t("sortDefault") }),
|
|
873
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "released", children: t("sortReleased") }),
|
|
874
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "name", children: t("sortName") }),
|
|
875
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "context", children: t("sortContext") }),
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "quota", children: t("sortQuota") }),
|
|
877
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "price", children: t("sortPrice") }),
|
|
878
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "enabled", children: t("sortEnabled") })
|
|
879
|
+
]
|
|
880
|
+
}
|
|
881
|
+
)
|
|
882
|
+
] }),
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: section_default.segmented, children: [
|
|
884
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
885
|
+
"button",
|
|
886
|
+
{
|
|
887
|
+
type: "button",
|
|
888
|
+
className: state.filter.view === "list" ? section_default.segmentActive : section_default.segment,
|
|
889
|
+
onClick: () => {
|
|
890
|
+
controller.setFilter({ view: "list" });
|
|
891
|
+
},
|
|
892
|
+
children: t("viewList")
|
|
893
|
+
}
|
|
894
|
+
),
|
|
895
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
896
|
+
"button",
|
|
897
|
+
{
|
|
898
|
+
type: "button",
|
|
899
|
+
className: state.filter.view === "table" ? section_default.segmentActive : section_default.segment,
|
|
900
|
+
onClick: () => {
|
|
901
|
+
controller.setFilter({ view: "table" });
|
|
902
|
+
},
|
|
903
|
+
children: t("viewTable")
|
|
904
|
+
}
|
|
905
|
+
)
|
|
906
|
+
] }),
|
|
907
|
+
hidden > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: section_default.hint, children: [
|
|
908
|
+
hidden,
|
|
909
|
+
" ",
|
|
910
|
+
t("filterHidden")
|
|
911
|
+
] })
|
|
912
|
+
] }),
|
|
913
|
+
reading !== void 0 && (state.filter.view === "table" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: section_default.tableWrap, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: section_default.table, children: [
|
|
914
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
915
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {}),
|
|
916
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerModel") }),
|
|
917
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerId") }),
|
|
918
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerReleased") }),
|
|
919
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerCapacity") }),
|
|
920
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerIo") }),
|
|
921
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerPrice") }),
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerQuota") }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: section_default.hint, children: t("headerNotes") })
|
|
924
|
+
] }) }),
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: rows.map((model) => {
|
|
926
|
+
const badge = badgeFor(model, t);
|
|
927
|
+
const offered = isOffered(model, visibility);
|
|
928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
929
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.toggle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
930
|
+
"input",
|
|
931
|
+
{
|
|
932
|
+
type: "checkbox",
|
|
933
|
+
"aria-label": `${t("catalogTitle")}: ${model.name}`,
|
|
934
|
+
checked: offered,
|
|
935
|
+
disabled: !editable || model.configurationMissing !== void 0,
|
|
936
|
+
onChange: (event) => {
|
|
937
|
+
controller.setVisibility(model.id, event.target.checked);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
) }),
|
|
941
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.name, children: model.name }),
|
|
942
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.mono, children: model.id }),
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.hint, children: model.releaseDate ?? "\u2014" }),
|
|
944
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.hint, children: model.contextWindow === void 0 ? "\u2014" : model.contextWindow.toLocaleString(getLocale?.()) }),
|
|
945
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.hint, children: ioLabel(model, t) }),
|
|
946
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.hint, children: priceLabel(model) }),
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: section_default.hint, children: quotaLabel(model, t) }),
|
|
948
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: badge.length === 0 ? section_default.hint : section_default.badge, children: badge })
|
|
949
|
+
] }, model.id);
|
|
950
|
+
}) })
|
|
951
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: section_default.list, children: rows.map((model) => {
|
|
952
|
+
const badge = badgeFor(model, t);
|
|
953
|
+
const offered = isOffered(model, visibility);
|
|
954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.item, children: [
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
956
|
+
"input",
|
|
957
|
+
{
|
|
958
|
+
type: "checkbox",
|
|
959
|
+
"aria-label": `${t("catalogTitle")}: ${model.name}`,
|
|
960
|
+
checked: offered,
|
|
961
|
+
disabled: !editable || model.configurationMissing !== void 0,
|
|
962
|
+
onChange: (event) => {
|
|
963
|
+
controller.setVisibility(model.id, event.target.checked);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
),
|
|
967
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.itemBody, children: [
|
|
968
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.itemMain, children: [
|
|
969
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.name, children: model.name }),
|
|
970
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.mono, children: model.id }),
|
|
971
|
+
model.releaseDate !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: model.releaseDate }),
|
|
972
|
+
badge.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.badge, children: badge })
|
|
973
|
+
] }),
|
|
974
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.itemMeta, children: [
|
|
975
|
+
model.contextWindow !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: `${t("iosContext")} ${model.contextWindow.toLocaleString(getLocale?.())}` }),
|
|
976
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: ioLabel(model, t) }),
|
|
977
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: priceLabel(model) }),
|
|
978
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: quotaLabel(model, t) })
|
|
979
|
+
] })
|
|
980
|
+
] })
|
|
981
|
+
] }, model.id);
|
|
982
|
+
}) }))
|
|
983
|
+
] })
|
|
984
|
+
] });
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/client/UsagePill.tsx
|
|
988
|
+
var import_react2 = require("react");
|
|
989
|
+
|
|
990
|
+
// plugin-css:D:\prj\dshopencodego\src\client\pill.module.css
|
|
991
|
+
var id2 = "@dan-ai-studio/dshopencodego/pill.module.css";
|
|
992
|
+
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]")) {
|
|
993
|
+
const style = document.createElement("style");
|
|
994
|
+
style.dataset.plugin = "@dan-ai-studio/dshopencodego";
|
|
995
|
+
style.dataset.pluginCss = id2;
|
|
996
|
+
style.textContent = ".y-bZgq_root{align-items:center;display:inline-flex;position:relative}.y-bZgq_trigger{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;border-radius:999px;padding:.35rem .6rem;font-size:.8rem;line-height:1}.y-bZgq_trigger:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.y-bZgq_panel{z-index:20;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-overlay);width:18rem;color:var(--dsw-alias-label-primary);border-radius:.6rem;flex-direction:column;gap:.6rem;padding:.75rem .85rem;display:flex;position:absolute;bottom:calc(100% + .5rem);right:0;box-shadow:0 8px 24px #0000002e}.y-bZgq_window{flex-direction:column;gap:.25rem;display:flex}.y-bZgq_row{justify-content:space-between;gap:.5rem;font-size:.85rem;display:flex}.y-bZgq_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:.75rem}.y-bZgq_progress{width:100%;height:.35rem;accent-color:var(--dsw-alias-brand-primary)}.y-bZgq_limited{color:var(--dsw-alias-state-warn-primary);font-size:.75rem}.y-bZgq_warning{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-label-primary);border-radius:.4rem;padding:.4rem .5rem;font-size:.75rem}.y-bZgq_retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:.35rem;align-self:flex-start;padding:.25rem .5rem;font-size:.75rem}.y-bZgq_local{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:.2rem;padding-top:.5rem;display:flex}";
|
|
997
|
+
document.head.appendChild(style);
|
|
998
|
+
}
|
|
999
|
+
var pill_default = { "hint": "y-bZgq_hint", "trigger": "y-bZgq_trigger", "window": "y-bZgq_window", "row": "y-bZgq_row", "retry": "y-bZgq_retry", "progress": "y-bZgq_progress", "warning": "y-bZgq_warning", "panel": "y-bZgq_panel", "local": "y-bZgq_local", "root": "y-bZgq_root", "limited": "y-bZgq_limited" };
|
|
1000
|
+
|
|
1001
|
+
// src/client/UsagePill.tsx
|
|
1002
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1003
|
+
function failureOf(error) {
|
|
1004
|
+
if (error !== null && typeof error === "object" && "code" in error && error.code === "dshopencodego/usage-unavailable") {
|
|
1005
|
+
const details = error.details;
|
|
1006
|
+
const record = details !== null && typeof details === "object" ? details : {};
|
|
1007
|
+
return {
|
|
1008
|
+
message: typeof error.message === "string" ? error.message : "",
|
|
1009
|
+
retainPrevious: record["retryable"] === true && record["retainPrevious"] === true,
|
|
1010
|
+
...typeof record["source"] === "string" ? { source: record["source"] } : {}
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
return { message: "", retainPrevious: false };
|
|
1014
|
+
}
|
|
1015
|
+
var POLL_MS = 6e4;
|
|
1016
|
+
function UsagePill({ directory, ...rest }) {
|
|
1017
|
+
const state = (0, import_react2.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
|
|
1018
|
+
return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActiveUsage, { ...rest }) : null;
|
|
1019
|
+
}
|
|
1020
|
+
function ActiveUsage({
|
|
1021
|
+
readWindows,
|
|
1022
|
+
readMeter,
|
|
1023
|
+
t,
|
|
1024
|
+
getLocale
|
|
1025
|
+
}) {
|
|
1026
|
+
const [windows, setWindows] = (0, import_react2.useState)(void 0);
|
|
1027
|
+
const [meter, setMeter] = (0, import_react2.useState)(void 0);
|
|
1028
|
+
const [failure, setFailure] = (0, import_react2.useState)(void 0);
|
|
1029
|
+
const [updatedAt, setUpdatedAt] = (0, import_react2.useState)(void 0);
|
|
1030
|
+
const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
|
|
1031
|
+
const [open, setOpen] = (0, import_react2.useState)(false);
|
|
1032
|
+
const root = (0, import_react2.useRef)(null);
|
|
1033
|
+
const refresh = (0, import_react2.useCallback)(async () => {
|
|
1034
|
+
setRefreshing(true);
|
|
1035
|
+
try {
|
|
1036
|
+
const [nextWindows, nextMeter] = await Promise.all([readWindows(), readMeter()]);
|
|
1037
|
+
setWindows(nextWindows);
|
|
1038
|
+
setMeter(nextMeter);
|
|
1039
|
+
setFailure(void 0);
|
|
1040
|
+
setUpdatedAt(Date.now());
|
|
1041
|
+
} catch (error) {
|
|
1042
|
+
const failure2 = failureOf(error);
|
|
1043
|
+
setFailure(failure2);
|
|
1044
|
+
if (!failure2.retainPrevious) {
|
|
1045
|
+
setWindows(void 0);
|
|
1046
|
+
setUpdatedAt(void 0);
|
|
1047
|
+
}
|
|
1048
|
+
} finally {
|
|
1049
|
+
setRefreshing(false);
|
|
1050
|
+
}
|
|
1051
|
+
}, [readWindows, readMeter]);
|
|
1052
|
+
(0, import_react2.useEffect)(() => {
|
|
1053
|
+
let alive = true;
|
|
1054
|
+
const run = () => {
|
|
1055
|
+
if (!alive || document.visibilityState === "hidden") return;
|
|
1056
|
+
void refresh();
|
|
1057
|
+
};
|
|
1058
|
+
run();
|
|
1059
|
+
const timer = setInterval(run, POLL_MS);
|
|
1060
|
+
document.addEventListener("visibilitychange", run);
|
|
1061
|
+
return () => {
|
|
1062
|
+
alive = false;
|
|
1063
|
+
clearInterval(timer);
|
|
1064
|
+
document.removeEventListener("visibilitychange", run);
|
|
1065
|
+
};
|
|
1066
|
+
}, [refresh]);
|
|
1067
|
+
(0, import_react2.useEffect)(() => {
|
|
1068
|
+
if (!open) return;
|
|
1069
|
+
const close = (event) => {
|
|
1070
|
+
if (!root.current?.contains(event.target)) setOpen(false);
|
|
1071
|
+
};
|
|
1072
|
+
const escape = (event) => {
|
|
1073
|
+
if (event.key === "Escape") setOpen(false);
|
|
1074
|
+
};
|
|
1075
|
+
document.addEventListener("mousedown", close);
|
|
1076
|
+
document.addEventListener("keydown", escape);
|
|
1077
|
+
return () => {
|
|
1078
|
+
document.removeEventListener("mousedown", close);
|
|
1079
|
+
document.removeEventListener("keydown", escape);
|
|
1080
|
+
};
|
|
1081
|
+
}, [open]);
|
|
1082
|
+
const label = windows === void 0 ? `Go \xB7 ${failure === void 0 ? "\u2026" : t("usageUnavailable")}` : `Go \xB7 ${t("usageRolling")} ${windows.rolling.percent}% \xB7 ${t("usageWeekly")} ${windows.weekly.percent}%` + (failure === void 0 ? "" : ` \xB7 ${t("usageStale")}`);
|
|
1083
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: pill_default.root, ref: root, children: [
|
|
1084
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1085
|
+
"button",
|
|
1086
|
+
{
|
|
1087
|
+
type: "button",
|
|
1088
|
+
className: pill_default.trigger,
|
|
1089
|
+
"aria-expanded": open,
|
|
1090
|
+
"aria-haspopup": "dialog",
|
|
1091
|
+
"aria-label": `${t("usageTitle")}: ${label}`,
|
|
1092
|
+
onClick: () => {
|
|
1093
|
+
setOpen(!open);
|
|
1094
|
+
},
|
|
1095
|
+
children: label
|
|
1096
|
+
}
|
|
1097
|
+
),
|
|
1098
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
|
|
1099
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageTitle") }),
|
|
1100
|
+
failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.warning, role: "alert", children: [
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageUnavailable") }) }),
|
|
1102
|
+
failure.message.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: failure.message }),
|
|
1103
|
+
windows !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: t("usageStale") })
|
|
1104
|
+
] }),
|
|
1105
|
+
windows === void 0 && failure === void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: pill_default.hint, children: t("usageLoading") }),
|
|
1106
|
+
windows !== void 0 && [["rolling", "usageRolling"], ["weekly", "usageWeekly"], ["monthly", "usageMonthly"]].map(([key, label2]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.window, children: [
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t(label2) }),
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
|
|
1110
|
+
windows[key].percent,
|
|
1111
|
+
"%"
|
|
1112
|
+
] })
|
|
1113
|
+
] }),
|
|
1114
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("progress", { className: pill_default.progress, max: 100, value: Math.min(100, windows[key].percent), "aria-label": t(label2) }),
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.hint, children: [
|
|
1116
|
+
t("usageResets"),
|
|
1117
|
+
" ",
|
|
1118
|
+
new Date(windows[key].resetsAt).toLocaleString(getLocale?.())
|
|
1119
|
+
] }),
|
|
1120
|
+
windows[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: pill_default.limited, children: t("usageLimited") })
|
|
1121
|
+
] }, key)),
|
|
1122
|
+
meter !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.local, children: [
|
|
1123
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageSinceBoot") }),
|
|
1124
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
|
|
1125
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageCallsUnit") }),
|
|
1126
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.calls })
|
|
1127
|
+
] }),
|
|
1128
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageTokensUnit") }),
|
|
1130
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.totalTokens.toLocaleString(getLocale?.()) })
|
|
1131
|
+
] }),
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageCached") }),
|
|
1134
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.cacheReadTokens.toLocaleString(getLocale?.()) })
|
|
1135
|
+
] }),
|
|
1136
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: pill_default.hint, children: t("usageLocalHint") })
|
|
1137
|
+
] }),
|
|
1138
|
+
updatedAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: pill_default.hint, children: [
|
|
1139
|
+
t("usageLastUpdated"),
|
|
1140
|
+
" ",
|
|
1141
|
+
new Date(updatedAt).toLocaleString(getLocale?.())
|
|
1142
|
+
] }),
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: pill_default.retry, disabled: refreshing, onClick: () => {
|
|
1144
|
+
void refresh();
|
|
1145
|
+
}, children: t(refreshing ? "usageRefreshing" : "usageRetry") })
|
|
1146
|
+
] })
|
|
1147
|
+
] });
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// src/client/index.ts
|
|
1151
|
+
var NS = "settings.dshopencodego";
|
|
1152
|
+
var inject = ["slots", "locale", "remote"];
|
|
1153
|
+
function apply(ctx) {
|
|
1154
|
+
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dshopencodego: copy dictionaries");
|
|
1155
|
+
const mounted = ctx.remote.$mount({
|
|
1156
|
+
package: usageRemote.package,
|
|
1157
|
+
descriptors: [...usageRemote.descriptors, ...catalogRemote.descriptors]
|
|
1158
|
+
});
|
|
1159
|
+
ctx.effect(() => {
|
|
1160
|
+
let dispose;
|
|
1161
|
+
void mounted.then((next) => {
|
|
1162
|
+
dispose = next;
|
|
1163
|
+
}).catch(() => {
|
|
1164
|
+
});
|
|
1165
|
+
return () => {
|
|
1166
|
+
void dispose?.();
|
|
1167
|
+
};
|
|
1168
|
+
}, "dshopencodego: usage Remote");
|
|
1169
|
+
ctx.inject(["configForms", "remote.opencodeGoCatalog", "remote.credentials"], (scope) => {
|
|
1170
|
+
const forms = scope.get("configForms");
|
|
1171
|
+
const controller = new SectionController({
|
|
1172
|
+
remote: scope.remote,
|
|
1173
|
+
scope: forms?.get("dshopencodego")
|
|
1174
|
+
});
|
|
1175
|
+
const translate = scope.locale.bind(NS);
|
|
1176
|
+
scope.effect(() => () => {
|
|
1177
|
+
controller.dispose();
|
|
1178
|
+
});
|
|
1179
|
+
scope.slots.inject("settings.section", () => scope.slots.register({
|
|
1180
|
+
name: "settings.section",
|
|
1181
|
+
id: "dshopencodego",
|
|
1182
|
+
order: 20,
|
|
1183
|
+
label: () => translate("nav"),
|
|
1184
|
+
inject: () => ({
|
|
1185
|
+
controller,
|
|
1186
|
+
t: (key) => translate(key),
|
|
1187
|
+
getLocale: () => scope.locale.getLocale().active
|
|
1188
|
+
})
|
|
1189
|
+
}, Section));
|
|
1190
|
+
});
|
|
1191
|
+
ctx.inject(["modelDirectories", "remote.opencodeGoUsage"], (scope) => {
|
|
1192
|
+
const translate = scope.locale.bind(NS);
|
|
1193
|
+
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
1194
|
+
name: "conversation.input.right",
|
|
1195
|
+
id: "dshopencodego-usage",
|
|
1196
|
+
order: 1e3,
|
|
1197
|
+
inject: (sessionId) => ({
|
|
1198
|
+
directory: scope.modelDirectories.directoryFor(sessionId).store,
|
|
1199
|
+
readWindows: async () => {
|
|
1200
|
+
const result = await scope.remote.opencodeGoUsage.readWindows();
|
|
1201
|
+
if (!result.ok) throw result.error;
|
|
1202
|
+
return result.value;
|
|
1203
|
+
},
|
|
1204
|
+
readMeter: async () => {
|
|
1205
|
+
const result = await scope.remote.opencodeGoUsage.readMeter();
|
|
1206
|
+
if (!result.ok) throw result.error;
|
|
1207
|
+
return result.value;
|
|
1208
|
+
},
|
|
1209
|
+
t: (key) => translate(key),
|
|
1210
|
+
getLocale: () => scope.locale.getLocale().active
|
|
1211
|
+
})
|
|
1212
|
+
}, UsagePill));
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
return module.exports; } });
|