dsh-provider-qoder 0.4.1 → 0.4.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.
- package/README.md +13 -22
- package/README_CN.md +13 -25
- package/lib/client.js +549 -277
- package/lib/index.d.ts +8 -44
- package/lib/index.js +785 -522
- package/package.json +19 -16
package/lib/client.js
CHANGED
|
@@ -69,6 +69,29 @@ window.__ModuleLoader__.load({
|
|
|
69
69
|
tokenCount
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
+
/** Clone a model catalog entry, detaching any contextOptions object. */
|
|
73
|
+
function cloneCatalogModel(model) {
|
|
74
|
+
return {
|
|
75
|
+
...model,
|
|
76
|
+
...model.contextOptions !== void 0 ? { contextOptions: { ...model.contextOptions } } : {}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Carry subscriber context choices only while the refreshed catalog supports them. */
|
|
80
|
+
function mergeAdvertisedContext(remembered, advertised, updated) {
|
|
81
|
+
const merged = { ...updated };
|
|
82
|
+
delete merged.contextOptions;
|
|
83
|
+
delete merged.contextTier;
|
|
84
|
+
if (advertised.contextOptions !== void 0) merged.contextOptions = { ...advertised.contextOptions };
|
|
85
|
+
const tier = selectedContextTier({
|
|
86
|
+
contextTier: remembered.contextTier,
|
|
87
|
+
contextOptions: merged.contextOptions
|
|
88
|
+
});
|
|
89
|
+
if (tier !== void 0) {
|
|
90
|
+
merged.contextTier = tier.key;
|
|
91
|
+
merged.contextWindow = tier.tokenCount;
|
|
92
|
+
} else if (advertised.contextWindow !== void 0) merged.contextWindow = remembered.contextTier !== void 0 ? advertised.contextWindow : Math.min(remembered.contextWindow ?? advertised.contextWindow, advertised.contextWindow);
|
|
93
|
+
return merged;
|
|
94
|
+
}
|
|
72
95
|
const defaultMaxTokens = 32768;
|
|
73
96
|
const defaultModels = [
|
|
74
97
|
{
|
|
@@ -120,6 +143,31 @@ window.__ModuleLoader__.load({
|
|
|
120
143
|
}
|
|
121
144
|
];
|
|
122
145
|
//#endregion
|
|
146
|
+
//#region src/client/credential-operations.ts
|
|
147
|
+
function regionOf(value) {
|
|
148
|
+
if (typeof value !== "object" || value === null) return "global";
|
|
149
|
+
return value.region === "china" ? "china" : "global";
|
|
150
|
+
}
|
|
151
|
+
function modelsOf(section, region) {
|
|
152
|
+
const scoped = section?.modelsByRegion?.[region];
|
|
153
|
+
return Array.isArray(scoped) ? scoped : defaultModels.map((model) => ({ ...model }));
|
|
154
|
+
}
|
|
155
|
+
function reconcileQoderModels(known, discovered) {
|
|
156
|
+
const availableIds = new Set(discovered.map((model) => model.id));
|
|
157
|
+
const unavailable = known.filter((model) => !availableIds.has(model.id)).map(cloneCatalogModel);
|
|
158
|
+
const previous = new Map(known.map((model) => [model.id, model]));
|
|
159
|
+
const reconciled = discovered.map((model) => {
|
|
160
|
+
const remembered = previous.get(model.id);
|
|
161
|
+
if (remembered === void 0) return cloneCatalogModel(model);
|
|
162
|
+
return mergeAdvertisedContext(remembered, model, model);
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
catalog: [...reconciled, ...unavailable],
|
|
166
|
+
selected: reconciled,
|
|
167
|
+
unavailableIds: new Set(unavailable.map((model) => model.id))
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
123
171
|
//#region src/client/locales.ts
|
|
124
172
|
const zh = {
|
|
125
173
|
nav: "Qoder",
|
|
@@ -165,7 +213,6 @@ window.__ModuleLoader__.load({
|
|
|
165
213
|
contextTierDefaultSuffix: "(默认)",
|
|
166
214
|
contextTierHint: "选择该模型使用的上下文档位;更大的档位会同时提升 DSH 的上下文预算并改变 Qoder 请求使用的档位。",
|
|
167
215
|
contextSelectFailed: "上下文切换失败,请重试。",
|
|
168
|
-
contextDefaultFailed: "当前会话已切换,但新会话默认值保存失败。",
|
|
169
216
|
contextSelectTitle: "选择上下文大小",
|
|
170
217
|
contextSelectMenuHeader: "上下文容量",
|
|
171
218
|
accountTitle: "Qoder",
|
|
@@ -176,6 +223,7 @@ window.__ModuleLoader__.load({
|
|
|
176
223
|
refreshing: "正在刷新…",
|
|
177
224
|
userQuotaTitle: "个人额度",
|
|
178
225
|
orgResourceTitle: "组织资源包",
|
|
226
|
+
addOnQuotaTitle: "增值额度",
|
|
179
227
|
dedicatedResourceTitle: "专属资源包",
|
|
180
228
|
dedicatedResourceExpiresAt: "有效期至:{value}",
|
|
181
229
|
quotaRemaining: "剩余 {value}%",
|
|
@@ -237,7 +285,6 @@ window.__ModuleLoader__.load({
|
|
|
237
285
|
contextTierDefaultSuffix: " (default)",
|
|
238
286
|
contextTierHint: "Select the context tier for this model. A larger tier raises the DSH context budget and changes the tier the Qoder request uses.",
|
|
239
287
|
contextSelectFailed: "Could not change the context window. Please retry.",
|
|
240
|
-
contextDefaultFailed: "Session updated, but the default for new sessions could not be saved.",
|
|
241
288
|
contextSelectTitle: "Select context window size",
|
|
242
289
|
contextSelectMenuHeader: "Context Capacity",
|
|
243
290
|
accountTitle: "Qoder",
|
|
@@ -248,6 +295,7 @@ window.__ModuleLoader__.load({
|
|
|
248
295
|
refreshing: "Refreshing…",
|
|
249
296
|
userQuotaTitle: "Personal Quota",
|
|
250
297
|
orgResourceTitle: "Org Resource Package",
|
|
298
|
+
addOnQuotaTitle: "Add-on Credits",
|
|
251
299
|
dedicatedResourceTitle: "Dedicated Resource Package",
|
|
252
300
|
dedicatedResourceExpiresAt: "Expires at: {value}",
|
|
253
301
|
quotaRemaining: "{value}% remaining",
|
|
@@ -316,48 +364,145 @@ window.__ModuleLoader__.load({
|
|
|
316
364
|
}
|
|
317
365
|
}
|
|
318
366
|
//#endregion
|
|
319
|
-
//#region src/client/
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
367
|
+
//#region src/client/model-catalog-editor.ts
|
|
368
|
+
/** One mounted region owns its directory and asynchronous edits. */
|
|
369
|
+
var QoderModelCatalogEditor = class {
|
|
370
|
+
region;
|
|
371
|
+
operations;
|
|
372
|
+
active = true;
|
|
373
|
+
confirmed;
|
|
374
|
+
snapshot;
|
|
375
|
+
listeners = /* @__PURE__ */ new Set();
|
|
376
|
+
constructor(region, models, operations) {
|
|
377
|
+
this.region = region;
|
|
378
|
+
this.operations = operations;
|
|
379
|
+
this.confirmed = models.map(cloneCatalogModel);
|
|
380
|
+
this.snapshot = {
|
|
381
|
+
models: this.confirmed,
|
|
382
|
+
catalog: this.confirmed,
|
|
383
|
+
unavailableIds: /* @__PURE__ */ new Set()
|
|
332
384
|
};
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (carried !== void 0) return {
|
|
340
|
-
...model,
|
|
341
|
-
...clonedOptions,
|
|
342
|
-
contextTier: carried.key,
|
|
343
|
-
contextWindow: carried.tokenCount
|
|
344
|
-
};
|
|
345
|
-
const budget = remembered.contextWindow;
|
|
346
|
-
return budget === void 0 || model.contextWindow === void 0 ? {
|
|
347
|
-
...model,
|
|
348
|
-
...clonedOptions
|
|
349
|
-
} : {
|
|
350
|
-
...model,
|
|
351
|
-
...clonedOptions,
|
|
352
|
-
contextWindow: Math.min(budget, model.contextWindow)
|
|
385
|
+
}
|
|
386
|
+
getSnapshot = () => this.snapshot;
|
|
387
|
+
subscribe = (listener) => {
|
|
388
|
+
this.listeners.add(listener);
|
|
389
|
+
return () => {
|
|
390
|
+
this.listeners.delete(listener);
|
|
353
391
|
};
|
|
354
|
-
});
|
|
355
|
-
return {
|
|
356
|
-
catalog: [...reconciled, ...unavailable],
|
|
357
|
-
selected: reconciled,
|
|
358
|
-
unavailableIds: new Set(unavailable.map((model) => model.id))
|
|
359
392
|
};
|
|
360
|
-
|
|
393
|
+
/** ConfigForms supplies accepted values, including its recovery read after refusal. */
|
|
394
|
+
replaceModels(models) {
|
|
395
|
+
const followsConfig = this.snapshot.catalog === this.confirmed;
|
|
396
|
+
this.confirmed = models.map(cloneCatalogModel);
|
|
397
|
+
const selected = new Map(this.confirmed.map((model) => [model.id, model]));
|
|
398
|
+
this.publish({
|
|
399
|
+
...this.snapshot,
|
|
400
|
+
models: this.confirmed,
|
|
401
|
+
catalog: followsConfig ? this.confirmed : this.snapshot.catalog.map((model) => selected.get(model.id) ?? model)
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
activate() {
|
|
405
|
+
this.active = true;
|
|
406
|
+
}
|
|
407
|
+
dispose() {
|
|
408
|
+
this.active = false;
|
|
409
|
+
this.listeners.clear();
|
|
410
|
+
}
|
|
411
|
+
publish(snapshot) {
|
|
412
|
+
if (!this.active) return;
|
|
413
|
+
this.snapshot = snapshot;
|
|
414
|
+
for (const listener of this.listeners) listener();
|
|
415
|
+
}
|
|
416
|
+
async discover() {
|
|
417
|
+
if (!this.active || this.snapshot.pending) return;
|
|
418
|
+
this.publish({
|
|
419
|
+
...this.snapshot,
|
|
420
|
+
pending: "discovering",
|
|
421
|
+
failure: void 0,
|
|
422
|
+
failureMessage: void 0
|
|
423
|
+
});
|
|
424
|
+
try {
|
|
425
|
+
const result = await this.operations.discoverModels();
|
|
426
|
+
if (!this.active) return;
|
|
427
|
+
if (!result.ok) {
|
|
428
|
+
this.publish({
|
|
429
|
+
...this.snapshot,
|
|
430
|
+
pending: void 0,
|
|
431
|
+
failure: "modelsFetchFailed",
|
|
432
|
+
failureMessage: result.error.message
|
|
433
|
+
});
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const reconciled = reconcileQoderModels(this.snapshot.catalog, result.value);
|
|
437
|
+
await this.save(reconciled.selected, reconciled.catalog, reconciled.unavailableIds);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
this.publish({
|
|
440
|
+
...this.snapshot,
|
|
441
|
+
pending: void 0,
|
|
442
|
+
failure: "modelsFetchFailed",
|
|
443
|
+
failureMessage: error instanceof Error ? error.message : void 0
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
async toggle(id, enabled) {
|
|
448
|
+
if (!this.active || this.snapshot.pending || this.snapshot.unavailableIds.has(id)) return;
|
|
449
|
+
const selected = new Set(this.snapshot.models.map((model) => model.id));
|
|
450
|
+
if (enabled) selected.add(id);
|
|
451
|
+
else selected.delete(id);
|
|
452
|
+
await this.save(this.snapshot.catalog.filter((model) => selected.has(model.id) && !this.snapshot.unavailableIds.has(model.id)));
|
|
453
|
+
}
|
|
454
|
+
async selectTier(id, tierKey) {
|
|
455
|
+
if (!this.active || this.snapshot.pending || !this.snapshot.models.some((model) => model.id === id)) return;
|
|
456
|
+
const tokenCount = this.snapshot.catalog.find((model) => model.id === id)?.contextOptions?.[tierKey]?.tokenCount;
|
|
457
|
+
if (typeof tokenCount !== "number" || !Number.isFinite(tokenCount) || tokenCount <= 0) return;
|
|
458
|
+
const apply = (candidate) => candidate.id === id ? {
|
|
459
|
+
...candidate,
|
|
460
|
+
contextTier: tierKey,
|
|
461
|
+
contextWindow: tokenCount
|
|
462
|
+
} : candidate;
|
|
463
|
+
await this.save(this.snapshot.models.map(apply), this.snapshot.catalog.map(apply));
|
|
464
|
+
}
|
|
465
|
+
async save(models, catalog = this.snapshot.catalog, unavailableIds = this.snapshot.unavailableIds) {
|
|
466
|
+
if (models.length === 0) {
|
|
467
|
+
this.publish({
|
|
468
|
+
...this.snapshot,
|
|
469
|
+
pending: void 0,
|
|
470
|
+
failure: "modelsRequired",
|
|
471
|
+
failureMessage: void 0
|
|
472
|
+
});
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const submitted = models.map(cloneCatalogModel);
|
|
476
|
+
const confirmedAtSubmission = this.confirmed;
|
|
477
|
+
this.publish({
|
|
478
|
+
...this.snapshot,
|
|
479
|
+
pending: "saving",
|
|
480
|
+
failure: void 0,
|
|
481
|
+
failureMessage: void 0
|
|
482
|
+
});
|
|
483
|
+
let saved = false;
|
|
484
|
+
try {
|
|
485
|
+
saved = await this.operations.storeModels(this.region, submitted);
|
|
486
|
+
} catch {}
|
|
487
|
+
if (!this.active) return;
|
|
488
|
+
if (saved) {
|
|
489
|
+
if (this.confirmed === confirmedAtSubmission) this.confirmed = submitted;
|
|
490
|
+
const accepted = new Map(this.confirmed.map((model) => [model.id, model]));
|
|
491
|
+
const directory = new Map(catalog.map((model) => [model.id, model]));
|
|
492
|
+
for (const [id, model] of accepted) directory.set(id, model);
|
|
493
|
+
this.publish({
|
|
494
|
+
models: this.confirmed,
|
|
495
|
+
catalog: [...directory.values()],
|
|
496
|
+
unavailableIds: new Set([...unavailableIds].filter((id) => !accepted.has(id)))
|
|
497
|
+
});
|
|
498
|
+
} else this.publish({
|
|
499
|
+
models: this.confirmed,
|
|
500
|
+
catalog: this.confirmed,
|
|
501
|
+
unavailableIds: /* @__PURE__ */ new Set(),
|
|
502
|
+
failure: "saveFailed"
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
};
|
|
361
506
|
//#endregion
|
|
362
507
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderCredentialCard.module.css.mjs
|
|
363
508
|
const css$1 = ".SRqrhW_credential{color:var(--dsw-alias-label-primary);border-radius:10px;margin-top:12px}.SRqrhW_credential p{margin:8px 0 0}.SRqrhW_credentialEditor{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);flex-direction:column;gap:12px;padding:12px 14px;display:flex}.SRqrhW_credentialRowHead{align-items:center;gap:10px;display:flex}.SRqrhW_credentialIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.SRqrhW_credentialName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.SRqrhW_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.SRqrhW_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.SRqrhW_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.SRqrhW_regionBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:500;line-height:16px;display:inline-flex}.SRqrhW_regionSelector{flex-direction:column;gap:8px;margin-bottom:14px;display:flex}.SRqrhW_regionGroup{gap:8px;display:flex}.SRqrhW_regionOption{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);user-select:none;border-radius:8px;align-items:center;gap:6px;padding:6px 12px;font-size:12px;line-height:18px;transition:all .12s;display:inline-flex}.SRqrhW_regionOption:hover:not(.SRqrhW_regionOptionDisabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.SRqrhW_credential button.SRqrhW_regionOptionActive{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-selected);color:var(--dsw-alias-brand-primary);font-weight:500}.SRqrhW_regionOptionDisabled{cursor:not-allowed;opacity:.5}.SRqrhW_editButton{box-sizing:border-box;font:inherit;background:0 0;margin-left:auto;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2)!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_editButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.SRqrhW_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;padding:14px 16px}.SRqrhW_customized{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);margin-top:12px;transition:all .12s;overflow:hidden}.SRqrhW_customizedSummary{box-sizing:border-box;border-radius:var(--dsw-radius-xl,12px);cursor:pointer;width:100%;color:var(--dsw-alias-label-primary);user-select:none;align-items:center;gap:8px;margin:0;padding:12px 14px;font-size:13px;font-weight:600;line-height:18px;list-style:none;transition:background .12s;display:flex}.SRqrhW_customizedSummary:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelSummaryBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:400;line-height:16px;display:inline-flex}.SRqrhW_customizedSummary::-webkit-details-marker{display:none}.SRqrhW_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary{border-bottom:.5px solid var(--dsw-alias-border-l2);border-bottom-right-radius:0;border-bottom-left-radius:0}.SRqrhW_customizedBody{padding:12px 14px 14px}.SRqrhW_modelCatalog{flex-direction:column;gap:10px;display:flex}.SRqrhW_modelList{flex-direction:column;gap:10px;max-height:360px;padding-right:4px;display:flex;overflow-y:auto}.SRqrhW_modelList::-webkit-scrollbar{width:4px}.SRqrhW_modelList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);border-radius:2px}.SRqrhW_modelCatalogHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.SRqrhW_modelCatalogHeadCompact{justify-content:flex-end;align-items:center;gap:12px;display:flex}.SRqrhW_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.SRqrhW_modelCatalogMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:2px 0 0!important}.SRqrhW_linkButton{box-sizing:border-box;font:inherit;background:0 0;font-size:12px;line-height:18px;border:none!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoice{border-radius:6px;flex-direction:column;gap:4px;padding:6px 8px;font-size:13px;display:flex}.SRqrhW_modelChoice:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoiceHead{cursor:pointer;grid-template-columns:auto minmax(0,1fr) auto auto auto;align-items:center;gap:8px;display:grid}.SRqrhW_modelTier{align-items:center;gap:8px;padding-left:24px;display:flex}.SRqrhW_modelTierLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}.SRqrhW_modelTierSelect{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);height:24px;color:inherit;font:inherit;cursor:pointer;border:0;border-radius:6px;padding:0 6px;font-size:12px}.SRqrhW_modelTierHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px;margin:0!important}.SRqrhW_modelChoiceName{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.SRqrhW_modelChoice code{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_modelRate{min-width:34px;color:var(--dsw-alias-brand-primary);text-align:right;font-size:12px;font-weight:600}.SRqrhW_modelUnavailable{cursor:not-allowed;opacity:.55}.SRqrhW_modelBadge{color:var(--dsw-alias-state-error-primary);font-size:11px}@media (prefers-reduced-motion:reduce){.SRqrhW_customizedSummary:before{transition:none}}.SRqrhW_head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:20px;display:flex}.SRqrhW_heading{margin:0;font-size:18px;font-weight:600}.SRqrhW_status{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_configured,.SRqrhW_success{color:var(--dsw-alias-state-success-primary)}.SRqrhW_label{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;display:block}.SRqrhW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:32px;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;margin-top:6px;padding:0 10px}.SRqrhW_input:focus{border-color:var(--dsw-alias-brand-primary)}.SRqrhW_input::placeholder{color:var(--dsw-alias-label-dimmed)}.SRqrhW_input:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_hint{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_actions{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.SRqrhW_credential button{cursor:pointer;height:32px;color:var(--dsw-alias-label-primary);border:1px solid #0000;border-radius:16px;padding:0 12px}.SRqrhW_credential button:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)!important}.SRqrhW_primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.SRqrhW_secondary{background:0 0;border-color:var(--dsw-alias-border-l2)!important}.SRqrhW_secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_danger{background:0 0;border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.SRqrhW_danger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.SRqrhW_error{color:var(--dsw-alias-state-error-primary);font-size:12px}.SRqrhW_success{font-size:12px}.SRqrhW_accountSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_accountHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_userInfo{align-items:center;gap:10px;min-width:0;display:flex}.SRqrhW_avatar{background:var(--dsw-alias-brand-primary);width:32px;height:32px;color:var(--dsw-alias-label-primary-foreground);text-transform:uppercase;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:flex}.SRqrhW_userDetails{flex-direction:column;gap:2px;min-width:0;display:flex}.SRqrhW_userName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;overflow:hidden}.SRqrhW_userEmail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.SRqrhW_refreshBtn{border:1px solid var(--dsw-alias-border-l2)!important;height:26px!important;color:var(--dsw-alias-label-secondary)!important;background:0 0!important;border-radius:13px!important;padding:0 8px!important;font-size:12px!important}.SRqrhW_refreshBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)!important}.SRqrhW_quotaBlock{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding-top:8px;display:flex}.SRqrhW_quotaHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_quotaLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.SRqrhW_quotaTop{justify-content:space-between;align-items:baseline;gap:8px;font-size:12px;display:flex}.SRqrhW_quotaTop strong{color:var(--dsw-alias-brand-primary);font-size:13px}.SRqrhW_quotaDescription{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0!important}.SRqrhW_quotaProgress{background:var(--dsw-alias-border-l3);width:100%;height:6px;accent-color:var(--dsw-alias-brand-primary);-webkit-appearance:none;appearance:none;border:0;border-radius:999px;overflow:hidden}.SRqrhW_quotaProgress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.SRqrhW_quotaProgress::-webkit-progress-value{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaProgress::-moz-progress-bar{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaMeta{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;gap:8px;font-size:11px;display:flex}.SRqrhW_accountLoadingText,.SRqrhW_accountEmptyText{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.SRqrhW_userNameRow{align-items:center;gap:8px;display:flex}.SRqrhW_planBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-brand-primary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.SRqrhW_orgTag{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_suspendedBanner{background:var(--dsw-alias-state-error-subtle,#ff4d4f1a);color:var(--dsw-alias-state-error-primary);border-radius:6px;align-items:center;gap:6px;margin-bottom:8px;padding:6px 10px;font-size:12px;display:flex}.SRqrhW_searchModeSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_searchModeHintText{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:12px;line-height:18px}";
|
|
@@ -446,57 +591,26 @@ window.__ModuleLoader__.load({
|
|
|
446
591
|
};
|
|
447
592
|
//#endregion
|
|
448
593
|
//#region src/client/QoderModelCatalog.tsx
|
|
449
|
-
|
|
450
|
-
return models.length === 0 ? "modelsRequired" : void 0;
|
|
451
|
-
}
|
|
594
|
+
/** The key resets directory state whenever the active Qoder service region changes. */
|
|
452
595
|
function QoderModelCatalog(props) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const [
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
setUnavailableIds(reconciled.unavailableIds);
|
|
472
|
-
onChange(reconciled.selected);
|
|
473
|
-
};
|
|
474
|
-
const toggleModel = (id, enabled) => {
|
|
475
|
-
if (unavailableIds.has(id)) return;
|
|
476
|
-
const source = catalog ?? models;
|
|
477
|
-
if (catalog === void 0) setCatalog(source);
|
|
478
|
-
const nextSelected = new Set(selectedIds);
|
|
479
|
-
if (enabled) nextSelected.add(id);
|
|
480
|
-
else nextSelected.delete(id);
|
|
481
|
-
onChange(source.filter((model) => nextSelected.has(model.id) && !unavailableIds.has(model.id)));
|
|
482
|
-
};
|
|
483
|
-
const changeContextTier = (id, tierKey) => {
|
|
484
|
-
const source = catalog ?? models;
|
|
485
|
-
if (catalog === void 0) setCatalog(source);
|
|
486
|
-
const apply = (model) => {
|
|
487
|
-
if (model.id !== id) return model;
|
|
488
|
-
const tokenCount = model.contextOptions?.[tierKey]?.tokenCount;
|
|
489
|
-
if (typeof tokenCount !== "number" || !Number.isFinite(tokenCount) || tokenCount <= 0) return model;
|
|
490
|
-
return {
|
|
491
|
-
...model,
|
|
492
|
-
contextTier: tierKey,
|
|
493
|
-
contextWindow: tokenCount
|
|
494
|
-
};
|
|
495
|
-
};
|
|
496
|
-
const nextCatalog = source.map(apply);
|
|
497
|
-
setCatalog(nextCatalog);
|
|
498
|
-
onChange(models.map(apply));
|
|
499
|
-
};
|
|
596
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegionModelCatalog, { ...props }, props.region);
|
|
597
|
+
}
|
|
598
|
+
function RegionModelCatalog({ operations, models, region, disabled, fetchDisabled, hideTitle, t }) {
|
|
599
|
+
const [editor] = (0, react.useState)(() => new QoderModelCatalogEditor(region, models, operations));
|
|
600
|
+
const snapshot = (0, react.useSyncExternalStore)(editor.subscribe, editor.getSnapshot, editor.getSnapshot);
|
|
601
|
+
(0, react.useLayoutEffect)(() => {
|
|
602
|
+
editor.activate();
|
|
603
|
+
return () => editor.dispose();
|
|
604
|
+
}, [editor]);
|
|
605
|
+
(0, react.useLayoutEffect)(() => {
|
|
606
|
+
editor.replaceModels(models);
|
|
607
|
+
}, [editor, models]);
|
|
608
|
+
const displayedModels = snapshot.catalog;
|
|
609
|
+
const unavailableIds = snapshot.unavailableIds;
|
|
610
|
+
const selectedIds = new Set(snapshot.models.map((model) => model.id));
|
|
611
|
+
const busy = snapshot.pending !== void 0;
|
|
612
|
+
const fetching = snapshot.pending === "discovering";
|
|
613
|
+
const failure = snapshot.failureMessage || (snapshot.failure ? t(snapshot.failure) : void 0);
|
|
500
614
|
const renderRate = (model) => {
|
|
501
615
|
if (model.isFree || model.priceFactor === 0) return t("modelRateFree");
|
|
502
616
|
if (model.priceFactor === void 0) return t("modelRateUnknown");
|
|
@@ -519,13 +633,13 @@ window.__ModuleLoader__.load({
|
|
|
519
633
|
children: t("modelsTitle")
|
|
520
634
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
521
635
|
className: QoderCredentialCard_module_css_default.modelCatalogMeta,
|
|
522
|
-
children: t("modelsEnabled", { count: models.length })
|
|
636
|
+
children: t("modelsEnabled", { count: snapshot.models.length })
|
|
523
637
|
})] }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
524
638
|
type: "button",
|
|
525
639
|
className: QoderCredentialCard_module_css_default.linkButton,
|
|
526
|
-
disabled: disabled ||
|
|
640
|
+
disabled: disabled || busy || Boolean(fetchDisabled),
|
|
527
641
|
onClick: () => {
|
|
528
|
-
|
|
642
|
+
if (!disabled && !fetchDisabled) editor.discover();
|
|
529
643
|
},
|
|
530
644
|
children: fetching ? t("modelsFetching") : t("modelsFetch")
|
|
531
645
|
})]
|
|
@@ -550,9 +664,9 @@ window.__ModuleLoader__.load({
|
|
|
550
664
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
551
665
|
type: "checkbox",
|
|
552
666
|
checked: !unavailable && selectedIds.has(model.id),
|
|
553
|
-
disabled: disabled || unavailable,
|
|
667
|
+
disabled: disabled || busy || unavailable,
|
|
554
668
|
onChange: (event) => {
|
|
555
|
-
|
|
669
|
+
if (!disabled) editor.toggle(model.id, event.currentTarget.checked);
|
|
556
670
|
}
|
|
557
671
|
}),
|
|
558
672
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -577,9 +691,9 @@ window.__ModuleLoader__.load({
|
|
|
577
691
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
578
692
|
className: QoderCredentialCard_module_css_default.modelTierSelect,
|
|
579
693
|
value: selectedTier ?? "",
|
|
580
|
-
disabled: disabled || unavailable || !selectedIds.has(model.id),
|
|
694
|
+
disabled: disabled || busy || unavailable || !selectedIds.has(model.id),
|
|
581
695
|
onChange: (event) => {
|
|
582
|
-
|
|
696
|
+
if (!disabled) editor.selectTier(model.id, event.currentTarget.value);
|
|
583
697
|
},
|
|
584
698
|
children: tiers.map((tier) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
585
699
|
value: tier.key,
|
|
@@ -610,32 +724,33 @@ window.__ModuleLoader__.load({
|
|
|
610
724
|
minute: "2-digit"
|
|
611
725
|
});
|
|
612
726
|
}
|
|
613
|
-
function modelsOf$1(value, selectedRegion) {
|
|
614
|
-
if (typeof value !== "object" || value === null) return defaultModels.map((model) => ({ ...model }));
|
|
615
|
-
const section = value;
|
|
616
|
-
const region = selectedRegion ?? (section.region === "china" ? "china" : "global");
|
|
617
|
-
const scoped = section.modelsByRegion?.[region];
|
|
618
|
-
if (Array.isArray(scoped)) return scoped;
|
|
619
|
-
return defaultModels.map((model) => ({ ...model }));
|
|
620
|
-
}
|
|
621
|
-
function regionOf$1(value) {
|
|
622
|
-
if (typeof value !== "object" || value === null) return "global";
|
|
623
|
-
return value.region === "china" ? "china" : "global";
|
|
624
|
-
}
|
|
625
727
|
/**
|
|
626
728
|
* Settings card for the Qoder subscription: credential state, subscriber
|
|
627
|
-
* profile, and every quota block the provider reports.
|
|
729
|
+
* profile, and every quota block the provider reports. Region changes remount
|
|
730
|
+
* the account state before any old profile can be displayed.
|
|
628
731
|
*/
|
|
629
|
-
function QoderAccountCard(
|
|
732
|
+
function QoderAccountCard(props) {
|
|
733
|
+
const modelSnapshot = (0, react.useSyncExternalStore)(props.operations.subscribeModels, props.operations.getModelSnapshot, props.operations.getModelSnapshot);
|
|
734
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegionAccountCard, {
|
|
735
|
+
...props,
|
|
736
|
+
modelSnapshot
|
|
737
|
+
}, regionOf(modelSnapshot.value));
|
|
738
|
+
}
|
|
739
|
+
function RegionAccountCard({ operations, t, activeLocale, modelSnapshot }) {
|
|
630
740
|
const [credentialState, setCredentialState] = (0, react.useState)({ status: "loading" });
|
|
631
741
|
const [accountState, setAccountState] = (0, react.useState)({ status: "idle" });
|
|
632
742
|
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
633
743
|
const [credentialRevision, setCredentialRevision] = (0, react.useState)(0);
|
|
634
|
-
const [modelSaveError, setModelSaveError] = (0, react.useState)();
|
|
635
744
|
const latestAccountRequest = (0, react.useRef)(0);
|
|
636
|
-
const
|
|
745
|
+
const latestCredentialRequest = (0, react.useRef)(0);
|
|
746
|
+
(0, react.useLayoutEffect)(() => () => {
|
|
747
|
+
latestAccountRequest.current++;
|
|
748
|
+
latestCredentialRequest.current++;
|
|
749
|
+
}, []);
|
|
637
750
|
const loadCredential = (0, react.useCallback)(async () => {
|
|
751
|
+
const requestId = ++latestCredentialRequest.current;
|
|
638
752
|
const info = await operations.describe();
|
|
753
|
+
if (requestId !== latestCredentialRequest.current) return;
|
|
639
754
|
setCredentialState(info === void 0 ? { status: "failed" } : {
|
|
640
755
|
status: "ready",
|
|
641
756
|
info
|
|
@@ -790,13 +905,14 @@ window.__ModuleLoader__.load({
|
|
|
790
905
|
const { profile, usage, plan } = accountState.account;
|
|
791
906
|
const userQuota = usage?.userQuota;
|
|
792
907
|
const orgPackage = usage?.orgResourcePackage;
|
|
908
|
+
const addOnQuota = usage?.addOnQuota;
|
|
793
909
|
const dedicatedPackages = usage?.dedicatedResourcePackages ?? [];
|
|
794
910
|
const locale = activeLocale();
|
|
795
911
|
const avatarInitial = (profile.name || profile.email || "Q").charAt(0).toUpperCase();
|
|
796
912
|
const resetDate = formatResetDate(usage?.expiresAt);
|
|
797
913
|
const planExpiry = plan?.endDate ? formatResetDate(plan.endDate) : void 0;
|
|
798
914
|
const isSuspended = plan?.organization?.isSuspended === true;
|
|
799
|
-
const hasQuota = (userQuota?.total ?? 0) > 0 || (orgPackage?.total ?? 0) > 0 || dedicatedPackages.some((pkg) => pkg.total > 0);
|
|
915
|
+
const hasQuota = (userQuota?.total ?? 0) > 0 || (orgPackage?.total ?? 0) > 0 || (addOnQuota?.total ?? 0) > 0 || dedicatedPackages.some((pkg) => pkg.total > 0);
|
|
800
916
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
801
917
|
className: QoderCredentialCard_module_css_default.accountSection,
|
|
802
918
|
children: [
|
|
@@ -853,6 +969,7 @@ window.__ModuleLoader__.load({
|
|
|
853
969
|
}) : null,
|
|
854
970
|
renderQuota("userQuota", t("userQuotaTitle"), userQuota, { resetDate }),
|
|
855
971
|
renderQuota("orgResource", t("orgResourceTitle"), orgPackage, { resetDate }),
|
|
972
|
+
renderQuota("addOnQuota", t("addOnQuotaTitle"), addOnQuota),
|
|
856
973
|
dedicatedPackages.map((pkg, index) => renderQuota(`dedicatedResource-${pkg.id ?? index}`, resolveLocalizedText(pkg.title, locale) ?? t("dedicatedResourceTitle"), pkg, {
|
|
857
974
|
expiresAt: formatResetDate(pkg.expiresAt),
|
|
858
975
|
description: resolveLocalizedText(pkg.description, locale)
|
|
@@ -928,19 +1045,9 @@ window.__ModuleLoader__.load({
|
|
|
928
1045
|
]
|
|
929
1046
|
});
|
|
930
1047
|
};
|
|
931
|
-
const currentRegion = regionOf
|
|
932
|
-
const currentModels = modelsOf
|
|
1048
|
+
const currentRegion = regionOf(modelSnapshot.value);
|
|
1049
|
+
const currentModels = modelsOf(modelSnapshot.value, currentRegion);
|
|
933
1050
|
const canModifyModels = modelSnapshot.status === "ready" && modelSnapshot.writable;
|
|
934
|
-
const handleModelsChange = async (models) => {
|
|
935
|
-
if (!canModifyModels) return;
|
|
936
|
-
setModelSaveError(void 0);
|
|
937
|
-
const failure = validateModelCatalog(models);
|
|
938
|
-
if (failure) {
|
|
939
|
-
setModelSaveError(t(failure));
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
if (!await operations.storeModels(currentRegion, models)) setModelSaveError(t("saveFailed"));
|
|
943
|
-
};
|
|
944
1051
|
const renderModelCatalogSection = () => {
|
|
945
1052
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
946
1053
|
className: QoderCredentialCard_module_css_default.customized,
|
|
@@ -950,29 +1057,23 @@ window.__ModuleLoader__.load({
|
|
|
950
1057
|
className: QoderCredentialCard_module_css_default.modelSummaryBadge,
|
|
951
1058
|
children: t("modelsEnabled", { count: currentModels.length })
|
|
952
1059
|
})]
|
|
953
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1060
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
954
1061
|
className: QoderCredentialCard_module_css_default.customizedBody,
|
|
955
|
-
children:
|
|
1062
|
+
children: modelSnapshot.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
956
1063
|
className: QoderCredentialCard_module_css_default.hint,
|
|
957
1064
|
children: t("modelsLoading")
|
|
958
1065
|
}) : modelSnapshot.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
959
1066
|
className: QoderCredentialCard_module_css_default.error,
|
|
960
1067
|
children: t("modelsUnavailable")
|
|
961
1068
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QoderModelCatalog, {
|
|
1069
|
+
region: currentRegion,
|
|
962
1070
|
operations,
|
|
963
1071
|
models: currentModels,
|
|
964
1072
|
disabled: !canModifyModels,
|
|
965
1073
|
fetchDisabled: !configured,
|
|
966
1074
|
hideTitle: true,
|
|
967
|
-
t
|
|
968
|
-
|
|
969
|
-
handleModelsChange(models);
|
|
970
|
-
}
|
|
971
|
-
}), modelSaveError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
972
|
-
className: QoderCredentialCard_module_css_default.error,
|
|
973
|
-
role: "alert",
|
|
974
|
-
children: modelSaveError
|
|
975
|
-
}) : null]
|
|
1075
|
+
t
|
|
1076
|
+
})
|
|
976
1077
|
})]
|
|
977
1078
|
});
|
|
978
1079
|
};
|
|
@@ -998,10 +1099,6 @@ window.__ModuleLoader__.load({
|
|
|
998
1099
|
}
|
|
999
1100
|
//#endregion
|
|
1000
1101
|
//#region src/client/QoderCredentialCard.tsx
|
|
1001
|
-
function regionOf(value) {
|
|
1002
|
-
if (typeof value !== "object" || value === null) return "global";
|
|
1003
|
-
return value.region === "china" ? "china" : "global";
|
|
1004
|
-
}
|
|
1005
1102
|
function QoderCredentialCard({ operations, t }) {
|
|
1006
1103
|
const [state, setState] = (0, react.useState)({ status: "loading" });
|
|
1007
1104
|
const [editing, setEditing] = (0, react.useState)(false);
|
|
@@ -1240,39 +1337,105 @@ window.__ModuleLoader__.load({
|
|
|
1240
1337
|
"qoder-subscription"
|
|
1241
1338
|
].includes(provider ?? "");
|
|
1242
1339
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1340
|
+
//#endregion
|
|
1341
|
+
//#region src/client/session-tier-state.ts
|
|
1342
|
+
/** A mounted view of the host's accepted selection; it owns no manual tier map. */
|
|
1343
|
+
var SessionTierState = class {
|
|
1344
|
+
snapshot = {
|
|
1345
|
+
loading: true,
|
|
1346
|
+
saving: false,
|
|
1347
|
+
error: false
|
|
1348
|
+
};
|
|
1349
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1350
|
+
generation = 0;
|
|
1351
|
+
active = false;
|
|
1352
|
+
lifetime = 0;
|
|
1353
|
+
unsubscribe;
|
|
1354
|
+
scope;
|
|
1355
|
+
operations;
|
|
1356
|
+
constructor(scope, operations) {
|
|
1357
|
+
this.scope = scope;
|
|
1358
|
+
this.operations = operations;
|
|
1257
1359
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1360
|
+
getSnapshot = () => this.snapshot;
|
|
1361
|
+
subscribe = (listener) => {
|
|
1362
|
+
this.listeners.add(listener);
|
|
1363
|
+
return () => {
|
|
1364
|
+
this.listeners.delete(listener);
|
|
1365
|
+
};
|
|
1366
|
+
};
|
|
1367
|
+
publish(value) {
|
|
1368
|
+
this.snapshot = {
|
|
1369
|
+
...this.snapshot,
|
|
1370
|
+
...value
|
|
1371
|
+
};
|
|
1372
|
+
for (const listener of this.listeners) listener();
|
|
1271
1373
|
}
|
|
1272
|
-
|
|
1374
|
+
activate() {
|
|
1375
|
+
this.active = true;
|
|
1376
|
+
this.lifetime++;
|
|
1377
|
+
this.publish({ saving: false });
|
|
1378
|
+
this.unsubscribe = this.operations.subscribeSessionTiers?.(this.scope, () => {
|
|
1379
|
+
this.refresh();
|
|
1380
|
+
});
|
|
1381
|
+
this.refresh();
|
|
1382
|
+
}
|
|
1383
|
+
dispose() {
|
|
1384
|
+
this.active = false;
|
|
1385
|
+
this.generation++;
|
|
1386
|
+
this.unsubscribe?.();
|
|
1387
|
+
this.unsubscribe = void 0;
|
|
1388
|
+
}
|
|
1389
|
+
matches(value) {
|
|
1390
|
+
return !!value && value.region === this.scope.region && value.sessionId === this.scope.sessionId && value.modelId === this.scope.modelId;
|
|
1391
|
+
}
|
|
1392
|
+
async refresh() {
|
|
1393
|
+
if (!this.active) return;
|
|
1394
|
+
const generation = ++this.generation;
|
|
1395
|
+
this.publish({ loading: true });
|
|
1396
|
+
try {
|
|
1397
|
+
const selection = await this.operations.readSessionTier?.(this.scope);
|
|
1398
|
+
if (this.active && generation === this.generation) this.publish(this.matches(selection) ? {
|
|
1399
|
+
selection,
|
|
1400
|
+
loading: false,
|
|
1401
|
+
error: false
|
|
1402
|
+
} : {
|
|
1403
|
+
loading: false,
|
|
1404
|
+
error: true
|
|
1405
|
+
});
|
|
1406
|
+
} catch {
|
|
1407
|
+
if (this.active && generation === this.generation) this.publish({
|
|
1408
|
+
loading: false,
|
|
1409
|
+
error: true
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
async select(tierKey) {
|
|
1414
|
+
if (!this.active || this.snapshot.loading || this.snapshot.saving || !this.snapshot.selection) return;
|
|
1415
|
+
if (tierKey === this.snapshot.selection.tierKey && !this.snapshot.error) return;
|
|
1416
|
+
const generation = ++this.generation;
|
|
1417
|
+
const lifetime = this.lifetime;
|
|
1418
|
+
this.publish({
|
|
1419
|
+
saving: true,
|
|
1420
|
+
error: false
|
|
1421
|
+
});
|
|
1422
|
+
try {
|
|
1423
|
+
const { sessionId, modelId, region } = this.scope;
|
|
1424
|
+
const selection = await this.operations.setSessionTier?.(sessionId, modelId, tierKey, region);
|
|
1425
|
+
if (this.active && generation === this.generation) this.publish(this.matches(selection) ? {
|
|
1426
|
+
selection,
|
|
1427
|
+
error: false
|
|
1428
|
+
} : { error: true });
|
|
1429
|
+
} catch {
|
|
1430
|
+
if (this.active && generation === this.generation) this.publish({ error: true });
|
|
1431
|
+
} finally {
|
|
1432
|
+
if (this.active && lifetime === this.lifetime) this.publish({ saving: false });
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1273
1436
|
//#endregion
|
|
1274
1437
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderContextSelect.module.css.mjs
|
|
1275
|
-
const css = ".hiDrJa_root{align-items:center;display:inline-flex;position:relative}.hiDrJa_trigger{height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;user-select:none;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;transition:background .12s,color .12s;display:flex}.hiDrJa_trigger:hover,.hiDrJa_triggerActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.hiDrJa_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.hiDrJa_icon{color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;display:inline-flex}.hiDrJa_label{white-space:nowrap}.hiDrJa_chevron{color:var(--dsw-alias-label-caption);align-items:center;transition:transform .12s;display:inline-flex}.hiDrJa_chevronOpen{transform:rotate(180deg)}.hiDrJa_menu{z-index:1100;background:var(--dsw-
|
|
1438
|
+
const css = ".hiDrJa_root{align-items:center;display:inline-flex;position:relative}.hiDrJa_trigger{height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;user-select:none;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;transition:background .12s,color .12s;display:flex}.hiDrJa_trigger:hover,.hiDrJa_triggerActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.hiDrJa_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.hiDrJa_icon{color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;display:inline-flex}.hiDrJa_label{white-space:nowrap}.hiDrJa_chevron{color:var(--dsw-alias-label-caption);align-items:center;transition:transform .12s;display:inline-flex}.hiDrJa_chevronOpen{transform:rotate(180deg)}.hiDrJa_menu{z-index:1100;background:var(--dsw-menu-surface-fill);min-width:180px;backdrop-filter:var(--dsw-menu-backdrop-filter);border:1px solid var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;padding:4px;animation:.12s hiDrJa_fadeIn;display:flex;position:absolute;bottom:calc(100% + 8px);right:0}@keyframes hiDrJa_fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.hiDrJa_menuHeader{text-transform:uppercase;letter-spacing:.5px;color:var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-border-l1);margin-bottom:4px;padding:6px 10px 4px;font-size:11px;font-weight:600}.hiDrJa_option{box-sizing:border-box;width:100%;color:inherit;cursor:pointer;text-align:left;background:0 0;border:none;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;font-size:13px;line-height:20px;transition:background .1s;display:flex}.hiDrJa_option:hover{background:var(--dsw-alias-interactive-bg-hover)}.hiDrJa_optionSelected{color:var(--dsw-alias-state-brand);font-weight:600}.hiDrJa_optionInfo{align-items:center;gap:6px;display:flex}.hiDrJa_tag{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-caption);border-radius:4px;padding:1px 5px;font-size:11px;font-weight:500}.hiDrJa_check{color:var(--dsw-alias-state-brand);align-items:center;font-size:12px;display:inline-flex}.hiDrJa_error{color:var(--dsw-alias-label-primary);max-width:240px;font-size:12px}";
|
|
1276
1439
|
const tagId = "dsh-provider-qoder/QoderContextSelect.module.css";
|
|
1277
1440
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1278
1441
|
const tag = document.createElement("style");
|
|
@@ -1302,31 +1465,9 @@ window.__ModuleLoader__.load({
|
|
|
1302
1465
|
//#endregion
|
|
1303
1466
|
//#region src/client/QoderContextSelect.tsx
|
|
1304
1467
|
function QoderContextSelect(props) {
|
|
1305
|
-
const { directory, operations,
|
|
1306
|
-
const [open, setOpen] = (0, react.useState)(false);
|
|
1307
|
-
const [manualTiers, setManualTiers] = (0, react.useState)({});
|
|
1308
|
-
const [pending, setPending] = (0, react.useState)(false);
|
|
1309
|
-
const [error, setError] = (0, react.useState)(null);
|
|
1310
|
-
const saving = (0, react.useRef)(false);
|
|
1311
|
-
const legacyRegion = (0, react.useRef)(void 0);
|
|
1312
|
-
const rootRef = (0, react.useRef)(null);
|
|
1468
|
+
const { directory, operations, sessionId, useProjection } = props;
|
|
1313
1469
|
const directoryState = (0, react.useSyncExternalStore)((fn) => directory ? directory.subscribe(fn) : () => () => {}, () => directory ? directory.getSnapshot() : null);
|
|
1314
1470
|
const modelSnapshot = (0, react.useSyncExternalStore)((fn) => operations ? operations.subscribeModels(fn) : () => () => {}, () => operations ? operations.getModelSnapshot() : null);
|
|
1315
|
-
(0, react.useEffect)(() => {
|
|
1316
|
-
if (!open) return;
|
|
1317
|
-
const handleClickOutside = (e) => {
|
|
1318
|
-
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
1319
|
-
};
|
|
1320
|
-
const handleKeyDown = (e) => {
|
|
1321
|
-
if (e.key === "Escape") setOpen(false);
|
|
1322
|
-
};
|
|
1323
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
1324
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
1325
|
-
return () => {
|
|
1326
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
1327
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
1328
|
-
};
|
|
1329
|
-
}, [open]);
|
|
1330
1471
|
const modelProj = useProjection ? useProjection("modelSelection") : void 0;
|
|
1331
1472
|
const pressure = useProjection ? useProjection("contextPressure") : void 0;
|
|
1332
1473
|
if (!operations) return null;
|
|
@@ -1336,45 +1477,77 @@ window.__ModuleLoader__.load({
|
|
|
1336
1477
|
model: projectedCurrent.model
|
|
1337
1478
|
} : null);
|
|
1338
1479
|
if (!current) return null;
|
|
1339
|
-
const region = modelSnapshot?.value
|
|
1340
|
-
|
|
1341
|
-
const models = modelsOf(modelSnapshot?.value, region, legacyRegion.current ?? region);
|
|
1480
|
+
const region = regionOf(modelSnapshot?.value);
|
|
1481
|
+
const models = modelsOf(modelSnapshot?.value, region);
|
|
1342
1482
|
const currentModelId = current.model.includes("/") ? current.model.split("/")[1] : current.model;
|
|
1343
1483
|
const currentProviderId = current.provider ?? (current.model.includes("/") ? current.model.split("/")[0] : void 0);
|
|
1344
1484
|
const activeModel = models.find((m) => m.id === currentModelId || m.id === current.model);
|
|
1345
1485
|
if (!isQoderProvider(currentProviderId) || !activeModel) return null;
|
|
1346
|
-
|
|
1347
|
-
if (
|
|
1348
|
-
|
|
1486
|
+
if (contextTiersOf(activeModel).length <= 1) return null;
|
|
1487
|
+
if (!sessionId) return null;
|
|
1488
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionContextSelect, {
|
|
1489
|
+
...props,
|
|
1490
|
+
sessionId,
|
|
1491
|
+
operations,
|
|
1492
|
+
region,
|
|
1493
|
+
activeModel,
|
|
1494
|
+
historicalWindow: pressure?.contextWindow,
|
|
1495
|
+
lastUsed: modelProj?.lastUsed
|
|
1496
|
+
}, JSON.stringify([
|
|
1349
1497
|
region,
|
|
1350
1498
|
sessionId,
|
|
1351
1499
|
activeModel.id
|
|
1352
|
-
])
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const
|
|
1357
|
-
const
|
|
1500
|
+
]));
|
|
1501
|
+
}
|
|
1502
|
+
function SessionContextSelect({ operations, sessionId, region, activeModel, t, historicalWindow, lastUsed }) {
|
|
1503
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
1504
|
+
const rootRef = (0, react.useRef)(null);
|
|
1505
|
+
const state = (0, react.useMemo)(() => new SessionTierState({
|
|
1506
|
+
region,
|
|
1507
|
+
sessionId,
|
|
1508
|
+
modelId: activeModel.id
|
|
1509
|
+
}, operations), [
|
|
1510
|
+
region,
|
|
1511
|
+
sessionId,
|
|
1512
|
+
activeModel.id,
|
|
1513
|
+
operations
|
|
1514
|
+
]);
|
|
1515
|
+
const snapshot = (0, react.useSyncExternalStore)(state.subscribe, state.getSnapshot);
|
|
1516
|
+
(0, react.useLayoutEffect)(() => {
|
|
1517
|
+
state.activate();
|
|
1518
|
+
return () => state.dispose();
|
|
1519
|
+
}, [state]);
|
|
1520
|
+
(0, react.useEffect)(() => {
|
|
1521
|
+
state.refresh();
|
|
1522
|
+
}, [
|
|
1523
|
+
state,
|
|
1524
|
+
JSON.stringify(activeModel),
|
|
1525
|
+
historicalWindow,
|
|
1526
|
+
lastUsed?.provider,
|
|
1527
|
+
lastUsed?.model
|
|
1528
|
+
]);
|
|
1529
|
+
(0, react.useEffect)(() => {
|
|
1530
|
+
if (!open) return;
|
|
1531
|
+
const handleClickOutside = (e) => {
|
|
1532
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
1533
|
+
};
|
|
1534
|
+
const handleKeyDown = (e) => {
|
|
1535
|
+
if (e.key === "Escape") setOpen(false);
|
|
1536
|
+
};
|
|
1537
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1538
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1539
|
+
return () => {
|
|
1540
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1541
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
1542
|
+
};
|
|
1543
|
+
}, [open]);
|
|
1544
|
+
const tiers = contextTiersOf(activeModel);
|
|
1545
|
+
const currentTier = snapshot.selection;
|
|
1546
|
+
const selectedTierKey = currentTier?.tierKey;
|
|
1547
|
+
const pending = snapshot.loading || snapshot.saving;
|
|
1548
|
+
const selectTier = (tierKey) => {
|
|
1358
1549
|
setOpen(false);
|
|
1359
|
-
|
|
1360
|
-
if (tierKey === selectedTierKey && error?.key !== sessionKey) return;
|
|
1361
|
-
saving.current = true;
|
|
1362
|
-
setPending(true);
|
|
1363
|
-
setError(null);
|
|
1364
|
-
try {
|
|
1365
|
-
const result = await saveContextSelection(operations, sessionId, region, activeModel.id, tierKey, legacyRegion.current ?? region);
|
|
1366
|
-
if (result !== "session-failed") setManualTiers((prev) => ({
|
|
1367
|
-
...prev,
|
|
1368
|
-
[sessionKey]: tierKey
|
|
1369
|
-
}));
|
|
1370
|
-
if (result !== "saved") setError({
|
|
1371
|
-
key: sessionKey,
|
|
1372
|
-
message: result === "session-failed" ? "contextSelectFailed" : "contextDefaultFailed"
|
|
1373
|
-
});
|
|
1374
|
-
} finally {
|
|
1375
|
-
saving.current = false;
|
|
1376
|
-
setPending(false);
|
|
1377
|
-
}
|
|
1550
|
+
state.select(tierKey);
|
|
1378
1551
|
};
|
|
1379
1552
|
const defaultSuffix = t ? t("contextTierDefaultSuffix").replace(/[()()]/g, "") : "默认";
|
|
1380
1553
|
const selectTitle = t ? t("contextSelectTitle") : "选择上下文大小";
|
|
@@ -1386,10 +1559,10 @@ window.__ModuleLoader__.load({
|
|
|
1386
1559
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1387
1560
|
type: "button",
|
|
1388
1561
|
className: `${QoderContextSelect_module_css_default.trigger} ${open ? QoderContextSelect_module_css_default.triggerActive : ""}`,
|
|
1389
|
-
disabled: pending || !
|
|
1562
|
+
disabled: pending || !currentTier,
|
|
1390
1563
|
"aria-expanded": open,
|
|
1391
1564
|
"aria-label": selectTitle,
|
|
1392
|
-
title: `${selectTitle}: ${formatContextTokens(currentTier.tokenCount)}`,
|
|
1565
|
+
title: `${selectTitle}: ${currentTier ? formatContextTokens(currentTier.tokenCount) : "…"}`,
|
|
1393
1566
|
onClick: () => setOpen((prev) => !prev),
|
|
1394
1567
|
children: [
|
|
1395
1568
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1404,7 +1577,7 @@ window.__ModuleLoader__.load({
|
|
|
1404
1577
|
}),
|
|
1405
1578
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1406
1579
|
className: QoderContextSelect_module_css_default.label,
|
|
1407
|
-
children: formatContextTokens(currentTier.tokenCount)
|
|
1580
|
+
children: currentTier ? formatContextTokens(currentTier.tokenCount) : "…"
|
|
1408
1581
|
}),
|
|
1409
1582
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1410
1583
|
className: `${QoderContextSelect_module_css_default.chevron} ${open ? QoderContextSelect_module_css_default.chevronOpen : ""}`,
|
|
@@ -1422,10 +1595,21 @@ window.__ModuleLoader__.load({
|
|
|
1422
1595
|
})
|
|
1423
1596
|
]
|
|
1424
1597
|
}),
|
|
1425
|
-
error &&
|
|
1598
|
+
snapshot.error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1426
1599
|
role: "alert",
|
|
1427
1600
|
className: QoderContextSelect_module_css_default.error,
|
|
1428
|
-
children:
|
|
1601
|
+
children: [
|
|
1602
|
+
t ? t("contextSelectFailed") : "contextSelectFailed",
|
|
1603
|
+
" ",
|
|
1604
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1605
|
+
type: "button",
|
|
1606
|
+
disabled: pending,
|
|
1607
|
+
onClick: () => {
|
|
1608
|
+
state.refresh();
|
|
1609
|
+
},
|
|
1610
|
+
children: t ? t("refresh") : "refresh"
|
|
1611
|
+
})
|
|
1612
|
+
]
|
|
1429
1613
|
}),
|
|
1430
1614
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1431
1615
|
className: QoderContextSelect_module_css_default.menu,
|
|
@@ -1439,6 +1623,7 @@ window.__ModuleLoader__.load({
|
|
|
1439
1623
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1440
1624
|
type: "button",
|
|
1441
1625
|
role: "menuitemradio",
|
|
1626
|
+
disabled: pending,
|
|
1442
1627
|
"aria-checked": isSelected,
|
|
1443
1628
|
className: `${QoderContextSelect_module_css_default.option} ${isSelected ? QoderContextSelect_module_css_default.optionSelected : ""}`,
|
|
1444
1629
|
onClick: () => {
|
|
@@ -1494,6 +1679,97 @@ window.__ModuleLoader__.load({
|
|
|
1494
1679
|
return typeof value === "string" && qoderRpcErrorCodes.includes(value);
|
|
1495
1680
|
}
|
|
1496
1681
|
//#endregion
|
|
1682
|
+
//#region src/client/session-tier-events.ts
|
|
1683
|
+
/** One authenticated host change stream shared by the mounted composer controls. */
|
|
1684
|
+
function createSessionTierEvents(send = (...args) => globalThis.fetch(...args)) {
|
|
1685
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1686
|
+
let active;
|
|
1687
|
+
let disposed = false;
|
|
1688
|
+
const notify = (scope) => {
|
|
1689
|
+
for (const entry of listeners) if (!scope || entry.scope.region === scope.region && entry.scope.sessionId === scope.sessionId && entry.scope.modelId === scope.modelId) try {
|
|
1690
|
+
entry.listener();
|
|
1691
|
+
} catch {}
|
|
1692
|
+
};
|
|
1693
|
+
const start = () => {
|
|
1694
|
+
if (active || disposed || !listeners.size) return;
|
|
1695
|
+
const controller = new AbortController();
|
|
1696
|
+
active = controller;
|
|
1697
|
+
follow(controller).finally(() => {
|
|
1698
|
+
if (active === controller) active = void 0;
|
|
1699
|
+
});
|
|
1700
|
+
};
|
|
1701
|
+
async function follow(controller) {
|
|
1702
|
+
let delay = 1e3;
|
|
1703
|
+
while (!controller.signal.aborted) {
|
|
1704
|
+
try {
|
|
1705
|
+
const response = await send(qoderRpcPath("sessionTierEvents"), {
|
|
1706
|
+
method: "POST",
|
|
1707
|
+
credentials: "include",
|
|
1708
|
+
signal: controller.signal,
|
|
1709
|
+
headers: { "content-type": "application/json" },
|
|
1710
|
+
body: "{}"
|
|
1711
|
+
});
|
|
1712
|
+
if (!response.ok || !response.body) throw new Error("Context tier stream unavailable");
|
|
1713
|
+
const reader = response.body.getReader();
|
|
1714
|
+
const decoder = new TextDecoder();
|
|
1715
|
+
let buffered = "";
|
|
1716
|
+
try {
|
|
1717
|
+
while (!controller.signal.aborted) {
|
|
1718
|
+
const { value, done } = await reader.read();
|
|
1719
|
+
if (done) break;
|
|
1720
|
+
buffered += decoder.decode(value, { stream: true });
|
|
1721
|
+
let newline;
|
|
1722
|
+
while ((newline = buffered.indexOf("\n")) >= 0) {
|
|
1723
|
+
const item = JSON.parse(buffered.slice(0, newline));
|
|
1724
|
+
buffered = buffered.slice(newline + 1);
|
|
1725
|
+
delay = 1e3;
|
|
1726
|
+
if (item.ready === true) notify();
|
|
1727
|
+
else if ((item.region === "global" || item.region === "china") && typeof item.sessionId === "string" && typeof item.modelId === "string") notify(item);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
} finally {
|
|
1731
|
+
await reader.cancel().catch(() => {});
|
|
1732
|
+
reader.releaseLock();
|
|
1733
|
+
}
|
|
1734
|
+
} catch {}
|
|
1735
|
+
if (controller.signal.aborted) break;
|
|
1736
|
+
await new Promise((resolve) => {
|
|
1737
|
+
const finish = () => {
|
|
1738
|
+
clearTimeout(timer);
|
|
1739
|
+
controller.signal.removeEventListener("abort", finish);
|
|
1740
|
+
resolve();
|
|
1741
|
+
};
|
|
1742
|
+
const timer = setTimeout(finish, delay);
|
|
1743
|
+
controller.signal.addEventListener("abort", finish, { once: true });
|
|
1744
|
+
});
|
|
1745
|
+
delay = Math.min(delay * 2, 3e4);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
return {
|
|
1749
|
+
subscribe(scope, listener) {
|
|
1750
|
+
const entry = {
|
|
1751
|
+
scope,
|
|
1752
|
+
listener
|
|
1753
|
+
};
|
|
1754
|
+
listeners.add(entry);
|
|
1755
|
+
start();
|
|
1756
|
+
return () => {
|
|
1757
|
+
listeners.delete(entry);
|
|
1758
|
+
if (!listeners.size) {
|
|
1759
|
+
active?.abort();
|
|
1760
|
+
active = void 0;
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
},
|
|
1764
|
+
dispose() {
|
|
1765
|
+
disposed = true;
|
|
1766
|
+
listeners.clear();
|
|
1767
|
+
active?.abort();
|
|
1768
|
+
active = void 0;
|
|
1769
|
+
}
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
//#endregion
|
|
1497
1773
|
//#region src/client/rpc-client.ts
|
|
1498
1774
|
/**
|
|
1499
1775
|
* Browser caller for the Qoder settings RPC.
|
|
@@ -1589,21 +1865,9 @@ window.__ModuleLoader__.load({
|
|
|
1589
1865
|
}), "provider-qoder: credential copy");
|
|
1590
1866
|
const credentials = ctx.remote.credentials;
|
|
1591
1867
|
const rpc = createQoderRpcCaller();
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
const readModelSnapshot = () =>
|
|
1595
|
-
const snapshot = modelScope.getSnapshot();
|
|
1596
|
-
if (snapshot.value) {
|
|
1597
|
-
const region = snapshot.value.region ?? "global";
|
|
1598
|
-
if (historyRegion !== void 0 && historyRegion !== region) historyRegionChanged = true;
|
|
1599
|
-
historyRegion = region;
|
|
1600
|
-
}
|
|
1601
|
-
return snapshot;
|
|
1602
|
-
};
|
|
1603
|
-
readModelSnapshot();
|
|
1604
|
-
ctx.effect(() => modelScope.subscribe(() => {
|
|
1605
|
-
readModelSnapshot();
|
|
1606
|
-
}), "provider-qoder: context history region");
|
|
1868
|
+
const tierEvents = createSessionTierEvents();
|
|
1869
|
+
ctx.effect(() => () => tierEvents.dispose(), "provider-qoder: session context tier events");
|
|
1870
|
+
const readModelSnapshot = () => modelScope.getSnapshot();
|
|
1607
1871
|
const operations = {
|
|
1608
1872
|
describe: async () => {
|
|
1609
1873
|
try {
|
|
@@ -1629,19 +1893,15 @@ window.__ModuleLoader__.load({
|
|
|
1629
1893
|
},
|
|
1630
1894
|
getAccount: async (force) => await rpc.call("account", { force }),
|
|
1631
1895
|
getModelSnapshot: readModelSnapshot,
|
|
1632
|
-
canRestoreContextHistory: () => !historyRegionChanged,
|
|
1633
1896
|
subscribeModels: (listener) => modelScope.subscribe(listener),
|
|
1634
1897
|
storeModels: async (region, models) => {
|
|
1635
1898
|
try {
|
|
1636
|
-
const
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
...current?.modelsByRegion,
|
|
1643
|
-
[region]: clonedModels
|
|
1644
|
-
}) !== false;
|
|
1899
|
+
const clonedModels = JSON.parse(JSON.stringify(models));
|
|
1900
|
+
return await modelScope.mutate([{
|
|
1901
|
+
op: "set",
|
|
1902
|
+
path: ["modelsByRegion", region],
|
|
1903
|
+
value: clonedModels
|
|
1904
|
+
}]) !== false;
|
|
1645
1905
|
} catch {
|
|
1646
1906
|
return false;
|
|
1647
1907
|
}
|
|
@@ -1663,16 +1923,22 @@ window.__ModuleLoader__.load({
|
|
|
1663
1923
|
discoverModels: async () => await rpc.call("models", {}),
|
|
1664
1924
|
setSessionTier: async (sessionId, modelId, tierKey, region) => {
|
|
1665
1925
|
try {
|
|
1666
|
-
|
|
1926
|
+
const res = await rpc.call("sessionTier", {
|
|
1667
1927
|
sessionId,
|
|
1668
1928
|
modelId,
|
|
1669
1929
|
tierKey,
|
|
1670
1930
|
region
|
|
1671
|
-
})
|
|
1931
|
+
});
|
|
1932
|
+
return res.ok ? res.value : void 0;
|
|
1672
1933
|
} catch {
|
|
1673
|
-
return
|
|
1934
|
+
return;
|
|
1674
1935
|
}
|
|
1675
1936
|
},
|
|
1937
|
+
readSessionTier: async (scope) => {
|
|
1938
|
+
const result = await rpc.call("readSessionTier", scope);
|
|
1939
|
+
return result.ok ? result.value : void 0;
|
|
1940
|
+
},
|
|
1941
|
+
subscribeSessionTiers: (scope, listener) => tierEvents.subscribe(scope, listener),
|
|
1676
1942
|
subscribe: (listener) => ctx.remote.$on("credentials/reference-updated", (ref) => {
|
|
1677
1943
|
if (ref === "QODER_MANAGED_CREDENTIAL") listener();
|
|
1678
1944
|
})
|
|
@@ -1709,25 +1975,31 @@ window.__ModuleLoader__.load({
|
|
|
1709
1975
|
activeLocale
|
|
1710
1976
|
})
|
|
1711
1977
|
}, QoderCredentialCard));
|
|
1712
|
-
ctx.
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1978
|
+
ctx.inject([
|
|
1979
|
+
"modelDirectories",
|
|
1980
|
+
"sessions",
|
|
1981
|
+
"remote.session"
|
|
1982
|
+
], (scope) => {
|
|
1983
|
+
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
1984
|
+
name: "conversation.input.right",
|
|
1985
|
+
id: "qoder-context-select",
|
|
1986
|
+
order: 10,
|
|
1987
|
+
inject: (sessionId) => {
|
|
1988
|
+
let directory = void 0;
|
|
1989
|
+
try {
|
|
1990
|
+
const modelDirectories = scope.get("modelDirectories");
|
|
1991
|
+
directory = sessionId && modelDirectories ? modelDirectories.directoryFor(sessionId)?.store : void 0;
|
|
1992
|
+
} catch {}
|
|
1993
|
+
return {
|
|
1994
|
+
sessionId,
|
|
1995
|
+
directory,
|
|
1996
|
+
operations,
|
|
1997
|
+
t,
|
|
1998
|
+
activeLocale
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
}, QoderContextSelect));
|
|
2002
|
+
});
|
|
1731
2003
|
}
|
|
1732
2004
|
//#endregion
|
|
1733
2005
|
exports.apply = apply;
|