cortico-provider-deepseek 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1234 @@
1
+ // ../../Cortico/src/web/shared/console-protocol.ts
2
+ var CONSOLE_LANGUAGE_HEADER = "x-cortico-language";
3
+ var CONSOLE_AUTH_HEADER = "x-cortico-auth";
4
+ var CONTROL_CHARS_RE = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(31)}${String.fromCharCode(127)}]`);
5
+
6
+ // ../../Cortico/src/web/shared/client-panel.ts
7
+ var ConsoleInvokeError = class extends Error {
8
+ status;
9
+ constructor(message, status) {
10
+ super(message);
11
+ this.name = "ConsoleInvokeError";
12
+ this.status = status;
13
+ }
14
+ };
15
+
16
+ // ../../Cortico/src/web/shared/path-picker.ts
17
+ var PATH_PICKER_ROUTE = "/api/path-picker";
18
+
19
+ // ../../Cortico/src/web/client/core/language.ts
20
+ var STORAGE_KEY = "cortico.console.language";
21
+ function readLanguage(doc) {
22
+ let preference = null;
23
+ try {
24
+ preference = doc.defaultView?.localStorage.getItem(STORAGE_KEY) ?? null;
25
+ } catch {
26
+ }
27
+ const language = preference === "zh" || preference === "en" ? preference : doc.documentElement.lang.toLowerCase().startsWith("en") ? "en" : "zh";
28
+ doc.documentElement.lang = language === "zh" ? "zh-CN" : "en";
29
+ return language;
30
+ }
31
+ function readStamp() {
32
+ try {
33
+ return readLanguage(document);
34
+ } catch {
35
+ return "zh";
36
+ }
37
+ }
38
+ var LANGUAGE = readStamp();
39
+ function pick(table) {
40
+ return LANGUAGE === "en" ? table.en : table.zh;
41
+ }
42
+ function languageHeaders() {
43
+ return { [CONSOLE_LANGUAGE_HEADER]: LANGUAGE };
44
+ }
45
+
46
+ // ../../Cortico/src/web/client/core/api.ts
47
+ var zh = {
48
+ httpStatus: (status, snippet2) => `HTTP ${status}\uFF1A${snippet2}`,
49
+ notJson: (status, snippet2) => `\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5 JSON\uFF08HTTP ${status}\uFF09\uFF1A${snippet2}`
50
+ };
51
+ var en = {
52
+ httpStatus: (status, snippet2) => `HTTP ${status}: ${snippet2}`,
53
+ notJson: (status, snippet2) => `Response is not valid JSON (HTTP ${status}): ${snippet2}`
54
+ };
55
+ var S = pick({ zh, en });
56
+ var SNIPPET_MAX = 200;
57
+ function snippet(text) {
58
+ const s = text.trim();
59
+ return s.length > SNIPPET_MAX ? `${s.slice(0, SNIPPET_MAX)}\u2026` : s;
60
+ }
61
+ function isAbortError(err) {
62
+ return err?.name === "AbortError";
63
+ }
64
+ function normalizeError(err, status) {
65
+ if (isAbortError(err)) throw err;
66
+ if (err instanceof ConsoleInvokeError) throw err;
67
+ throw new ConsoleInvokeError(String(err), status);
68
+ }
69
+ async function send(path, init, opts) {
70
+ try {
71
+ const res = await fetch(path, {
72
+ ...init,
73
+ headers: { ...languageHeaders(), ...init.headers },
74
+ ...opts?.signal ? { signal: opts.signal } : {},
75
+ ...opts?.keepalive ? { keepalive: true } : {}
76
+ });
77
+ if (res.status === 401 && res.headers.get(CONSOLE_AUTH_HEADER) !== null) location.reload();
78
+ return res;
79
+ } catch (err) {
80
+ normalizeError(err, 0);
81
+ }
82
+ }
83
+ async function readText(res) {
84
+ try {
85
+ return await res.text();
86
+ } catch (err) {
87
+ normalizeError(err, res.status);
88
+ }
89
+ }
90
+ async function throwHttpError(res) {
91
+ const text = await readText(res);
92
+ let message = `HTTP ${res.status}`;
93
+ try {
94
+ const parsed = JSON.parse(text);
95
+ const err = parsed?.error;
96
+ if (typeof err === "string" && err !== "") message = err;
97
+ } catch {
98
+ if (text.trim() !== "") message = S.httpStatus(res.status, snippet(text));
99
+ }
100
+ throw new ConsoleInvokeError(message, res.status);
101
+ }
102
+ async function readJson(res) {
103
+ if (!res.ok) await throwHttpError(res);
104
+ if (res.status === 204) return null;
105
+ const text = await readText(res);
106
+ if (text.trim() === "") return null;
107
+ try {
108
+ return JSON.parse(text);
109
+ } catch {
110
+ throw new ConsoleInvokeError(S.notJson(res.status, snippet(text)), res.status);
111
+ }
112
+ }
113
+ async function get(path, opts) {
114
+ return readJson(await send(path, { method: "GET" }, opts));
115
+ }
116
+ async function post(path, body, opts) {
117
+ const init = {
118
+ method: "POST",
119
+ headers: { "Content-Type": "application/json" },
120
+ body: JSON.stringify(body ?? {})
121
+ };
122
+ return readJson(await send(path, init, opts));
123
+ }
124
+ async function pickPath(options, opts) {
125
+ const response = await post(PATH_PICKER_ROUTE, options, opts);
126
+ return response.path;
127
+ }
128
+
129
+ // ../../Cortico/src/web/client/ui/icons.ts
130
+ var SVG_NS = "http://www.w3.org/2000/svg";
131
+ var SHAPES = {
132
+ terminal: [
133
+ ["path", { d: "m4 17 6-6-6-6" }],
134
+ ["path", { d: "M12 19h8" }]
135
+ ],
136
+ activity: [
137
+ ["path", { d: "M3 12h4l2-7 4 14 2-7h6" }]
138
+ ],
139
+ chart: [
140
+ ["path", { d: "M4 19V9" }],
141
+ ["path", { d: "M10 19V5" }],
142
+ ["path", { d: "M16 19v-7" }],
143
+ ["path", { d: "M22 19H2" }]
144
+ ],
145
+ boxes: [
146
+ ["path", { d: "m12 2 7 4-7 4-7-4 7-4Z" }],
147
+ ["path", { d: "m5 10 7 4 7-4" }],
148
+ ["path", { d: "m5 14 7 4 7-4" }]
149
+ ],
150
+ bot: [
151
+ ["rect", { x: "5", y: "7", width: "14", height: "12", rx: "3" }],
152
+ ["path", { d: "M12 3v4" }],
153
+ ["circle", { cx: "9", cy: "13", r: "1" }],
154
+ ["circle", { cx: "15", cy: "13", r: "1" }]
155
+ ],
156
+ settings: [
157
+ ["circle", { cx: "12", cy: "12", r: "3" }],
158
+ ["path", { d: "M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1-2.8 2.8-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.5V21h-4v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.9.3l-.1.1L4.2 17l.1-.1a1.7 1.7 0 0 0 .3-1.9 1.7 1.7 0 0 0-1.5-1H3v-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.9L4.2 7 7 4.2l.1.1A1.7 1.7 0 0 0 9 4.6a1.7 1.7 0 0 0 1-1.5V3h4v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.9-.3l.1-.1L19.8 7l-.1.1a1.7 1.7 0 0 0-.3 1.9 1.7 1.7 0 0 0 1.5 1h.1v4h-.1a1.7 1.7 0 0 0-1.5 1Z" }]
159
+ ],
160
+ play: [["path", { d: "m8 5 11 7-11 7V5Z" }]],
161
+ power: [
162
+ ["path", { d: "M12 3v8" }],
163
+ ["path", { d: "M17.7 6.3a8 8 0 1 1-11.4 0" }]
164
+ ],
165
+ pause: [
166
+ ["rect", { x: "7", y: "5", width: "3", height: "14", rx: "1" }],
167
+ ["rect", { x: "14", y: "5", width: "3", height: "14", rx: "1" }]
168
+ ],
169
+ image: [
170
+ ["rect", { x: "3", y: "4", width: "18", height: "16", rx: "3" }],
171
+ ["circle", { cx: "9", cy: "10", r: "2" }],
172
+ ["path", { d: "m21 15-4-4L5 20" }]
173
+ ],
174
+ "folder-open": [
175
+ ["path", { d: "M3 6h6l2 2h10" }],
176
+ ["path", { d: "M3 6v13h15l3-8H6l-3 8" }]
177
+ ],
178
+ download: [
179
+ ["path", { d: "M12 3v12" }],
180
+ ["path", { d: "m7 10 5 5 5-5" }],
181
+ ["path", { d: "M5 21h14" }]
182
+ ],
183
+ cpu: [
184
+ ["rect", { x: "5", y: "5", width: "14", height: "14", rx: "2" }],
185
+ ["rect", { x: "9", y: "9", width: "6", height: "6", rx: "1" }],
186
+ ["path", { d: "M9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3" }]
187
+ ],
188
+ text: [
189
+ ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }],
190
+ ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }],
191
+ ["path", { d: "M10 9H8M16 13H8M16 17H8" }]
192
+ ],
193
+ eye: [
194
+ ["path", { d: "M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z" }],
195
+ ["circle", { cx: "12", cy: "12", r: "3" }]
196
+ ],
197
+ "eye-off": [
198
+ ["path", { d: "M3 3l18 18" }],
199
+ ["path", { d: "M10.6 5.2A10.9 10.9 0 0 1 12 5c6.5 0 10 7 10 7a17.3 17.3 0 0 1-3.2 4" }],
200
+ ["path", { d: "M6.6 6.6C3.8 8.5 2 12 2 12s3.5 7 10 7c1.6 0 3-.4 4.3-1" }],
201
+ ["path", { d: "M9.9 9.9a3 3 0 0 0 4.2 4.2" }]
202
+ ],
203
+ pencil: [
204
+ ["path", { d: "M4 20h4.2L19.4 8.8a2.3 2.3 0 0 0-3.2-3.2L5 16.8V20Z" }],
205
+ ["path", { d: "m12.6 6.5 4.9 4.9" }]
206
+ ],
207
+ refresh: [
208
+ ["path", { d: "M21 12a9 9 0 1 1-2.6-6.4" }],
209
+ ["path", { d: "M21 3v6h-6" }]
210
+ ],
211
+ trash: [
212
+ ["path", { d: "M4 7h16" }],
213
+ ["path", { d: "M9.5 7V5h5v2" }],
214
+ ["path", { d: "M6.5 7v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V7" }],
215
+ ["path", { d: "M10 11v6" }],
216
+ ["path", { d: "M14 11v6" }]
217
+ ]
218
+ };
219
+ function shapesInto(doc, parent, shapes) {
220
+ for (const [tag, attrs] of shapes) {
221
+ const child = doc.createElementNS(SVG_NS, tag);
222
+ for (const [key, value] of Object.entries(attrs)) child.setAttribute(key, value);
223
+ parent.appendChild(child);
224
+ }
225
+ }
226
+ function icon(doc, name, cls = "icon") {
227
+ const svg = doc.createElementNS(SVG_NS, "svg");
228
+ svg.setAttribute("viewBox", "0 0 24 24");
229
+ svg.setAttribute("fill", "none");
230
+ svg.setAttribute("stroke", "currentColor");
231
+ svg.setAttribute("stroke-width", "1.8");
232
+ svg.setAttribute("stroke-linecap", "round");
233
+ svg.setAttribute("stroke-linejoin", "round");
234
+ svg.setAttribute("aria-hidden", "true");
235
+ svg.setAttribute("class", cls);
236
+ shapesInto(doc, svg, SHAPES[name]);
237
+ return svg;
238
+ }
239
+
240
+ // ../../Cortico/src/web/client/features/config/strings.ts
241
+ var zh2 = {
242
+ loading: "\u52A0\u8F7D\u4E2D\u2026",
243
+ optionCurrent: "(\u5F53\u524D)",
244
+ ownerPersona: "Persona",
245
+ chooseFile: "\u9009\u62E9\u6587\u4EF6",
246
+ chooseDirectory: "\u9009\u62E9\u76EE\u5F55",
247
+ recommendedDir: (dir) => `\u63A8\u8350\u76EE\u5F55\uFF1A${dir}`,
248
+ download: "\u4E0B\u8F7D",
249
+ on: "\u5F00\u542F",
250
+ leaveBlank: "\u7559\u7A7A",
251
+ saving: "\u4FDD\u5B58\u4E2D\u2026",
252
+ saveFailed: (err) => "\u5931\u8D25: " + err,
253
+ emptyDefault: "\u6B64\u9875\u6CA1\u6709\u914D\u7F6E\u9879\u3002",
254
+ noSchema: "\u672A\u63D0\u4F9B\u914D\u7F6E\u9879\u3002",
255
+ restartWorld: "\u91CD\u542F World \u751F\u6548",
256
+ restartProcess: "\u91CD\u542F\u751F\u6548",
257
+ loadFailed: (err) => "\u914D\u7F6E\u9879\u52A0\u8F7D\u5931\u8D25: " + err
258
+ };
259
+ var en2 = {
260
+ loading: "Loading\u2026",
261
+ optionCurrent: "(current)",
262
+ ownerPersona: "Persona",
263
+ chooseFile: "Choose file",
264
+ chooseDirectory: "Choose directory",
265
+ recommendedDir: (dir) => `Recommended directory: ${dir}`,
266
+ download: "Download",
267
+ on: "On",
268
+ leaveBlank: "Leave blank",
269
+ saving: "Saving\u2026",
270
+ saveFailed: (err) => "Failed: " + err,
271
+ emptyDefault: "No configuration fields on this page.",
272
+ noSchema: "No configuration fields provided.",
273
+ restartWorld: "takes effect after World restart",
274
+ restartProcess: "takes effect after restart",
275
+ loadFailed: (err) => "Failed to load config: " + err
276
+ };
277
+ var S2 = pick({ zh: zh2, en: en2 });
278
+
279
+ // ../../Cortico/src/web/client/features/config/view.ts
280
+ function mergeOptionList(live, current) {
281
+ const seen = /* @__PURE__ */ new Set();
282
+ const out = [];
283
+ const add = (value, label) => {
284
+ if (seen.has(value)) return;
285
+ seen.add(value);
286
+ out.push({ value, label });
287
+ };
288
+ for (const item of live) add(item.value, item.label);
289
+ if (!seen.has(current)) add(current, current || S2.optionCurrent);
290
+ return out;
291
+ }
292
+ function fillSelect(ui, sel, items, current) {
293
+ sel.replaceChildren();
294
+ for (const item of items) {
295
+ const opt = ui.h("option", null, item.label);
296
+ opt.value = item.value;
297
+ sel.appendChild(opt);
298
+ }
299
+ sel.value = current;
300
+ }
301
+ var OWNER_LABEL = {
302
+ "persona": S2.ownerPersona
303
+ };
304
+ function errText(err) {
305
+ return err instanceof Error ? err.message : String(err);
306
+ }
307
+ function isAbort(err) {
308
+ return err?.name === "AbortError";
309
+ }
310
+ function optionsField(ui, kind, current, onChange, signal) {
311
+ const sel = ui.select({
312
+ options: mergeOptionList([], current),
313
+ value: current,
314
+ onChange
315
+ });
316
+ let seq = 0;
317
+ const refresh = () => {
318
+ const n = ++seq;
319
+ void get(
320
+ `/api/config/options/${encodeURIComponent(kind)}`,
321
+ signal ? { signal } : void 0
322
+ ).then((d) => {
323
+ if (n !== seq || signal?.aborted) return;
324
+ const live = Array.isArray(d.options) ? d.options : [];
325
+ fillSelect(ui, sel, mergeOptionList(live, sel.value), sel.value);
326
+ }).catch((err) => {
327
+ if (isAbort(err) || signal?.aborted) return;
328
+ });
329
+ };
330
+ const listenOpts = signal ? { signal } : void 0;
331
+ sel.addEventListener("pointerdown", refresh, listenOpts);
332
+ sel.addEventListener("focus", refresh, listenOpts);
333
+ refresh();
334
+ return { node: sel, read: () => sel.value };
335
+ }
336
+ function httpDownloadHref(raw) {
337
+ try {
338
+ const url = new URL(raw);
339
+ return url.protocol === "http:" || url.protocol === "https:" ? url.href : null;
340
+ } catch {
341
+ return null;
342
+ }
343
+ }
344
+ function pathField(ui, prop, current, onChange, signal) {
345
+ const spec = prop["x-path"];
346
+ const input = ui.input({ type: "text", value: current, onChange });
347
+ const controls = ui.h("div", "pathfield-controls");
348
+ const choose = ui.button("", {
349
+ size: "sm",
350
+ onClick: () => {
351
+ choose.disabled = true;
352
+ void pickPath({
353
+ kind: spec.kind,
354
+ title: prop.title,
355
+ currentPath: input.value.trim() || void 0,
356
+ recommendedDir: spec.recommendedDir,
357
+ extensions: spec.extensions
358
+ }, signal ? { signal } : void 0).then((selected) => {
359
+ if (!selected || signal?.aborted) return;
360
+ input.value = selected;
361
+ onChange();
362
+ }).catch((err) => {
363
+ if (isAbort(err) || signal?.aborted) return;
364
+ ui.toast(errText(err), "bad");
365
+ }).finally(() => {
366
+ choose.disabled = false;
367
+ });
368
+ }
369
+ });
370
+ choose.className += " pathpick";
371
+ choose.title = spec.kind === "file" ? S2.chooseFile : S2.chooseDirectory;
372
+ choose.setAttribute("aria-label", choose.title);
373
+ choose.appendChild(icon(choose.ownerDocument, "folder-open"));
374
+ controls.append(input, choose);
375
+ const field = ui.h("div", "pathfield");
376
+ field.appendChild(controls);
377
+ const meta = ui.h("div", "pathfield-meta");
378
+ if (spec.recommendedDir) {
379
+ const recommended = ui.h("span", "pathrecommended", S2.recommendedDir(spec.recommendedDir));
380
+ recommended.title = spec.recommendedDir;
381
+ meta.appendChild(recommended);
382
+ }
383
+ const download = prop["x-download"];
384
+ const href = download ? httpDownloadHref(download.href) : null;
385
+ if (download && href) {
386
+ const link = ui.h("a", "pathdownload");
387
+ link.setAttribute("href", href);
388
+ link.setAttribute("target", "_blank");
389
+ link.setAttribute("rel", "noopener noreferrer");
390
+ link.append(icon(link.ownerDocument, "download"), ui.h("span", null, download.label || S2.download));
391
+ meta.appendChild(link);
392
+ }
393
+ if (meta.children.length) field.appendChild(meta);
394
+ return { node: field, read: () => input.value };
395
+ }
396
+ function configField(ui, prop, val, onChange, signal) {
397
+ const changed = () => onChange?.();
398
+ if (prop.type === "boolean") {
399
+ const box = ui.checkbox(S2.on, { checked: !!val, onChange: changed });
400
+ return { node: box.el, read: () => box.checked };
401
+ }
402
+ if (prop.type === "string") {
403
+ if (prop["x-options"]) {
404
+ return optionsField(ui, prop["x-options"], val == null ? "" : String(val), changed, signal);
405
+ }
406
+ if (Array.isArray(prop.enum)) {
407
+ const sel = ui.select({
408
+ options: prop.enum,
409
+ value: val == null ? prop.enum[0] : String(val),
410
+ onChange: changed
411
+ });
412
+ return { node: sel, read: () => sel.value };
413
+ }
414
+ if (prop["x-path"]) {
415
+ return pathField(ui, prop, val == null ? "" : String(val), changed, signal);
416
+ }
417
+ const inp = ui.input({ type: "text", value: val == null ? "" : String(val), onChange: changed });
418
+ return { node: inp, read: () => inp.value };
419
+ }
420
+ if (prop.type === "integer" || prop.type === "number") {
421
+ const scale = prop["x-scale"] || 1;
422
+ const inp = ui.input({ type: "number", onChange: changed });
423
+ if (prop.minimum != null) inp.min = String(prop.minimum / scale);
424
+ if (prop.maximum != null) inp.max = String(prop.maximum / scale);
425
+ if (prop.multipleOf != null) inp.step = String(prop.multipleOf / scale);
426
+ if (prop.nullable) {
427
+ inp.value = val == null ? "" : String(Number(val) / scale);
428
+ inp.placeholder = S2.leaveBlank;
429
+ return {
430
+ node: inp,
431
+ read: () => inp.value.trim() === "" ? null : Number(inp.value) * scale
432
+ };
433
+ }
434
+ inp.value = String((Number(val) || 0) / scale);
435
+ return { node: inp, read: () => Number(inp.value) * scale };
436
+ }
437
+ const itemType = prop.items?.type;
438
+ if (prop.type === "array" && (itemType === "integer" || itemType === "number")) {
439
+ const scale = prop["x-scale"] || 1;
440
+ const spec = prop.items || {};
441
+ const mk = (v) => {
442
+ const inp = ui.input({ type: "number", value: String((Number(v) || 0) / scale), onChange: changed });
443
+ if (spec.minimum != null) inp.min = String(spec.minimum / scale);
444
+ if (spec.maximum != null) inp.max = String(spec.maximum / scale);
445
+ return inp;
446
+ };
447
+ const pair = Array.isArray(val) ? val : [0, 0];
448
+ const a = mk(pair[0]);
449
+ const b = mk(pair[1]);
450
+ const wrap = ui.h("div", "pairfield");
451
+ wrap.append(a, ui.h("span", "pairsep", "\u2013"), b);
452
+ return {
453
+ node: wrap,
454
+ read: () => [Number(a.value) * scale, Number(b.value) * scale]
455
+ };
456
+ }
457
+ return { node: ui.h("span", "tdesc", JSON.stringify(val)), read: null };
458
+ }
459
+
460
+ // ../../Cortico/src/providers/openai-responses-compat/strings.ts
461
+ var panelZh = {
462
+ title: "\u601D\u7EF4\u94FE",
463
+ encrypted: "\u52A0\u5BC6",
464
+ plaintext: "\u660E\u6587",
465
+ detect: "\u6211\u4E0D\u77E5\u9053,\u6D4B\u4E00\u4E0B",
466
+ detecting: "\u63A2\u6D4B\u4E2D",
467
+ saved: "\u5DF2\u4FDD\u5B58",
468
+ accepted: "\u901A\u8FC7",
469
+ rejected: (status, error) => `\u88AB\u62D2${status ? ` ${status}` : ""}:${error}`,
470
+ skipped: "\u672A\u6D4B",
471
+ outcome: (bare, withReasoning) => `\u4E0D\u5E26\u601D\u7EF4\u94FE\u7684\u5408\u6210\u8C03\u7528:${bare};\u5E26\u660E\u6587\u601D\u7EF4\u94FE:${withReasoning}`,
472
+ applied: (label) => `\u5DF2\u8BBE\u4E3A${label}`,
473
+ undetermined: "\u5224\u65AD\u4E0D\u51FA,\u8BBE\u7F6E\u672A\u6539"
474
+ };
475
+ var panelEn = {
476
+ title: "Reasoning",
477
+ encrypted: "Encrypted",
478
+ plaintext: "Plaintext",
479
+ detect: "Not sure, test it",
480
+ detecting: "Testing",
481
+ saved: "Saved",
482
+ accepted: "accepted",
483
+ rejected: (status, error) => `rejected${status ? ` ${status}` : ""}: ${error}`,
484
+ skipped: "not tested",
485
+ outcome: (bare, withReasoning) => `Synthetic call without reasoning: ${bare}; with plaintext reasoning: ${withReasoning}`,
486
+ applied: (label) => `Set to ${label}`,
487
+ undetermined: "Undetermined; the setting is unchanged"
488
+ };
489
+ var panel = { zh: panelZh, en: panelEn };
490
+
491
+ // ../../Cortico/src/providers/openai-responses-compat/console/reasoning-panel.ts
492
+ var reasoningPanel = {
493
+ mount: async (ctx) => {
494
+ const { ui, root } = ctx;
495
+ const S3 = ctx.language === "en" ? panel.en : panel.zh;
496
+ const name = ctx.scope.instance;
497
+ const path = `providers.${name}.options.reasoningReplay`;
498
+ const textPath = `providers.${name}.options.syntheticReasoningText`;
499
+ const labels = { encrypted: S3.encrypted, plaintext: S3.plaintext };
500
+ const card = ui.sheet({ title: S3.title });
501
+ const message = ui.msgline();
502
+ root.append(card.el, message);
503
+ const outcome = (probe) => !probe ? S3.skipped : probe.ok ? S3.accepted : S3.rejected(probe.status, probe.error);
504
+ const describe = (result) => `${S3.outcome(outcome(result.bare), outcome(result.withReasoning))}\u3002${result.verdict ? S3.applied(labels[result.verdict]) : S3.undetermined}`;
505
+ async function save(groupId, key, value) {
506
+ try {
507
+ await ctx.setConfig(groupId, { [key]: value });
508
+ message.textContent = S3.saved;
509
+ } catch (error) {
510
+ message.textContent = String(error);
511
+ }
512
+ }
513
+ async function detect(button) {
514
+ const release = ui.disable(button);
515
+ message.textContent = S3.detecting;
516
+ try {
517
+ message.textContent = describe(await ctx.invoke("detect", [{ name }]));
518
+ } catch (error) {
519
+ message.textContent = String(error);
520
+ } finally {
521
+ release.dispose();
522
+ }
523
+ await load();
524
+ }
525
+ async function load() {
526
+ let state;
527
+ try {
528
+ state = await ctx.invoke("state", [{ name }]);
529
+ } catch (error) {
530
+ message.textContent = String(error);
531
+ return;
532
+ }
533
+ if (ctx.signal.aborted) return;
534
+ const { group, values } = state.config[0];
535
+ const property = group.schema.properties[path];
536
+ const current = values[path];
537
+ const select = ui.select({
538
+ value: typeof current === "string" && current ? current : "encrypted",
539
+ options: Object.entries(labels).map(([value, label]) => ({ value, label })),
540
+ onChange: (value) => void save(group.id, path, value)
541
+ });
542
+ select.setAttribute("aria-label", property.title);
543
+ const button = ui.button(S3.detect, { onClick: () => void detect(button) });
544
+ const row = ui.rowbar();
545
+ row.append(select, button);
546
+ card.body.replaceChildren(ui.field(property.title, row));
547
+ if (property.description) card.body.append(ui.msgline(property.description));
548
+ const textProperty = group.schema.properties[textPath];
549
+ const text = configField(ui, textProperty, values[textPath], () => {
550
+ if (text.read) void save(group.id, textPath, String(text.read()).trim());
551
+ }, ctx.signal);
552
+ text.node.setAttribute("aria-label", textProperty.title);
553
+ card.body.append(ui.field(textProperty.title, text.node));
554
+ if (textProperty.description) card.body.append(ui.msgline(textProperty.description));
555
+ }
556
+ await load();
557
+ }
558
+ };
559
+
560
+ // ../../Cortico/src/providers/openai-responses-compat/console/client.ts
561
+ var client_default = { panels: { reasoning: reasoningPanel } };
562
+
563
+ // ../../Cortico/src/web/client/console-pages/builtins/llm-settings/strings.ts
564
+ var zh3 = {
565
+ saved: "\u5DF2\u4FDD\u5B58\uFF0C\u4E0B\u4E00\u6B21\u8BF7\u6C42\u751F\u6548\u3002",
566
+ instancesTitle: "\u4F9B\u5E94\u5B9E\u4F8B",
567
+ instancesDescription: "\u6BCF\u4E2A\u5B9E\u4F8B\u72EC\u7ACB\u4FDD\u5B58\u8FDE\u63A5\u3001\u6A21\u578B\u6863\u4E0E\u62A5\u4EF7\u3002\u5F53\u524D\u8BF7\u6C42\u4E0E\u5DF2\u542F\u52A8\u7684\u540E\u53F0\u4F1A\u8BDD\u4FDD\u6301\u539F\u6709\u7ED1\u5B9A\u3002",
568
+ activeSuffix: " \xB7 \u5F53\u524D",
569
+ instanceField: "\u4F9B\u5E94\u5B9E\u4F8B",
570
+ newInstanceName: "\u65B0\u5B9E\u4F8B\u540D\u79F0",
571
+ newInstanceUrl: "HTTP(S) \u4F9B\u5E94\u5730\u5740",
572
+ addInstance: "\u6DFB\u52A0\u5B9E\u4F8B",
573
+ connectionTitle: "\u8FDE\u63A5",
574
+ connectionDescription: "\u5730\u5740\u4E0E\u5BC6\u94A5\u5168\u5C40\u5171\u7528\uFF1A\u522B\u7684\u90E8\u7F72\u9009\u4E2D\u540C\u4E00\u5B9E\u4F8B\u65F6\u8BFB\u7684\u662F\u540C\u4E00\u4EFD\u3002",
575
+ baseUrl: "\u4F9B\u5E94\u5730\u5740",
576
+ secretName: "\u5BC6\u94A5\u53D8\u91CF\u540D",
577
+ secretNamePlaceholder: "\u73AF\u5883\u53D8\u91CF\u540D\uFF1B\u7559\u7A7A = \u65E0\u9274\u6743",
578
+ secretStatus: "\u5BC6\u94A5",
579
+ secretSource: { env: "\u8FDB\u7A0B\u73AF\u5883", file: "\u7AEF\u70B9 .env", none: "\u672A\u914D\u7F6E" },
580
+ secretValue: "\u5BC6\u94A5\u503C",
581
+ secretValuePlaceholder: "\u53EA\u5199\u5165\u7AEF\u70B9 .env\uFF0C\u4E0D\u56DE\u663E",
582
+ saveSecret: "\u5199\u5165\u5BC6\u94A5",
583
+ secretSaved: "\u5BC6\u94A5\u5DF2\u5199\u5165\u7AEF\u70B9 .env\u3002",
584
+ secretNameFirst: "\u5148\u4FDD\u5B58\u5BC6\u94A5\u53D8\u91CF\u540D\uFF0C\u518D\u5199\u5165\u5BC6\u94A5\u503C\u3002",
585
+ multimodal: "\u63A5\u53D7\u56FE\u7247\u8F93\u5165",
586
+ endpointPath: "\u8BF7\u6C42\u8DEF\u5F84",
587
+ extraHeaders: "\u9644\u52A0\u8BF7\u6C42\u5934\uFF08JSON \u5BF9\u8C61\uFF09",
588
+ extraBody: "\u9644\u52A0\u8BF7\u6C42\u4F53\uFF08JSON \u5BF9\u8C61\uFF09",
589
+ jsonObjectRequired: (label) => `${label} \u5FC5\u987B\u662F JSON \u5BF9\u8C61`,
590
+ advancedProtocolTitle: "\u534F\u8BAE\u4E0E\u8BF7\u6C42\u6269\u5C55",
591
+ advancedProtocolDescription: "\u9488\u5BF9 OpenAI Responses \u517C\u5BB9\u7AEF\u70B9\u7684\u9AD8\u7EA7\u914D\u7F6E\uFF08\u7AEF\u70B9\u8DEF\u5F84\u4E0E\u9644\u52A0 JSON \u5B57\u6BB5\uFF09\u3002",
592
+ modelFieldLabel: "\u6A21\u578B\u6807\u8BC6",
593
+ effortFieldLabel: "\u63A8\u7406\u5F3A\u5EA6",
594
+ temperatureFieldLabel: "\u91C7\u6837\u6E29\u5EA6",
595
+ specTitle: "\u6A21\u578B\u6863",
596
+ specDescription: "\u914D\u7F6E\u6B64\u5B9E\u4F8B\u8C03\u7528\u7684\u6A21\u578B\u53CA\u63A8\u7406\u3001\u6E29\u5EA6\u548C Token \u9650\u5236\u7B49\u751F\u6210\u53C2\u6570\u3002",
597
+ modelName: "\u660E\u786E\u6A21\u578B\u540D",
598
+ fetchModels: "\u53D6\u6A21\u578B\u5217\u8868",
599
+ modelsFetched: (count) => `\u53D6\u5230 ${count} \u4E2A\u6A21\u578B\u3002`,
600
+ modelListFailed: (message) => `\u53D6\u4E0D\u5230\u6A21\u578B\u5217\u8868\uFF1A${message}`,
601
+ selectModel: "\u9009\u62E9\u6A21\u578B",
602
+ unsupportedTier: (current) => `\u5F53\u524D\u6863\u4F4D\u672A\u652F\u6301\uFF1A${current}`,
603
+ thinkingOn: "\u5F00\u542F",
604
+ thinkingOff: "\u5173\u95ED",
605
+ effortPlaceholder: "\u63A8\u7406\u5F3A\u5EA6\uFF1B\u7A7A = \u7AEF\u70B9\u9ED8\u8BA4\uFF0Cnone = \u5173\u95ED",
606
+ effortAria: "\u63A8\u7406\u5F3A\u5EA6",
607
+ temperaturePlaceholder: "\u6E29\u5EA6\u9ED8\u8BA4",
608
+ modelAria: "\u6A21\u578B",
609
+ tierAria: "\u63A8\u7406\u6863\u4F4D",
610
+ temperatureAria: "\u6E29\u5EA6",
611
+ maxTokens: "\u6700\u5927\u8F93\u51FA token",
612
+ contextWindow: "\u4E0A\u4E0B\u6587\u7A97\u53E3",
613
+ serviceTier: "\u670D\u52A1\u6863",
614
+ serverDefault: "\u670D\u52A1\u7AEF\u9ED8\u8BA4",
615
+ activate: "\u8BBE\u4E3A\u5F53\u524D\u4F9B\u5E94\u5B9E\u4F8B",
616
+ probe: "\u6D4B\u8BD5\u53EF\u7528\u6027",
617
+ probeTitle: "\u6D4B\u8BD5\u7ED3\u679C",
618
+ probeStatus: "\u72B6\u6001",
619
+ probeOk: "\u6210\u529F",
620
+ probeFailed: "\u5931\u8D25",
621
+ probeLatency: "\u8017\u65F6",
622
+ probeModel: "\u56DE\u663E\u6A21\u578B",
623
+ probeUsage: "\u7528\u91CF",
624
+ probeUsageLine: (input, cached, output, reasoning) => `\u8F93\u5165 ${input} \xB7 \u7F13\u5B58\u547D\u4E2D ${cached} \xB7 \u8F93\u51FA ${output} \xB7 \u63A8\u7406 ${reasoning}`,
625
+ probeEncrypted: "\u52A0\u5BC6\u601D\u7EF4\u94FE",
626
+ yes: "\u6709",
627
+ no: "\u65E0",
628
+ probeCost: "\u672C\u6B21\u8D39\u7528",
629
+ duplicate: "\u590D\u5236",
630
+ duplicateName: "\u526F\u672C\u540D\u79F0",
631
+ duplicateConfirm: "\u590D\u5236\u4E3A",
632
+ duplicated: "\u5DF2\u590D\u5236\u3002",
633
+ delete: "\u5220\u9664",
634
+ deleteConfirmTitle: (name) => `\u5220\u9664\u5B9E\u4F8B ${name}\uFF1F`,
635
+ deleteConfirmBody: "\u7AEF\u70B9\u914D\u7F6E\u4E0E .env \u4E00\u5E76\u5220\u9664\u3002\u522B\u7684\u90E8\u7F72\u82E5\u9009\u4E2D\u4E86\u5B83\uFF0C\u65E0\u6CD5\u5728\u6B64\u5F97\u77E5\u3002",
636
+ deleted: "\u5DF2\u5220\u9664\u3002",
637
+ pricingTitle: "\u62A5\u4EF7",
638
+ pricingDescription: "\u5386\u53F2\u6D41\u6C34\u56FA\u5B9A\u4F7F\u7528\u8BF7\u6C42\u65F6\u7684\u62A5\u4EF7\u3002\u81EA\u5B9A\u4E49\u62A5\u4EF7\u6309\u6A21\u578B\u4E0E\u8D39\u7528\u53E3\u5F84\u8986\u76D6\u6A21\u5757\u9ED8\u8BA4\u503C\u3002",
639
+ pricingUnset: "\u672A\u8BBE\u81EA\u5B9A\u4E49\u62A5\u4EF7\uFF1A\u4F18\u5148\u4F7F\u7528\u6A21\u5757\u4EF7\u76EE\uFF1B\u82E5\u65E0\u9002\u7528\u4EF7\u76EE\uFF0C\u4EC5\u8BB0\u5F55 token\uFF0C\u4E0D\u8BA1\u91D1\u989D\u3002",
640
+ meters: {
641
+ input: "\u8F93\u5165",
642
+ cachedInput: "\u7F13\u5B58\u547D\u4E2D",
643
+ uncachedInput: "\u672A\u7F13\u5B58\u8F93\u5165",
644
+ output: "\u8F93\u51FA",
645
+ reasoning: "\u63A8\u7406",
646
+ total: "\u603B\u91CF"
647
+ },
648
+ marginal: "\u8FB9\u9645\u8D39\u7528",
649
+ equivalent: "API \u7B49\u4EF7\u8D39\u7528",
650
+ perMillion: (label, rate) => `${label} ${rate}/\u767E\u4E07`,
651
+ free: "\u5DF2\u660E\u786E\u514D\u8D39",
652
+ bandsNote: "\u542B\u8F93\u5165\u9636\u68AF\u6216\u670D\u52A1\u6863\uFF1B\u6309\u672C\u6B21\u5B9E\u9645\u7528\u91CF\u4E0E\u670D\u52A1\u6863\u8BA1\u8D39\u3002",
653
+ rateCached: "\u7F13\u5B58\u547D\u4E2D / \u767E\u4E07 token",
654
+ rateUncached: "\u672A\u7F13\u5B58\u8F93\u5165 / \u767E\u4E07 token",
655
+ rateOutput: "\u8F93\u51FA / \u767E\u4E07 token",
656
+ currencyField: "\u5E01\u79CD",
657
+ costFormNote: "\u57FA\u7840\u8D39\u7387\u7EDF\u4E00\u9002\u7528\u4E8E\u5168\u90E8\u6A21\u578B\uFF1B\u9636\u68AF\u6216\u591A\u6A21\u578B\u89C4\u5219\u8BF7\u5728\u4E0B\u65B9\u5B8C\u6574\u89C4\u5219\u4E2D\u914D\u7F6E\u3002",
658
+ costFormOverridden: "\u5F53\u524D\u62A5\u4EF7\u4E0D\u662F\u4E09\u683C\u8868\u80FD\u8868\u8FBE\u7684\u5F62\u72B6\uFF0C\u4EE5\u4E0B\u65B9\u5B8C\u6574\u89C4\u5219\u4E3A\u51C6\uFF1B\u6539\u52A8\u4E09\u683C\u8868\u4F1A\u8986\u76D6\u5B83\u3002",
659
+ editFull: "\u9AD8\u7EA7\u5B9A\u4EF7\u89C4\u5219 (JSON)",
660
+ fullNote: "\u7A7A\u6570\u7EC4\u6062\u590D\u6A21\u5757\u9ED8\u8BA4\u62A5\u4EF7\uFF1Brules \u4E3A\u7A7A\u6570\u7EC4\u8868\u793A\u660E\u786E\u514D\u8D39\u3002\u5B8C\u6574\u89C4\u5219\u652F\u6301\u8F93\u5165\u9636\u68AF\u3001\u670D\u52A1\u6863\u53CA\u989D\u5916\u8BA1\u91CF\u5355\u4F4D\u3002",
661
+ viewSnapshot: "\u67E5\u770B\u5F53\u524D\u751F\u6548\u62A5\u4EF7\u5FEB\u7167"
662
+ };
663
+ var en3 = {
664
+ saved: "Saved; applies from the next request.",
665
+ instancesTitle: "Provider instances",
666
+ instancesDescription: "Each instance keeps its own connection, model spec and pricing. In-flight requests and running background sessions keep their existing binding.",
667
+ activeSuffix: " \xB7 active",
668
+ instanceField: "Provider instance",
669
+ newInstanceName: "New instance name",
670
+ newInstanceUrl: "HTTP(S) provider URL",
671
+ addInstance: "Add instance",
672
+ connectionTitle: "Connection",
673
+ connectionDescription: "URL and key are global: other deployments selecting this instance read the same copy.",
674
+ baseUrl: "Provider URL",
675
+ secretName: "Key variable name",
676
+ secretNamePlaceholder: "Environment variable name; empty = no auth",
677
+ secretStatus: "API key",
678
+ secretSource: { env: "process env", file: "endpoint .env", none: "not set" },
679
+ secretValue: "Key value",
680
+ secretValuePlaceholder: "Written to the endpoint .env only; never shown",
681
+ saveSecret: "Save key",
682
+ secretSaved: "Key written to the endpoint .env.",
683
+ secretNameFirst: "Save the key variable name before writing a key value.",
684
+ multimodal: "Accepts image input",
685
+ endpointPath: "Request path",
686
+ extraHeaders: "Extra headers (JSON object)",
687
+ extraBody: "Extra body (JSON object)",
688
+ jsonObjectRequired: (label) => `${label} must be a JSON object`,
689
+ advancedProtocolTitle: "Protocol & Request Overrides",
690
+ advancedProtocolDescription: "Advanced options for OpenAI Responses compatible endpoints (custom path and extra JSON fields).",
691
+ modelFieldLabel: "Model identifier",
692
+ effortFieldLabel: "Reasoning effort",
693
+ temperatureFieldLabel: "Sampling temperature",
694
+ specTitle: "Model",
695
+ specDescription: "Configure model identifier, reasoning effort, temperature and token limits for this instance.",
696
+ modelName: "Exact model name",
697
+ fetchModels: "Fetch models",
698
+ modelsFetched: (count) => `Fetched ${count} models.`,
699
+ modelListFailed: (message) => `Could not fetch the model list: ${message}`,
700
+ selectModel: "Pick a model",
701
+ unsupportedTier: (current) => `Unsupported current tier: ${current}`,
702
+ thinkingOn: "on",
703
+ thinkingOff: "off",
704
+ effortPlaceholder: "Reasoning effort; empty = endpoint default, none = off",
705
+ effortAria: "Reasoning effort",
706
+ temperaturePlaceholder: "Default temperature",
707
+ modelAria: "Model",
708
+ tierAria: "Reasoning tier",
709
+ temperatureAria: "Temperature",
710
+ maxTokens: "Max output tokens",
711
+ contextWindow: "Context window",
712
+ serviceTier: "Service tier",
713
+ serverDefault: "Server default",
714
+ activate: "Set as active provider instance",
715
+ probe: "Test endpoint",
716
+ probeTitle: "Test result",
717
+ probeStatus: "Status",
718
+ probeOk: "ok",
719
+ probeFailed: "failed",
720
+ probeLatency: "Latency",
721
+ probeModel: "Model echoed",
722
+ probeUsage: "Usage",
723
+ probeUsageLine: (input, cached, output, reasoning) => `input ${input} \xB7 cached ${cached} \xB7 output ${output} \xB7 reasoning ${reasoning}`,
724
+ probeEncrypted: "Encrypted reasoning",
725
+ yes: "yes",
726
+ no: "no",
727
+ probeCost: "Cost of this call",
728
+ duplicate: "Duplicate",
729
+ duplicateName: "Copy name",
730
+ duplicateConfirm: "Duplicate as",
731
+ duplicated: "Duplicated.",
732
+ delete: "Delete",
733
+ deleteConfirmTitle: (name) => `Delete instance ${name}?`,
734
+ deleteConfirmBody: "Removes the endpoint config and its .env. Whether another deployment selects it cannot be known here.",
735
+ deleted: "Deleted.",
736
+ pricingTitle: "Pricing",
737
+ pricingDescription: "Historical records keep the quote in effect at request time. Custom quotes override module defaults per model and cost basis.",
738
+ pricingUnset: "No custom pricing: module prices apply when available; otherwise only tokens are recorded.",
739
+ meters: {
740
+ input: "Input",
741
+ cachedInput: "Cache hit",
742
+ uncachedInput: "Uncached input",
743
+ output: "Output",
744
+ reasoning: "Reasoning",
745
+ total: "Total"
746
+ },
747
+ marginal: "Marginal cost",
748
+ equivalent: "API-equivalent cost",
749
+ perMillion: (label, rate) => `${label} ${rate}/M`,
750
+ free: "Explicitly free",
751
+ bandsNote: "Includes input bands or service tiers; billed by actual usage and service tier per request.",
752
+ rateCached: "Cache hit / M tokens",
753
+ rateUncached: "Uncached input / M tokens",
754
+ rateOutput: "Output / M tokens",
755
+ currencyField: "Currency",
756
+ costFormNote: "Base rates apply to all models; input bands and service tiers go in the full rules below.",
757
+ costFormOverridden: "The saved pricing is not a shape the three-rate form can express; the full rules below apply. Editing the form replaces them.",
758
+ editFull: "Advanced Pricing Rules (JSON)",
759
+ fullNote: "An empty array restores the module default quote; an empty rules array means explicitly free. Full rules support input bands, service tiers and extra meters.",
760
+ viewSnapshot: "View active pricing snapshot"
761
+ };
762
+ var panel2 = { zh: zh3, en: en3 };
763
+
764
+ // ../../Cortico/src/web/client/console-pages/builtins/llm-settings/pricing-panel.ts
765
+ var FORM_METERS = ["cachedInput", "uncachedInput", "output"];
766
+ function readSimple(saved) {
767
+ if (saved.length !== 1) return null;
768
+ const definition = saved[0];
769
+ if (!definition || typeof definition !== "object") return null;
770
+ const models = definition.models;
771
+ if (!Array.isArray(models) || models.length !== 1 || models[0] !== "*") return null;
772
+ if (definition.basis !== "marginal" || typeof definition.currency !== "string") return null;
773
+ if (definition.inputBands !== void 0 || definition.serviceTiers !== void 0) return null;
774
+ const rules = definition.rules;
775
+ if (!Array.isArray(rules) || rules.length !== FORM_METERS.length) return null;
776
+ const rates = FORM_METERS.map((meter) => {
777
+ const rule = rules.find((rule2) => rule2.meter === meter);
778
+ return rule && typeof rule.perMillion === "number" ? rule.perMillion : NaN;
779
+ });
780
+ if (rates.some((rate) => Number.isNaN(rate))) return null;
781
+ return { currency: definition.currency, rates };
782
+ }
783
+ function writeSimple(cost) {
784
+ return [
785
+ {
786
+ models: ["*"],
787
+ currency: cost.currency,
788
+ basis: "marginal",
789
+ source: "console",
790
+ rules: FORM_METERS.map((meter, i) => ({ meter, perMillion: cost.rates[i] }))
791
+ }
792
+ ];
793
+ }
794
+ function pricingEditor(ui, saved, quotes, commit, language, draft) {
795
+ const S3 = language === "en" ? panel2.en : panel2.zh;
796
+ const card = ui.sheet({
797
+ title: S3.pricingTitle,
798
+ desc: S3.pricingDescription
799
+ });
800
+ const labels = S3.meters;
801
+ for (const row of quotes) {
802
+ for (const quote of row.quotes) {
803
+ card.body.append(
804
+ ui.kv([
805
+ {
806
+ k: row.model,
807
+ v: `${quote.currency} \xB7 ${quote.basis === "marginal" ? S3.marginal : S3.equivalent}`
808
+ }
809
+ ]),
810
+ ui.msgline(
811
+ quote.rules.length ? quote.rules.map((rule) => S3.perMillion(labels[rule.meter] ?? rule.meter, rule.perMillion)).join(" \xB7 ") : S3.free
812
+ ),
813
+ ui.msgline(quote.source)
814
+ );
815
+ if (quote.inputBands?.length || quote.serviceTiers)
816
+ card.body.append(ui.msgline(S3.bandsNote));
817
+ }
818
+ }
819
+ const unset = saved.length === 0;
820
+ const pricingNote = ui.h("p", "field-note pricing-note");
821
+ const updateNote = (pricing) => {
822
+ pricingNote.textContent = pricing.length ? "" : S3.pricingUnset;
823
+ pricingNote.hidden = pricing.length > 0;
824
+ };
825
+ updateNote(saved);
826
+ card.body.append(pricingNote);
827
+ const simple = unset ? null : readSimple(saved);
828
+ const raw = ui.textarea({
829
+ rows: 10,
830
+ value: draft?.raw ?? JSON.stringify(simple ? writeSimple(simple) : saved, null, 2),
831
+ onChange: commitDraft
832
+ });
833
+ const currency = ui.input({ value: simple?.currency ?? "USD", onChange: writeThrough });
834
+ currency.setAttribute("aria-label", S3.currencyField);
835
+ const problem = ui.msgline();
836
+ const rateLabels = [S3.rateCached, S3.rateUncached, S3.rateOutput];
837
+ const rates = rateLabels.map((label, i) => {
838
+ const input = ui.input({
839
+ type: "number",
840
+ value: simple ? String(simple.rates[i]) : "",
841
+ onChange: writeThrough
842
+ });
843
+ input.min = "0";
844
+ input.step = "any";
845
+ input.setAttribute("aria-label", label);
846
+ return input;
847
+ });
848
+ function writeThrough() {
849
+ const blank = rates.every((input) => input.value.trim() === "");
850
+ raw.value = blank ? "[]" : JSON.stringify(
851
+ writeSimple({
852
+ currency: currency.value.trim() || "USD",
853
+ rates: rates.map((input) => Number(input.value) || 0)
854
+ }),
855
+ null,
856
+ 2
857
+ );
858
+ commitDraft();
859
+ }
860
+ function commitDraft() {
861
+ try {
862
+ const pricing = JSON.parse(raw.value.trim() || "[]");
863
+ if (!Array.isArray(pricing)) throw new Error(S3.pricingTitle + ": JSON array required");
864
+ problem.textContent = "";
865
+ problem.classList.remove("bad");
866
+ raw.setAttribute("aria-invalid", "false");
867
+ updateNote(pricing);
868
+ commit(pricing);
869
+ draft?.onRaw(raw.value);
870
+ return true;
871
+ } catch (error) {
872
+ problem.textContent = String(error);
873
+ problem.classList.add("bad");
874
+ raw.setAttribute("aria-invalid", "true");
875
+ draft?.onRaw(raw.value);
876
+ return false;
877
+ }
878
+ }
879
+ card.body.append(
880
+ ui.field(S3.currencyField, currency),
881
+ ...rates.map((input, i) => ui.field(rateLabels[i], input)),
882
+ ui.msgline(simple || unset ? S3.costFormNote : S3.costFormOverridden)
883
+ );
884
+ const advanced = ui.h("details", "pricing-rules");
885
+ advanced.open = !simple && !unset;
886
+ advanced.append(ui.h("summary", null, S3.editFull), raw, ui.msgline(S3.fullNote), problem);
887
+ const preview = ui.h("details", "pricing-snapshot");
888
+ preview.append(
889
+ ui.h("summary", null, S3.viewSnapshot),
890
+ ui.h("pre", "mono", JSON.stringify(quotes, null, 2))
891
+ );
892
+ card.body.append(advanced, preview);
893
+ if (draft?.raw !== void 0) commitDraft();
894
+ return { el: card.el, body: card.body, validate: commitDraft };
895
+ }
896
+
897
+ // pricing.ts
898
+ var defaultPricingSchedule = {
899
+ windows: [
900
+ { from: "09:00", to: "12:00" },
901
+ { from: "14:00", to: "18:00" }
902
+ ],
903
+ exceptDates: [
904
+ "2026-01-01",
905
+ "2026-01-02",
906
+ "2026-01-03",
907
+ "2026-02-15",
908
+ "2026-02-16",
909
+ "2026-02-17",
910
+ "2026-02-18",
911
+ "2026-02-19",
912
+ "2026-02-20",
913
+ "2026-02-21",
914
+ "2026-02-22",
915
+ "2026-02-23",
916
+ "2026-04-04",
917
+ "2026-04-05",
918
+ "2026-04-06",
919
+ "2026-05-01",
920
+ "2026-05-02",
921
+ "2026-05-03",
922
+ "2026-05-04",
923
+ "2026-05-05",
924
+ "2026-06-19",
925
+ "2026-06-20",
926
+ "2026-06-21",
927
+ "2026-09-25",
928
+ "2026-09-26",
929
+ "2026-09-27",
930
+ "2026-10-01",
931
+ "2026-10-02",
932
+ "2026-10-03",
933
+ "2026-10-04",
934
+ "2026-10-05",
935
+ "2026-10-06",
936
+ "2026-10-07"
937
+ ]
938
+ };
939
+ var TIME = /^(?:[01]\d|2[0-3]):[0-5]\d$/;
940
+ var DATE = /^\d{4}-\d{2}-\d{2}$/;
941
+ function parsePricingSchedule(value) {
942
+ if (value === void 0 || value === "") return structuredClone(defaultPricingSchedule);
943
+ let parsed;
944
+ try {
945
+ parsed = typeof value === "string" ? JSON.parse(value) : value;
946
+ } catch {
947
+ throw new Error("Invalid DeepSeek pricing schedule JSON");
948
+ }
949
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Invalid DeepSeek pricing schedule");
950
+ const candidate = parsed;
951
+ if (!Array.isArray(candidate.windows) || candidate.windows.length !== 2 || candidate.windows.some((window) => !window || !TIME.test(window.from) || !TIME.test(window.to) || window.from >= window.to) || candidate.windows[0].to > candidate.windows[1].from) {
952
+ throw new Error("Peak windows must be two ordered, non-overlapping HH:MM ranges");
953
+ }
954
+ if (!Array.isArray(candidate.exceptDates) || candidate.exceptDates.some((date) => {
955
+ if (typeof date !== "string" || !DATE.test(date)) return true;
956
+ const value2 = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
957
+ return !Number.isFinite(value2.valueOf()) || value2.toISOString().slice(0, 10) !== date;
958
+ })) throw new Error("Exception dates must use YYYY-MM-DD");
959
+ return {
960
+ windows: candidate.windows.map(({ from, to }) => ({ from, to })),
961
+ exceptDates: [...new Set(candidate.exceptDates)].sort()
962
+ };
963
+ }
964
+ function currentPricingBand(scheduleValue, at) {
965
+ const schedule = parsePricingSchedule(scheduleValue);
966
+ const parts = new Intl.DateTimeFormat("en-GB", {
967
+ timeZone: "Asia/Shanghai",
968
+ weekday: "short",
969
+ year: "numeric",
970
+ month: "2-digit",
971
+ day: "2-digit",
972
+ hour: "2-digit",
973
+ minute: "2-digit",
974
+ hourCycle: "h23"
975
+ }).formatToParts(at);
976
+ const part = (type) => parts.find((item) => item.type === type)?.value ?? "";
977
+ const date = `${part("year")}-${part("month")}-${part("day")}`;
978
+ const weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].indexOf(part("weekday")) + 1;
979
+ const time = `${part("hour")}:${part("minute")}`;
980
+ if (weekday < 1 || weekday > 5 || schedule.exceptDates.includes(date)) return "offPeak";
981
+ return schedule.windows.some(({ from, to }) => from <= time && time < to) ? "peak" : "offPeak";
982
+ }
983
+
984
+ // console/pricing-panel.ts
985
+ var pricingPanel = {
986
+ mount: async (ctx) => {
987
+ const zh4 = ctx.language === "zh";
988
+ const S3 = zh4 ? {
989
+ title: "DeepSeek \u5B98\u65B9\u4EF7\u76EE",
990
+ current: "\u5F53\u524D\u8BA1\u4EF7\u6863\u4F4D",
991
+ peak: "\u9AD8\u5CF0",
992
+ offPeak: "\u7A7A\u95F2",
993
+ model: "\u6A21\u578B",
994
+ meter: "\u7528\u91CF",
995
+ cached: "\u8F93\u5165\uFF08\u7F13\u5B58\u547D\u4E2D\uFF09",
996
+ uncached: "\u8F93\u5165\uFF08\u7F13\u5B58\u672A\u547D\u4E2D\uFF09",
997
+ output: "\u8F93\u51FA",
998
+ custom: "\u7AEF\u70B9\u81EA\u5B9A\u4E49\u62A5\u4EF7",
999
+ customOn: "\u5DF2\u8BBE\u7F6E\u8986\u76D6",
1000
+ fallback: "\u672A\u8BBE\u7F6E\uFF0C\u4F7F\u7528\u6A21\u5757\u4EF7\u76EE",
1001
+ save: "\u5E94\u7528\u62A5\u4EF7",
1002
+ saved: "\u62A5\u4EF7\u5DF2\u5199\u5165\u8FDE\u63A5\u8349\u7A3F\uFF1B\u4FDD\u5B58\u8FDE\u63A5\u540E\u751F\u6548",
1003
+ savedNow: "\u62A5\u4EF7\u5DF2\u4FDD\u5B58",
1004
+ choose: "DeepSeek \u7AEF\u70B9",
1005
+ loadError: "\u65E0\u6CD5\u8BFB\u53D6\u4EF7\u76EE",
1006
+ noInstances: "\u6CA1\u6709\u53EF\u7528\u7684 DeepSeek \u7AEF\u70B9"
1007
+ } : {
1008
+ title: "DeepSeek official rates",
1009
+ current: "Active pricing band",
1010
+ peak: "Peak",
1011
+ offPeak: "Off-peak",
1012
+ model: "Model",
1013
+ meter: "Usage",
1014
+ cached: "Input (cache hit)",
1015
+ uncached: "Input (cache miss)",
1016
+ output: "Output",
1017
+ custom: "Endpoint-specific quote",
1018
+ customOn: "Override configured",
1019
+ fallback: "Unset; using module rates",
1020
+ save: "Apply quote",
1021
+ saved: "Quote staged; save the connection to apply it",
1022
+ savedNow: "Quote saved",
1023
+ choose: "DeepSeek endpoint",
1024
+ loadError: "Unable to load rates",
1025
+ noInstances: "No DeepSeek endpoints are available"
1026
+ };
1027
+ const message = ctx.ui.msgline();
1028
+ const selector = ctx.scope.instance ? null : ctx.ui.select({
1029
+ options: [],
1030
+ onChange: (name) => void load(name)
1031
+ });
1032
+ if (selector) ctx.root.append(ctx.ui.field(S3.choose, selector));
1033
+ ctx.root.append(message);
1034
+ let currentCard = null;
1035
+ let endpointNames = [];
1036
+ if (ctx.scope.instance) {
1037
+ endpointNames = [ctx.scope.instance];
1038
+ } else {
1039
+ try {
1040
+ const instances = await ctx.invoke("instances");
1041
+ endpointNames = instances.map(({ name }) => name);
1042
+ } catch (error) {
1043
+ message.textContent = `${S3.loadError}: ${String(error)}`;
1044
+ return;
1045
+ }
1046
+ if (!endpointNames.length) {
1047
+ message.textContent = S3.noInstances;
1048
+ return;
1049
+ }
1050
+ selector.replaceChildren(...endpointNames.map((name) => {
1051
+ const option = ctx.ui.h("option", null, name);
1052
+ option.value = name;
1053
+ return option;
1054
+ }));
1055
+ }
1056
+ if (ctx.signal.aborted) return;
1057
+ await load(endpointNames[0]);
1058
+ async function load(name) {
1059
+ try {
1060
+ const state = await ctx.invoke("state", [{ name }]);
1061
+ if (ctx.signal.aborted) return;
1062
+ render(state);
1063
+ message.textContent = "";
1064
+ } catch (error) {
1065
+ message.textContent = `${S3.loadError}: ${String(error)}`;
1066
+ }
1067
+ }
1068
+ function render(state) {
1069
+ const card = ctx.ui.sheet({ title: S3.title });
1070
+ const band = currentPricingBand(state.schedule, /* @__PURE__ */ new Date());
1071
+ card.body.append(ctx.ui.statgrid([
1072
+ { k: S3.model, v: state.official.models.join(", ") },
1073
+ { k: S3.current, v: band === "peak" ? S3.peak : S3.offPeak, accent: true }
1074
+ ]));
1075
+ const table = ctx.ui.table({ head: [S3.meter, S3.peak, S3.offPeak] });
1076
+ const peakRules = state.official.timeWindows?.[0]?.rules ?? [];
1077
+ const labels = /* @__PURE__ */ new Map([
1078
+ ["cachedInput", S3.cached],
1079
+ ["uncachedInput", S3.uncached],
1080
+ ["output", S3.output]
1081
+ ]);
1082
+ for (const rule of state.official.rules) {
1083
+ const peak = peakRules.find((item) => item.meter === rule.meter)?.perMillion ?? rule.perMillion;
1084
+ const format = (rate) => `\xA5${rate.toFixed(2)} / 1M`;
1085
+ table.addRow([
1086
+ labels.get(rule.meter) ?? rule.meter,
1087
+ band === "peak" ? ctx.ui.chip(format(peak), "accent") : format(peak),
1088
+ band === "offPeak" ? ctx.ui.chip(format(rule.perMillion), "accent") : format(rule.perMillion)
1089
+ ]);
1090
+ }
1091
+ card.body.append(table.el, ctx.ui.msgline(`${state.official.source} \xB7 Asia/Shanghai`));
1092
+ const details = ctx.ui.foldSheet("deepseek-custom-pricing", { title: S3.custom });
1093
+ details.el.classList.add("deepseek-custom-pricing");
1094
+ details.note.textContent = state.custom.length ? S3.customOn : S3.fallback;
1095
+ let customPricing = state.custom;
1096
+ const editor = pricingEditor(ctx.ui, state.custom, [], (value) => {
1097
+ customPricing = value;
1098
+ }, ctx.language);
1099
+ details.body.append(editor.body);
1100
+ const save = ctx.ui.button(S3.save, { variant: "primary", onClick: () => void savePricing() });
1101
+ details.body.append(ctx.ui.actions().appendChild(save));
1102
+ card.body.append(details.el);
1103
+ if (currentCard) currentCard.replaceWith(card.el);
1104
+ else ctx.root.insertBefore(card.el, message);
1105
+ currentCard = card.el;
1106
+ async function savePricing() {
1107
+ if (!editor.validate()) return;
1108
+ const release = ctx.ui.disable(save);
1109
+ try {
1110
+ const updated = await ctx.invoke("save", [{ name: state.name, pricing: customPricing }]);
1111
+ message.textContent = updated.editing ? S3.saved : S3.savedNow;
1112
+ render(updated);
1113
+ } catch (error) {
1114
+ message.textContent = String(error);
1115
+ } finally {
1116
+ release.dispose();
1117
+ }
1118
+ }
1119
+ }
1120
+ }
1121
+ };
1122
+
1123
+ // console/schedule-panel.ts
1124
+ var schedulePanel = {
1125
+ mount: async (ctx) => {
1126
+ const zh4 = ctx.language === "zh";
1127
+ const S3 = zh4 ? {
1128
+ current: "\u5F53\u524D\u8BA1\u4EF7\u65F6\u6BB5",
1129
+ peak: "\u9AD8\u5CF0",
1130
+ offPeak: "\u7A7A\u95F2",
1131
+ timezone: "\u5317\u4EAC\u65F6\u95F4\uFF08Asia/Shanghai\uFF09",
1132
+ windows: "\u9AD8\u5CF0\u65F6\u6BB5",
1133
+ weekday: "\u5468\u4E00\u81F3\u5468\u4E94\uFF1B\u5468\u672B\u59CB\u7EC8\u4E3A\u7A7A\u95F2\u65F6\u6BB5",
1134
+ exceptions: "\u4F8B\u5916\u65E5\u671F\uFF08\u6BCF\u884C YYYY-MM-DD\uFF09",
1135
+ from: "\u5F00\u59CB",
1136
+ to: "\u7ED3\u675F",
1137
+ save: "\u4FDD\u5B58\u65F6\u6BB5",
1138
+ saved: "\u5CF0\u8C37\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
1139
+ invalid: "\u65F6\u6BB5\u683C\u5F0F\u9519\u8BEF\uFF1B\u8BF7\u586B\u5199 HH:MM\uFF0C\u4F8B\u5916\u65E5\u671F\u6BCF\u884C\u586B\u5199 YYYY-MM-DD\u3002",
1140
+ refreshError: "\u65E0\u6CD5\u8BFB\u53D6\u5CF0\u8C37\u8BBE\u7F6E"
1141
+ } : {
1142
+ current: "Active pricing band",
1143
+ peak: "Peak",
1144
+ offPeak: "Off-peak",
1145
+ timezone: "China Standard Time (Asia/Shanghai)",
1146
+ windows: "Peak windows",
1147
+ weekday: "Monday to Friday; weekends are always off-peak",
1148
+ exceptions: "Exception dates (one YYYY-MM-DD per line)",
1149
+ from: "From",
1150
+ to: "To",
1151
+ save: "Save schedule",
1152
+ saved: "Pricing schedule saved",
1153
+ invalid: "Invalid time or date format. Use HH:MM and one YYYY-MM-DD date per line.",
1154
+ refreshError: "Unable to load pricing schedule"
1155
+ };
1156
+ const status = ctx.ui.foldSheet("deepseek-schedule", { title: S3.current });
1157
+ const message = ctx.ui.msgline();
1158
+ ctx.root.append(status.el, message);
1159
+ let state;
1160
+ try {
1161
+ state = await ctx.invoke("state", [{ name: ctx.scope.instance }]);
1162
+ } catch (error) {
1163
+ message.textContent = `${S3.refreshError}: ${String(error)}`;
1164
+ return;
1165
+ }
1166
+ if (ctx.signal.aborted) return;
1167
+ const updateStatus = (band = currentPricingBand(state.schedule, /* @__PURE__ */ new Date())) => {
1168
+ const now = /* @__PURE__ */ new Date();
1169
+ const time = new Intl.DateTimeFormat(zh4 ? "zh-CN" : "en-GB", {
1170
+ timeZone: "Asia/Shanghai",
1171
+ dateStyle: "medium",
1172
+ timeStyle: "short",
1173
+ hourCycle: "h23"
1174
+ }).format(now);
1175
+ status.note.textContent = `${band === "peak" ? S3.peak : S3.offPeak} \xB7 ${time} \xB7 ${S3.timezone}`;
1176
+ };
1177
+ updateStatus(state.band);
1178
+ ctx.interval(updateStatus, 3e4);
1179
+ const starts = state.schedule.windows.map((window) => ctx.ui.input({ value: window.from, placeholder: "09:00", cls: "mono" }));
1180
+ const ends = state.schedule.windows.map((window) => ctx.ui.input({ value: window.to, placeholder: "12:00", cls: "mono" }));
1181
+ const windows = ctx.ui.rowbar();
1182
+ windows.classList.add("deepseek-window-grid");
1183
+ windows.style.alignItems = "stretch";
1184
+ state.schedule.windows.forEach((_, index) => {
1185
+ const group = ctx.ui.h("div", "deepseek-window");
1186
+ group.style.flex = "1 1 280px";
1187
+ group.style.minWidth = "0";
1188
+ const times = ctx.ui.rowbar();
1189
+ times.style.flexWrap = "nowrap";
1190
+ for (const [label, input] of [[S3.from, starts[index]], [S3.to, ends[index]]]) {
1191
+ const field = ctx.ui.field(label, input);
1192
+ field.style.flex = "1 1 0";
1193
+ field.style.minWidth = "0";
1194
+ times.append(field);
1195
+ }
1196
+ group.append(ctx.ui.h("div", "fieldlabel", zh4 ? `\u65F6\u6BB5 ${index + 1}` : `Window ${index + 1}`), times);
1197
+ windows.append(group);
1198
+ });
1199
+ status.body.append(ctx.ui.section(S3.windows), ctx.ui.msgline(S3.weekday), windows);
1200
+ const exceptionDates = ctx.ui.textarea({ rows: 6, value: state.schedule.exceptDates.join("\n"), cls: "mono" });
1201
+ status.body.append(ctx.ui.field(S3.exceptions, exceptionDates));
1202
+ const save = ctx.ui.button(S3.save, { variant: "primary", onClick: () => void saveSchedule() });
1203
+ status.body.append(ctx.ui.actions().appendChild(save));
1204
+ async function saveSchedule() {
1205
+ const schedule = {
1206
+ windows: starts.map((input, index) => ({ from: input.value.trim(), to: ends[index].value.trim() })),
1207
+ exceptDates: exceptionDates.value.split(/\r?\n/).map((date) => date.trim()).filter(Boolean)
1208
+ };
1209
+ if (schedule.windows.some(({ from, to }) => !/^\d{2}:\d{2}$/.test(from) || !/^\d{2}:\d{2}$/.test(to)) || schedule.exceptDates.some((date) => !/^\d{4}-\d{2}-\d{2}$/.test(date))) {
1210
+ message.textContent = S3.invalid;
1211
+ return;
1212
+ }
1213
+ const release = ctx.ui.disable(save);
1214
+ try {
1215
+ state = await ctx.invoke("save", [{ name: state.name, schedule }]);
1216
+ message.textContent = S3.saved;
1217
+ updateStatus(state.band);
1218
+ } catch (error) {
1219
+ message.textContent = String(error);
1220
+ } finally {
1221
+ release.dispose();
1222
+ }
1223
+ }
1224
+ }
1225
+ };
1226
+
1227
+ // console/client.ts
1228
+ var client_default2 = {
1229
+ ...client_default,
1230
+ panels: { ...client_default.panels, schedule: schedulePanel, pricing: pricingPanel }
1231
+ };
1232
+ export {
1233
+ client_default2 as default
1234
+ };