dsh-codex-subscription 1.9.0 → 1.11.0
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/AGENTS.md +5 -5
- package/README.md +36 -44
- package/README.zh-CN.md +35 -43
- package/THIRD_PARTY_NOTICES.md +1 -0
- package/lib/client.js +458 -210
- package/lib/index.js +719 -51
- package/package.json +5 -1
package/lib/client.js
CHANGED
|
@@ -59,18 +59,45 @@ window.__ModuleLoader__.load({
|
|
|
59
59
|
const base = prompt.trim() === "" ? translate("imageEditDefault") : prompt.trim();
|
|
60
60
|
return notes.length === 0 ? base : base + "\n\n" + translate("imageRegionNotes") + "\n" + notes.join("\n");
|
|
61
61
|
}
|
|
62
|
+
const ORIGINAL_IMAGE_ID_PATTERN = /^img_[0-9a-f]{32}$/u;
|
|
63
|
+
const positiveInteger = (value) => Number.isSafeInteger(value) && value > 0;
|
|
64
|
+
function decodeOriginalImageRef(value) {
|
|
65
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || typeof value.assetId !== "string" || !ORIGINAL_IMAGE_ID_PATTERN.test(value.assetId) || value.mediaType !== "image/png" || !positiveInteger(value.bytes) || value.bytes > 48 * 1024 * 1024 || !positiveInteger(value.width) || !positiveInteger(value.height) || typeof value.name !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value.name) || typeof value.sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(value.sha256)) return void 0;
|
|
66
|
+
return {
|
|
67
|
+
assetId: value.assetId,
|
|
68
|
+
mediaType: value.mediaType,
|
|
69
|
+
bytes: value.bytes,
|
|
70
|
+
width: value.width,
|
|
71
|
+
height: value.height,
|
|
72
|
+
name: value.name,
|
|
73
|
+
sha256: value.sha256
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function decodeImagePresentation(value) {
|
|
77
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value.kind !== "codex-subscription-image" || value.schemaVersion !== 1) return void 0;
|
|
78
|
+
const original = decodeOriginalImageRef(value.original);
|
|
79
|
+
return original === void 0 ? void 0 : { original };
|
|
80
|
+
}
|
|
62
81
|
//#endregion
|
|
63
82
|
//#region src/settings-contract.js
|
|
64
83
|
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
65
84
|
const QUICK_QUOTA_MODE_FIELD = "quickQuotaMode";
|
|
66
85
|
const LEGACY_QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
67
86
|
const QUICK_QUOTA_MODE_PERCENT = "percent";
|
|
87
|
+
const QUICK_QUOTA_MODE_FORECAST = "forecast";
|
|
68
88
|
const SEARCH_PROVIDER_FIELD = "searchProvider";
|
|
89
|
+
const SEARCH_PROVIDER_AUTO = "auto";
|
|
69
90
|
const SEARCH_PROVIDER_CODEX = "codex";
|
|
91
|
+
const DEFAULT_SEARCH_PROVIDER = SEARCH_PROVIDER_AUTO;
|
|
70
92
|
const SPEED_MODE_FIELD = "speedMode";
|
|
71
93
|
const SPEED_MODE_STANDARD = "standard";
|
|
72
94
|
const SPEED_MODE_FAST = "fast";
|
|
73
95
|
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
96
|
+
const OUTPUT_VERBOSITY_FIELD = "outputVerbosity";
|
|
97
|
+
const OUTPUT_VERBOSITY_DEFAULT = "default";
|
|
98
|
+
const OUTPUT_VERBOSITY_MEDIUM = "medium";
|
|
99
|
+
const OUTPUT_VERBOSITY_HIGH = "high";
|
|
100
|
+
const DEFAULT_OUTPUT_VERBOSITY = OUTPUT_VERBOSITY_DEFAULT;
|
|
74
101
|
const CONTEXT_MODE_FIELD = "contextMode";
|
|
75
102
|
const CONTEXT_MODE_STANDARD = "standard";
|
|
76
103
|
const CONTEXT_MODE_EXTENDED = "extended";
|
|
@@ -98,7 +125,17 @@ window.__ModuleLoader__.load({
|
|
|
98
125
|
"gpt-5.5": 272e3,
|
|
99
126
|
"gpt-5.6": 272e3
|
|
100
127
|
});
|
|
101
|
-
const normalizeSearchProvider = (value) => [
|
|
128
|
+
const normalizeSearchProvider = (value) => [
|
|
129
|
+
"auto",
|
|
130
|
+
"dsh",
|
|
131
|
+
"codex"
|
|
132
|
+
].includes(value) ? value : DEFAULT_SEARCH_PROVIDER;
|
|
133
|
+
const normalizeOutputVerbosity = (value) => [
|
|
134
|
+
"default",
|
|
135
|
+
"low",
|
|
136
|
+
"medium",
|
|
137
|
+
"high"
|
|
138
|
+
].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
|
|
102
139
|
const normalizeSpeedMode = (value) => ["standard", "fast"].includes(value) ? value : DEFAULT_SPEED_MODE;
|
|
103
140
|
const normalizeContextMode = (value) => [
|
|
104
141
|
"standard",
|
|
@@ -118,7 +155,8 @@ window.__ModuleLoader__.load({
|
|
|
118
155
|
const normalizeQuickQuotaMode = (value, legacyVisible = false) => [
|
|
119
156
|
"off",
|
|
120
157
|
"percent",
|
|
121
|
-
"bar"
|
|
158
|
+
"bar",
|
|
159
|
+
"forecast"
|
|
122
160
|
].includes(value) ? value : legacyVisible === true ? QUICK_QUOTA_MODE_PERCENT : "off";
|
|
123
161
|
const supportsCodexFastMode = (modelId) => typeof modelId === "string" && (/^gpt-5\.(?:5|6)(?:$|-)/u.test(modelId) || modelId === "gpt-5.4");
|
|
124
162
|
//#endregion
|
|
@@ -136,7 +174,8 @@ window.__ModuleLoader__.load({
|
|
|
136
174
|
return {
|
|
137
175
|
remainingPercent: selected.remainingPercent,
|
|
138
176
|
windowSeconds: selected.windowSeconds,
|
|
139
|
-
...Number.isSafeInteger(selected.resetsAt) ? { resetsAt: selected.resetsAt } : {}
|
|
177
|
+
...Number.isSafeInteger(selected.resetsAt) ? { resetsAt: selected.resetsAt } : {},
|
|
178
|
+
...selected.forecast === void 0 ? {} : { forecast: selected.forecast }
|
|
140
179
|
};
|
|
141
180
|
}
|
|
142
181
|
//#endregion
|
|
@@ -223,7 +262,9 @@ window.__ModuleLoader__.load({
|
|
|
223
262
|
diagnosticsFailed: "无法生成诊断信息。",
|
|
224
263
|
feedbackOpen: "反馈问题",
|
|
225
264
|
searchTitle: "搜索来源",
|
|
226
|
-
searchScope: "
|
|
265
|
+
searchScope: "自动按当前会话模型分流;手动选择会覆盖所有模型和会话。",
|
|
266
|
+
searchAuto: "自动",
|
|
267
|
+
searchAutoHint: "Codex 模型用订阅搜索,其他模型用 DSH",
|
|
227
268
|
searchDsh: "DSH 默认",
|
|
228
269
|
searchDshHint: "所有模型使用 DSH 当前搜索服务",
|
|
229
270
|
searchCodex: "Codex 订阅",
|
|
@@ -285,6 +326,8 @@ window.__ModuleLoader__.load({
|
|
|
285
326
|
quickQuotaOff: "关闭",
|
|
286
327
|
quickQuotaPercent: "百分比",
|
|
287
328
|
quickQuotaBar: "进度条",
|
|
329
|
+
quickQuotaForecast: "续航预测",
|
|
330
|
+
quickQuotaBeta: "Beta",
|
|
288
331
|
contextTitle: "上下文窗口",
|
|
289
332
|
contextStandard: "标准",
|
|
290
333
|
contextStandardHint: "使用模型目录默认值;官方 Agent 预设会自动管理上下文。",
|
|
@@ -296,12 +339,27 @@ window.__ModuleLoader__.load({
|
|
|
296
339
|
contextFixed: "固定 {value}",
|
|
297
340
|
contextMaximum: "范围 128000–{value}",
|
|
298
341
|
quickQuotaStatus: "Codex 剩余额度 {value}%",
|
|
342
|
+
quickQuotaForecastStatus: "Codex 剩余额度 {value}%,按当前速度预计可用 {duration}",
|
|
343
|
+
quotaForecast: "按当前速度 {symbol}{duration}",
|
|
344
|
+
runwayDaysHours: "{days} 天 {hours} 小时",
|
|
345
|
+
runwayDays: "{days} 天",
|
|
346
|
+
runwayHours: "{hours} 小时",
|
|
347
|
+
runwayMinutes: "{minutes} 分钟",
|
|
299
348
|
speedTitle: "速度",
|
|
300
349
|
speedStandard: "标准",
|
|
301
350
|
speedStandardHint: "标准速度",
|
|
302
351
|
speedFast: "高速",
|
|
303
352
|
speedFastHint: "1.5 倍,消耗更多 Credits",
|
|
304
|
-
|
|
353
|
+
verbosityTitle: "输出详略",
|
|
354
|
+
verbosityDefault: "模型默认",
|
|
355
|
+
verbosityDefaultHint: "使用官方模型目录推荐值",
|
|
356
|
+
verbosityLow: "简洁",
|
|
357
|
+
verbosityLowHint: "更短、更直接",
|
|
358
|
+
verbosityMedium: "均衡",
|
|
359
|
+
verbosityMediumHint: "兼顾完整性与长度",
|
|
360
|
+
verbosityHigh: "详细",
|
|
361
|
+
verbosityHighHint: "更充分的说明与结构",
|
|
362
|
+
modelMenuAria: "模型、推理等级、速度与输出详略",
|
|
305
363
|
modelLabel: "模型",
|
|
306
364
|
effortLabel: "推理等级",
|
|
307
365
|
providerDefault: "Default",
|
|
@@ -318,13 +376,16 @@ window.__ModuleLoader__.load({
|
|
|
318
376
|
imageGenerated: "已生成",
|
|
319
377
|
imageFailed: "生成失败",
|
|
320
378
|
imageLabel: "生成的图片",
|
|
321
|
-
imageOpen: "
|
|
379
|
+
imageOpen: "查看图片",
|
|
322
380
|
imageOpenNamed: "查看 {value}",
|
|
323
381
|
imageLoading: "正在加载图片…",
|
|
324
382
|
imageLoadFailed: "图片加载失败,点击重试",
|
|
325
383
|
imagePreview: "图片预览",
|
|
384
|
+
imagePreviewShort: "预览图",
|
|
326
385
|
imageClosePreview: "关闭预览",
|
|
327
|
-
imageDownload: "
|
|
386
|
+
imageDownload: "下载",
|
|
387
|
+
imageDownloadPreparing: "正在准备原图…",
|
|
388
|
+
imageDownloadFailed: "下载失败,重试",
|
|
328
389
|
imageZoomOut: "缩小",
|
|
329
390
|
imageZoomIn: "放大",
|
|
330
391
|
imageFit: "适合窗口",
|
|
@@ -366,7 +427,9 @@ window.__ModuleLoader__.load({
|
|
|
366
427
|
diagnosticsFailed: "Could not create diagnostics.",
|
|
367
428
|
feedbackOpen: "Report a problem",
|
|
368
429
|
searchTitle: "Search source",
|
|
369
|
-
searchScope: "
|
|
430
|
+
searchScope: "Auto follows the current session model; an explicit choice overrides every model and session.",
|
|
431
|
+
searchAuto: "Auto",
|
|
432
|
+
searchAutoHint: "Codex models use subscription search; other models use DSH",
|
|
370
433
|
searchDsh: "DSH default",
|
|
371
434
|
searchDshHint: "Use DSH's current search service for every model",
|
|
372
435
|
searchCodex: "Codex subscription",
|
|
@@ -428,6 +491,8 @@ window.__ModuleLoader__.load({
|
|
|
428
491
|
quickQuotaOff: "Off",
|
|
429
492
|
quickQuotaPercent: "Percent",
|
|
430
493
|
quickQuotaBar: "Progress bar",
|
|
494
|
+
quickQuotaForecast: "Runway",
|
|
495
|
+
quickQuotaBeta: "Beta",
|
|
431
496
|
contextTitle: "Context window",
|
|
432
497
|
contextStandard: "Standard",
|
|
433
498
|
contextStandardHint: "Use the model catalog default; official agent presets manage context automatically.",
|
|
@@ -439,12 +504,27 @@ window.__ModuleLoader__.load({
|
|
|
439
504
|
contextFixed: "Fixed {value}",
|
|
440
505
|
contextMaximum: "128000–{value}",
|
|
441
506
|
quickQuotaStatus: "Codex quota: {value}% remaining",
|
|
507
|
+
quickQuotaForecastStatus: "Codex quota: {value}% remaining; about {duration} at the current pace",
|
|
508
|
+
quotaForecast: "At current pace {symbol}{duration}",
|
|
509
|
+
runwayDaysHours: "{days}d {hours}h",
|
|
510
|
+
runwayDays: "{days}d",
|
|
511
|
+
runwayHours: "{hours}h",
|
|
512
|
+
runwayMinutes: "{minutes}m",
|
|
442
513
|
speedTitle: "Speed",
|
|
443
514
|
speedStandard: "Standard",
|
|
444
515
|
speedStandardHint: "Standard speed",
|
|
445
516
|
speedFast: "Fast",
|
|
446
517
|
speedFastHint: "1.5x; higher Credits use",
|
|
447
|
-
|
|
518
|
+
verbosityTitle: "Output detail",
|
|
519
|
+
verbosityDefault: "Model default",
|
|
520
|
+
verbosityDefaultHint: "Use the official model catalog recommendation",
|
|
521
|
+
verbosityLow: "Concise",
|
|
522
|
+
verbosityLowHint: "Shorter and more direct",
|
|
523
|
+
verbosityMedium: "Balanced",
|
|
524
|
+
verbosityMediumHint: "Balance completeness and length",
|
|
525
|
+
verbosityHigh: "Detailed",
|
|
526
|
+
verbosityHighHint: "More explanation and structure",
|
|
527
|
+
modelMenuAria: "Model, effort, speed, and output detail",
|
|
448
528
|
modelLabel: "Model",
|
|
449
529
|
effortLabel: "Effort",
|
|
450
530
|
providerDefault: "Default",
|
|
@@ -461,13 +541,16 @@ window.__ModuleLoader__.load({
|
|
|
461
541
|
imageGenerated: "Generated",
|
|
462
542
|
imageFailed: "Generation failed",
|
|
463
543
|
imageLabel: "Generated image",
|
|
464
|
-
imageOpen: "View
|
|
544
|
+
imageOpen: "View image",
|
|
465
545
|
imageOpenNamed: "View {value}",
|
|
466
546
|
imageLoading: "Loading image…",
|
|
467
547
|
imageLoadFailed: "Image failed to load. Click to retry",
|
|
468
548
|
imagePreview: "Image preview",
|
|
549
|
+
imagePreviewShort: "Preview",
|
|
469
550
|
imageClosePreview: "Close preview",
|
|
470
|
-
imageDownload: "Download
|
|
551
|
+
imageDownload: "Download",
|
|
552
|
+
imageDownloadPreparing: "Preparing original…",
|
|
553
|
+
imageDownloadFailed: "Download failed. Retry",
|
|
471
554
|
imageZoomOut: "Zoom out",
|
|
472
555
|
imageZoomIn: "Zoom in",
|
|
473
556
|
imageFit: "Fit to window",
|
|
@@ -492,10 +575,10 @@ window.__ModuleLoader__.load({
|
|
|
492
575
|
.codexSubscriptionNote{font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
|
|
493
576
|
.codexSubscriptionCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);padding:14px 16px;display:flex;flex-direction:column;gap:12px}
|
|
494
577
|
.codexSubscriptionUsageCard{padding:12px 14px;gap:9px}.codexSubscriptionPreferencesCard{padding:12px 14px;gap:10px}.codexSubscriptionPreference{min-height:32px;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.codexSubscriptionPreferenceCopy{display:flex;min-width:0;flex-direction:column;gap:2px}.codexSubscriptionPreferenceLabel{display:flex;align-items:center;gap:6px}
|
|
495
|
-
.codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionQuotaMode{position:relative;display:flex;align-items:center;justify-content:center;min-height:26px;padding:0 9px;border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;cursor:pointer}.codexSubscriptionQuotaMode:has(input:checked){background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:0 0 0 1px var(--dsw-alias-border-l3)}.codexSubscriptionQuotaMode:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexSubscriptionQuotaMode:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionQuotaMode input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
|
|
578
|
+
.codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionQuotaMode{position:relative;display:flex;align-items:center;justify-content:center;min-height:26px;padding:0 9px;border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;cursor:pointer;white-space:nowrap}.codexSubscriptionQuotaMode small{margin-left:3px;font-size:9px;line-height:1;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionQuotaMode:has(input:checked){background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:0 0 0 1px var(--dsw-alias-border-l3)}.codexSubscriptionQuotaMode:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexSubscriptionQuotaMode:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionQuotaMode input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
|
|
496
579
|
.codexSubscriptionContext{display:flex;flex-direction:column;gap:8px}.codexSubscriptionContextHead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.codexSubscriptionContextCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}.codexSubscriptionContextHint{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextTrigger{height:32px;min-width:108px;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;padding:0 10px 0 12px;border:0;border-radius:999px;outline:0;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}.codexSubscriptionContextTrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionContextTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexSubscriptionContextTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.codexSubscriptionContextTrigger svg{color:var(--dsw-alias-label-tertiary);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionContextTrigger[aria-expanded=true] svg{transform:rotate(180deg)}.codexSubscriptionContextModels{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel{min-height:42px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel:last-child{border-bottom:0}.codexSubscriptionContextModelCopy{display:flex;min-width:0;flex-direction:column}.codexSubscriptionContextModelCopy strong{font-size:12px;line-height:18px;font-weight:500}.codexSubscriptionContextModelCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextInput{width:116px}
|
|
497
580
|
.codexSubscriptionSwitch{position:relative;flex:0 0 auto;width:32px;height:18px;padding:0;border:1px solid var(--dsw-alias-border-l3);border-radius:999px;background:var(--dsw-alias-bg-module-platform);cursor:pointer}.codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}.codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary)}.codexSubscriptionSwitchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-bg-layer-1);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(14px)}
|
|
498
|
-
.codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(
|
|
581
|
+
.codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:6px}.codexSubscriptionSearchChoice{display:grid;grid-template-columns:14px minmax(0,1fr);align-items:center;column-gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);padding:9px 10px;text-align:left;cursor:pointer}.codexSubscriptionSearchChoice:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionSearchChoice:has(input:checked){border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.codexSubscriptionSearchChoice:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.codexSubscriptionSearchInput{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-label-primary);cursor:inherit}.codexSubscriptionSearchCopy{display:block;min-width:0;pointer-events:none}.codexSubscriptionSearchCopy strong,.codexSubscriptionSearchCopy span{display:block}.codexSubscriptionSearchCopy strong{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary)}.codexSubscriptionSearchChoice:has(input:checked) strong{color:var(--dsw-alias-label-primary)}.codexSubscriptionSearchCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionDivider{height:1px;background:var(--dsw-alias-border-l2)}
|
|
499
582
|
.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionStatus{display:flex;align-items:center;gap:8px;font-size:14px;line-height:22px;font-weight:500}
|
|
500
583
|
.codexSubscriptionDot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-dimmed)}.codexSubscriptionDot[data-state=connected]{background:var(--dsw-alias-state-success-primary)}.codexSubscriptionDot[data-state=disconnected]{background:var(--dsw-alias-state-error-primary)}
|
|
501
584
|
.codexSubscriptionActions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.codexSubscriptionFlow{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-module-platform)}
|
|
@@ -521,12 +604,13 @@ window.__ModuleLoader__.load({
|
|
|
521
604
|
.codexModelSelectMenu{overflow:visible}
|
|
522
605
|
.codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}.codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}.codexImageToolIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}.codexImageToolIcon::before{content:'';width:8px;height:8px;border:1.5px solid currentColor;border-radius:3px}.codexImageTool[data-state=running] .codexImageToolIcon::before{border-radius:50%;border-right-color:transparent;animation:codexImageSpin 800ms linear infinite}.codexImageTool[data-state=error] .codexImageToolIcon::before{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-primary)}.codexImageToolTitle{font-weight:500}.codexImageToolState{color:var(--dsw-alias-label-tertiary)}.codexImageToolError{margin:0 0 0 24px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}.codexImageToolGallery{margin-left:24px}.codexGeneratedImageFrame{display:flex;align-items:center;justify-content:center;width:min(240px,100%);height:240px;padding:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer}.codexGeneratedImageFrame img{display:block;width:100%;height:100%;object-fit:cover}.codexGeneratedImageRetry{min-height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);cursor:pointer}.codexGeneratedImageModal{width:min(920px,calc(100vw - 32px));max-height:calc(100vh - 32px)}.codexGeneratedImageModalContent{min-height:0;overflow:hidden}.codexGeneratedImageViewer{display:flex;min-width:0;flex-direction:column;gap:12px}.codexGeneratedImageStage{display:grid;place-items:center;min-height:280px;max-height:calc(100vh - 260px);overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-module-platform)}.codexGeneratedImageStage img{display:block;max-width:100%;max-height:calc(100vh - 280px);object-fit:contain;transform-origin:center;transition:transform 120ms ease}.codexGeneratedImageMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.codexGeneratedImageToolbar{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.codexGeneratedImageZoom{display:flex;align-items:center;gap:6px}.codexGeneratedImageZoomValue{min-width:44px;color:var(--dsw-alias-label-secondary);font-size:12px;text-align:center}.codexGeneratedImageDownload{display:inline-flex;align-items:center;gap:6px;min-height:32px;box-sizing:border-box;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;text-decoration:none}.codexGeneratedImageDownload:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexGeneratedImageGuidance{display:flex;flex-direction:column;gap:2px;padding-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}@keyframes codexImageSpin{to{transform:rotate(360deg)}}
|
|
523
606
|
.codexImageBeta{padding:0 5px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:16px}
|
|
607
|
+
.codexImageToolGallery{display:flex;align-items:flex-start;flex-direction:column;gap:8px}
|
|
524
608
|
@container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
|
|
525
609
|
@container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
|
|
526
610
|
@media(max-width:640px){.codexSubscriptionCard{padding:14px}}
|
|
527
611
|
`;
|
|
528
612
|
const IMAGE_STYLE = String.raw`
|
|
529
|
-
.codexGeneratedImageLightbox{position:fixed;inset:0;z-index:1000;display:grid;grid-template-rows:auto minmax(0,1fr)
|
|
613
|
+
.codexGeneratedImageLightbox{position:fixed;inset:0;z-index:1000;display:grid;grid-template-rows:auto minmax(0,1fr);background:var(--dsw-alias-bg-base,#111);color:var(--dsw-alias-label-primary);outline:0}.codexGeneratedImageTopbar{display:flex;align-items:center;justify-content:space-between;gap:20px;min-height:58px;padding:8px 14px;border-bottom:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb,var(--dsw-alias-bg-base,#111) 92%,transparent);backdrop-filter:blur(18px)}.codexGeneratedImageTopbar>div:first-child{display:flex;min-width:0;flex-direction:column}.codexGeneratedImageTopbar strong{overflow:hidden;font-size:13px;font-weight:600;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.codexGeneratedImageTopbar small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:17px}.codexGeneratedImageActions{display:flex;align-items:center;gap:6px}.codexGeneratedImageActions button,.codexGeneratedImageActions a{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:5px;height:32px;padding:0 10px;border:1px solid transparent;border-radius:16px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;text-decoration:none;cursor:pointer}.codexGeneratedImageActions button:hover,.codexGeneratedImageActions a:hover,.codexGeneratedImageActions button.is-active{background:var(--dsw-alias-interactive-bg-hover)}.codexGeneratedImageActions button:focus-visible,.codexGeneratedImageActions a:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexGeneratedImageActions button:disabled{opacity:.4;cursor:default}.codexGeneratedImageActions>span{min-width:38px;color:var(--dsw-alias-label-tertiary);font-size:11px;text-align:center}.codexGeneratedImageClose{font-size:20px!important}.codexGeneratedImageCanvas{position:relative;display:grid;place-items:center;min-height:0;overflow:auto;padding:24px;background:var(--dsw-alias-bg-base,#111)}.codexGeneratedImageSurface{position:relative;display:inline-flex;max-width:calc(100vw - 48px);max-height:calc(100vh - 150px);transform-origin:center;transition:transform 120ms ease}.codexGeneratedImageSurface img{display:block;max-width:100%;max-height:calc(100vh - 150px);border-radius:12px;object-fit:contain}.codexGeneratedImageCanvas.is-annotating .codexGeneratedImageSurface{cursor:crosshair}.codexGeneratedImagePin{position:absolute;display:grid;place-items:center;width:24px;height:24px;padding:0;border:2px solid white;border-radius:50%;background:var(--dsw-alias-label-primary);box-shadow:0 1px 4px rgba(0,0,0,.35);color:var(--dsw-alias-bg-base,#111);font:inherit;font-size:11px;font-weight:700;transform:translate(-50%,-50%);cursor:pointer}.codexGeneratedImagePin.is-active{background:var(--dsw-alias-state-business-primary,#3964fe);color:white}.codexGeneratedImageAnnotateHint{position:absolute;bottom:14px;left:50%;padding:6px 10px;border-radius:14px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-3) 90%,transparent);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-secondary);font-size:11px;transform:translateX(-50%)}@media(max-width:760px){.codexGeneratedImageTopbar{align-items:flex-start;flex-direction:column}.codexGeneratedImageActions{width:100%;overflow-x:auto}.codexGeneratedImageActions>span{display:none}.codexGeneratedImageCanvas{padding:12px}.codexGeneratedImageSurface{max-width:calc(100vw - 24px);max-height:calc(100vh - 180px)}.codexGeneratedImageSurface img{max-height:calc(100vh - 180px)}}
|
|
530
614
|
`;
|
|
531
615
|
const IMAGE_LAYOUT_STYLE = String.raw`
|
|
532
616
|
.codexGeneratedImageWorkspace{display:grid;min-height:0;grid-template-columns:minmax(0,1fr)}
|
|
@@ -566,7 +650,66 @@ window.__ModuleLoader__.load({
|
|
|
566
650
|
return cleaned.toLowerCase().endsWith(".png") ? cleaned : `${cleaned}.png`;
|
|
567
651
|
};
|
|
568
652
|
const imageByteSize = (bytes) => bytes < 1024 * 1024 ? `${Math.max(.1, bytes / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} KB` : `${(bytes / 1024 / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} MB`;
|
|
569
|
-
|
|
653
|
+
const originalRefMatches = (left, right) => left.assetId === right.assetId && left.mediaType === right.mediaType && left.bytes === right.bytes && left.width === right.width && left.height === right.height && left.name === right.name && left.sha256 === right.sha256;
|
|
654
|
+
async function sha256Hex(data) {
|
|
655
|
+
const value = await crypto.subtle.digest("SHA-256", data);
|
|
656
|
+
return [...new Uint8Array(value)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
657
|
+
}
|
|
658
|
+
function decodeBase64Chunk(value) {
|
|
659
|
+
if (typeof value !== "string" || value.length === 0 || value.length > Math.ceil(4194304 / 3) * 4 + 8) throw new Error("Invalid original image chunk");
|
|
660
|
+
let decoded;
|
|
661
|
+
try {
|
|
662
|
+
decoded = atob(value);
|
|
663
|
+
} catch {
|
|
664
|
+
throw new Error("Invalid original image chunk");
|
|
665
|
+
}
|
|
666
|
+
const bytes = new Uint8Array(decoded.length);
|
|
667
|
+
for (let index = 0; index < decoded.length; index += 1) bytes[index] = decoded.charCodeAt(index);
|
|
668
|
+
return bytes;
|
|
669
|
+
}
|
|
670
|
+
async function readOriginalImage(rpc, sessionId, original) {
|
|
671
|
+
const parts = [];
|
|
672
|
+
let total = 0;
|
|
673
|
+
let done = false;
|
|
674
|
+
while (!done) {
|
|
675
|
+
const chunk = unwrap(await rpc.call(CHANNEL, "image/original/chunk", {
|
|
676
|
+
sessionId,
|
|
677
|
+
assetId: original.assetId,
|
|
678
|
+
offset: total
|
|
679
|
+
}));
|
|
680
|
+
const ref = decodeOriginalImageRef(chunk?.ref);
|
|
681
|
+
if (ref === void 0 || !originalRefMatches(ref, original) || chunk.offset !== total || typeof chunk.done !== "boolean") throw new Error("Original image metadata changed");
|
|
682
|
+
const bytes = decodeBase64Chunk(chunk.encoded);
|
|
683
|
+
if (bytes.byteLength === 0 || total + bytes.byteLength > original.bytes) throw new Error("Original image download is incomplete");
|
|
684
|
+
parts.push(bytes);
|
|
685
|
+
total += bytes.byteLength;
|
|
686
|
+
done = chunk.done;
|
|
687
|
+
}
|
|
688
|
+
if (total !== original.bytes) throw new Error("Original image download is incomplete");
|
|
689
|
+
const data = new Uint8Array(total);
|
|
690
|
+
let offset = 0;
|
|
691
|
+
for (const part of parts) {
|
|
692
|
+
data.set(part, offset);
|
|
693
|
+
offset += part.byteLength;
|
|
694
|
+
}
|
|
695
|
+
if (await sha256Hex(data) !== original.sha256) throw new Error("Original image integrity check failed");
|
|
696
|
+
return data;
|
|
697
|
+
}
|
|
698
|
+
function triggerBlobDownload(data, mediaType, filename) {
|
|
699
|
+
const url = URL.createObjectURL(new Blob([data], { type: mediaType }));
|
|
700
|
+
const anchor = document.createElement("a");
|
|
701
|
+
anchor.href = url;
|
|
702
|
+
anchor.download = filename;
|
|
703
|
+
anchor.rel = "noopener";
|
|
704
|
+
document.body.append(anchor);
|
|
705
|
+
try {
|
|
706
|
+
anchor.click();
|
|
707
|
+
} finally {
|
|
708
|
+
anchor.remove();
|
|
709
|
+
URL.revokeObjectURL(url);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
function CodexGeneratedImage({ attachment, original, rpc, sessionId, loadImage, attachForEdit, getImageViewer, t }) {
|
|
570
713
|
const [attempt, setAttempt] = (0, react.useState)(0);
|
|
571
714
|
const [error, setError] = (0, react.useState)(false);
|
|
572
715
|
const [open, setOpen] = (0, react.useState)(false);
|
|
@@ -575,9 +718,9 @@ window.__ModuleLoader__.load({
|
|
|
575
718
|
const [annotationMode, setAnnotationMode] = (0, react.useState)(false);
|
|
576
719
|
const [annotations, setAnnotations] = (0, react.useState)([]);
|
|
577
720
|
const [selectedAnnotation, setSelectedAnnotation] = (0, react.useState)();
|
|
578
|
-
const [prompt, setPrompt] = (0, react.useState)("");
|
|
579
721
|
const [editBusy, setEditBusy] = (0, react.useState)(false);
|
|
580
722
|
const [editError, setEditError] = (0, react.useState)(false);
|
|
723
|
+
const [downloadState, setDownloadState] = (0, react.useState)("idle");
|
|
581
724
|
const triggerRef = (0, react.useRef)(null);
|
|
582
725
|
const dialogRef = (0, react.useRef)(null);
|
|
583
726
|
(0, react.useEffect)(() => {
|
|
@@ -634,7 +777,8 @@ window.__ModuleLoader__.load({
|
|
|
634
777
|
}, [open]);
|
|
635
778
|
const label = attachment.name ?? t("imageLabel");
|
|
636
779
|
const downloadName = imageDownloadName(attachment);
|
|
637
|
-
const
|
|
780
|
+
const previewMeta = attachment.width + " × " + attachment.height + " · " + imageByteSize(attachment.bytes);
|
|
781
|
+
const imageMeta = original === void 0 ? previewMeta : original.width + " × " + original.height + " · " + imageByteSize(original.bytes) + " · " + t("imagePreviewShort") + " " + previewMeta;
|
|
638
782
|
const addAnnotation = (event) => {
|
|
639
783
|
if (!annotationMode || event.target.closest(".codexGeneratedImagePin")) return;
|
|
640
784
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
@@ -653,7 +797,6 @@ window.__ModuleLoader__.load({
|
|
|
653
797
|
setEditError(false);
|
|
654
798
|
try {
|
|
655
799
|
await attachForEdit(src, downloadName, buildImageEditDraft({
|
|
656
|
-
prompt,
|
|
657
800
|
annotations,
|
|
658
801
|
translate: t
|
|
659
802
|
}));
|
|
@@ -664,31 +807,50 @@ window.__ModuleLoader__.load({
|
|
|
664
807
|
setEditBusy(false);
|
|
665
808
|
}
|
|
666
809
|
};
|
|
810
|
+
const downloadOriginal = async () => {
|
|
811
|
+
if (downloadState === "pending" || original === void 0) return;
|
|
812
|
+
setDownloadState("pending");
|
|
813
|
+
try {
|
|
814
|
+
triggerBlobDownload(await readOriginalImage(rpc, sessionId, original), original.mediaType, original.name);
|
|
815
|
+
setDownloadState("idle");
|
|
816
|
+
} catch {
|
|
817
|
+
setDownloadState("failed");
|
|
818
|
+
throw new Error("original image download failed");
|
|
819
|
+
}
|
|
820
|
+
};
|
|
667
821
|
const openImage = () => {
|
|
668
822
|
if (src === void 0) return;
|
|
669
|
-
|
|
823
|
+
const viewer = getImageViewer?.();
|
|
824
|
+
const actions = [];
|
|
825
|
+
actions.push({
|
|
826
|
+
id: "continue-editing",
|
|
827
|
+
label: t("imageEdit"),
|
|
828
|
+
pendingLabel: t("imageEditPreparing"),
|
|
829
|
+
errorLabel: t("imageEditFailed"),
|
|
830
|
+
closeOnSuccess: true,
|
|
831
|
+
onInvoke: ({ annotations: nextAnnotations }) => attachForEdit(src, downloadName, buildImageEditDraft({
|
|
832
|
+
annotations: nextAnnotations,
|
|
833
|
+
translate: t
|
|
834
|
+
}))
|
|
835
|
+
});
|
|
836
|
+
if (viewer?.open?.({
|
|
670
837
|
items: [{
|
|
671
838
|
id: attachment.attachmentId ?? downloadName,
|
|
672
839
|
src,
|
|
673
840
|
name: label,
|
|
674
841
|
width: attachment.width,
|
|
675
842
|
height: attachment.height,
|
|
676
|
-
bytes: attachment.bytes
|
|
843
|
+
bytes: attachment.bytes,
|
|
844
|
+
download: original === void 0 ? void 0 : {
|
|
845
|
+
pendingLabel: t("imageDownloadPreparing"),
|
|
846
|
+
errorLabel: t("imageDownloadFailed"),
|
|
847
|
+
onInvoke: downloadOriginal
|
|
848
|
+
},
|
|
849
|
+
actions
|
|
677
850
|
}],
|
|
678
851
|
opener: triggerRef.current,
|
|
679
852
|
source: "codex-generated",
|
|
680
|
-
annotations: true
|
|
681
|
-
editor: {
|
|
682
|
-
label: t("imageEdit"),
|
|
683
|
-
busyLabel: t("imageEditPreparing"),
|
|
684
|
-
errorLabel: t("imageEditFailed"),
|
|
685
|
-
placeholder: t("imageEditPrompt"),
|
|
686
|
-
onSubmit: ({ prompt: nextPrompt, annotations: nextAnnotations }) => attachForEdit(src, downloadName, buildImageEditDraft({
|
|
687
|
-
prompt: nextPrompt,
|
|
688
|
-
annotations: nextAnnotations,
|
|
689
|
-
translate: t
|
|
690
|
-
}))
|
|
691
|
-
}
|
|
853
|
+
annotations: true
|
|
692
854
|
}) === true) return;
|
|
693
855
|
setZoom(1);
|
|
694
856
|
setOpen(true);
|
|
@@ -706,151 +868,142 @@ window.__ModuleLoader__.load({
|
|
|
706
868
|
"aria-modal": "true",
|
|
707
869
|
"aria-label": t("imagePreview"),
|
|
708
870
|
tabIndex: -1,
|
|
709
|
-
children: [
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
]
|
|
755
|
-
})]
|
|
756
|
-
}),
|
|
757
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
758
|
-
className: "codexGeneratedImageWorkspace " + (annotationMode || annotations.length > 0 ? "has-comments" : ""),
|
|
759
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
|
|
760
|
-
className: "codexGeneratedImageCanvas " + (annotationMode ? "is-annotating" : ""),
|
|
761
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
762
|
-
className: "codexGeneratedImageSurface",
|
|
763
|
-
onClick: addAnnotation,
|
|
764
|
-
style: { transform: "scale(" + zoom + ")" },
|
|
765
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
766
|
-
src,
|
|
767
|
-
alt: label
|
|
768
|
-
}), annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
769
|
-
type: "button",
|
|
770
|
-
className: "codexGeneratedImagePin " + (annotation.id === selectedAnnotation ? "is-active" : ""),
|
|
771
|
-
"aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
|
|
772
|
-
style: {
|
|
773
|
-
left: annotation.x * 100 + "%",
|
|
774
|
-
top: annotation.y * 100 + "%"
|
|
775
|
-
},
|
|
776
|
-
onClick: (event) => {
|
|
777
|
-
event.stopPropagation();
|
|
778
|
-
setSelectedAnnotation(annotation.id);
|
|
779
|
-
},
|
|
780
|
-
children: index + 1
|
|
781
|
-
}, annotation.id))]
|
|
782
|
-
}), annotationMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
783
|
-
className: "codexGeneratedImageAnnotateHint",
|
|
784
|
-
children: t("imageAnnotateHint")
|
|
785
|
-
}) : null]
|
|
786
|
-
}), annotationMode || annotations.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
|
|
787
|
-
className: "codexGeneratedImageComments",
|
|
788
|
-
"aria-label": t("imageAnnotate"),
|
|
789
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("imageAnnotate") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("imageAnnotateHint") })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
790
|
-
className: "codexGeneratedImageCommentList",
|
|
791
|
-
children: annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
792
|
-
className: annotation.id === selectedAnnotation ? "is-active" : "",
|
|
793
|
-
onClick: () => setSelectedAnnotation(annotation.id),
|
|
794
|
-
children: [
|
|
795
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: index + 1 }),
|
|
796
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
797
|
-
value: annotation.note,
|
|
798
|
-
rows: 3,
|
|
799
|
-
"aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
|
|
800
|
-
placeholder: t("imageAnnotationPlaceholder"),
|
|
801
|
-
onFocus: () => setSelectedAnnotation(annotation.id),
|
|
802
|
-
onChange: (event) => {
|
|
803
|
-
const note = event.target.value;
|
|
804
|
-
setAnnotations((value) => value.map((item) => item.id === annotation.id ? {
|
|
805
|
-
...item,
|
|
806
|
-
note
|
|
807
|
-
} : item));
|
|
808
|
-
}
|
|
809
|
-
}),
|
|
810
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
811
|
-
type: "button",
|
|
812
|
-
"aria-label": t("imageRemoveAnnotation"),
|
|
813
|
-
onClick: (event) => {
|
|
814
|
-
event.stopPropagation();
|
|
815
|
-
setAnnotations((value) => value.filter((item) => item.id !== annotation.id));
|
|
816
|
-
if (selectedAnnotation === annotation.id) setSelectedAnnotation(void 0);
|
|
817
|
-
},
|
|
818
|
-
children: "×"
|
|
819
|
-
})
|
|
820
|
-
]
|
|
821
|
-
}, annotation.id))
|
|
822
|
-
})]
|
|
823
|
-
}) : null]
|
|
824
|
-
}),
|
|
825
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
826
|
-
className: "codexGeneratedImageEditDock",
|
|
827
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
828
|
-
className: "codexGeneratedImagePrompt",
|
|
829
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
830
|
-
value: prompt,
|
|
831
|
-
placeholder: t("imageEditPrompt"),
|
|
832
|
-
onChange: (event) => setPrompt(event.target.value),
|
|
833
|
-
onKeyDown: (event) => {
|
|
834
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
835
|
-
event.preventDefault();
|
|
836
|
-
continueEditing();
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
871
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
872
|
+
className: "codexGeneratedImageTopbar",
|
|
873
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: imageMeta })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
874
|
+
className: "codexGeneratedImageActions",
|
|
875
|
+
children: [
|
|
876
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
877
|
+
type: "button",
|
|
878
|
+
className: annotationMode ? "is-active" : "",
|
|
879
|
+
"aria-pressed": annotationMode,
|
|
880
|
+
onClick: () => setAnnotationMode((value) => !value),
|
|
881
|
+
children: t("imageAnnotate")
|
|
882
|
+
}),
|
|
883
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
884
|
+
type: "button",
|
|
885
|
+
"aria-label": t("imageZoomOut"),
|
|
886
|
+
disabled: zoom <= .5,
|
|
887
|
+
onClick: () => setZoom((value) => Math.max(.5, value - .25)),
|
|
888
|
+
children: "−"
|
|
889
|
+
}),
|
|
890
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [Math.round(zoom * 100), "%"] }),
|
|
891
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
892
|
+
type: "button",
|
|
893
|
+
"aria-label": t("imageZoomIn"),
|
|
894
|
+
disabled: zoom >= 3,
|
|
895
|
+
onClick: () => setZoom((value) => Math.min(3, value + .25)),
|
|
896
|
+
children: "+"
|
|
897
|
+
}),
|
|
898
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
899
|
+
type: "button",
|
|
900
|
+
onClick: () => setZoom(1),
|
|
901
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { "aria-hidden": "true" }), t("imageFit")]
|
|
902
|
+
}),
|
|
903
|
+
original === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
904
|
+
href: src,
|
|
905
|
+
download: downloadName,
|
|
906
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { "aria-hidden": "true" }), t("imageDownload")]
|
|
907
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
908
|
+
type: "button",
|
|
909
|
+
disabled: downloadState === "pending",
|
|
910
|
+
onClick: () => {
|
|
911
|
+
downloadOriginal().catch(() => void 0);
|
|
912
|
+
},
|
|
913
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { "aria-hidden": "true" }), downloadState === "pending" ? t("imageDownloadPreparing") : downloadState === "failed" ? t("imageDownloadFailed") : t("imageDownload")]
|
|
914
|
+
}),
|
|
915
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
840
916
|
type: "button",
|
|
841
917
|
disabled: editBusy,
|
|
842
918
|
onClick: () => {
|
|
843
919
|
continueEditing();
|
|
844
920
|
},
|
|
845
|
-
children: editBusy ? t("imageEditPreparing") : t("imageEdit")
|
|
846
|
-
})
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
921
|
+
children: editBusy ? t("imageEditPreparing") : editError ? t("imageEditFailed") : t("imageEdit")
|
|
922
|
+
}),
|
|
923
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
924
|
+
type: "button",
|
|
925
|
+
className: "codexGeneratedImageClose",
|
|
926
|
+
"aria-label": t("imageClosePreview"),
|
|
927
|
+
onClick: close,
|
|
928
|
+
children: "×"
|
|
929
|
+
})
|
|
930
|
+
]
|
|
931
|
+
})]
|
|
932
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
933
|
+
className: "codexGeneratedImageWorkspace " + (annotationMode || annotations.length > 0 ? "has-comments" : ""),
|
|
934
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
|
|
935
|
+
className: "codexGeneratedImageCanvas " + (annotationMode ? "is-annotating" : ""),
|
|
936
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
937
|
+
className: "codexGeneratedImageSurface",
|
|
938
|
+
onClick: addAnnotation,
|
|
939
|
+
style: { transform: "scale(" + zoom + ")" },
|
|
940
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
941
|
+
src,
|
|
942
|
+
alt: label
|
|
943
|
+
}), annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
944
|
+
type: "button",
|
|
945
|
+
className: "codexGeneratedImagePin " + (annotation.id === selectedAnnotation ? "is-active" : ""),
|
|
946
|
+
"aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
|
|
947
|
+
style: {
|
|
948
|
+
left: annotation.x * 100 + "%",
|
|
949
|
+
top: annotation.y * 100 + "%"
|
|
950
|
+
},
|
|
951
|
+
onClick: (event) => {
|
|
952
|
+
event.stopPropagation();
|
|
953
|
+
setSelectedAnnotation(annotation.id);
|
|
954
|
+
},
|
|
955
|
+
children: index + 1
|
|
956
|
+
}, annotation.id))]
|
|
957
|
+
}), annotationMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
958
|
+
className: "codexGeneratedImageAnnotateHint",
|
|
959
|
+
children: t("imageAnnotateHint")
|
|
851
960
|
}) : null]
|
|
852
|
-
})
|
|
853
|
-
|
|
961
|
+
}), annotationMode || annotations.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
|
|
962
|
+
className: "codexGeneratedImageComments",
|
|
963
|
+
"aria-label": t("imageAnnotate"),
|
|
964
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("imageAnnotate") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("imageAnnotateHint") })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
965
|
+
className: "codexGeneratedImageCommentList",
|
|
966
|
+
children: annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
967
|
+
className: annotation.id === selectedAnnotation ? "is-active" : "",
|
|
968
|
+
onClick: () => setSelectedAnnotation(annotation.id),
|
|
969
|
+
children: [
|
|
970
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: index + 1 }),
|
|
971
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
972
|
+
value: annotation.note,
|
|
973
|
+
rows: 3,
|
|
974
|
+
"aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
|
|
975
|
+
placeholder: t("imageAnnotationPlaceholder"),
|
|
976
|
+
onFocus: () => setSelectedAnnotation(annotation.id),
|
|
977
|
+
onChange: (event) => {
|
|
978
|
+
const note = event.target.value;
|
|
979
|
+
setAnnotations((value) => value.map((item) => item.id === annotation.id ? {
|
|
980
|
+
...item,
|
|
981
|
+
note
|
|
982
|
+
} : item));
|
|
983
|
+
},
|
|
984
|
+
onKeyDown: (event) => {
|
|
985
|
+
if (event.key === "Enter" && !event.shiftKey || event.key === "Escape") {
|
|
986
|
+
event.preventDefault();
|
|
987
|
+
event.stopPropagation();
|
|
988
|
+
setSelectedAnnotation(void 0);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}),
|
|
992
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
993
|
+
type: "button",
|
|
994
|
+
"aria-label": t("imageRemoveAnnotation"),
|
|
995
|
+
onClick: (event) => {
|
|
996
|
+
event.stopPropagation();
|
|
997
|
+
setAnnotations((value) => value.filter((item) => item.id !== annotation.id));
|
|
998
|
+
if (selectedAnnotation === annotation.id) setSelectedAnnotation(void 0);
|
|
999
|
+
},
|
|
1000
|
+
children: "×"
|
|
1001
|
+
})
|
|
1002
|
+
]
|
|
1003
|
+
}, annotation.id))
|
|
1004
|
+
})]
|
|
1005
|
+
}) : null]
|
|
1006
|
+
})]
|
|
854
1007
|
}), document.body);
|
|
855
1008
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
856
1009
|
ref: triggerRef,
|
|
@@ -865,13 +1018,14 @@ window.__ModuleLoader__.load({
|
|
|
865
1018
|
})
|
|
866
1019
|
}), lightbox] });
|
|
867
1020
|
}
|
|
868
|
-
function CodexImageToolRow({ block, loadImage, attachForEdit, getImageViewer, t }) {
|
|
1021
|
+
function CodexImageToolRow({ block, sessionId, rpc, loadImage, attachForEdit, getImageViewer, t }) {
|
|
869
1022
|
const settled = block?.kind === "tool-result";
|
|
870
1023
|
const image = settled ? block.content.find((item) => item?.type === "image" && item.attachment !== void 0) : void 0;
|
|
871
1024
|
const failed = settled && block.isError === true;
|
|
872
1025
|
const state = !settled ? "running" : failed ? "error" : "done";
|
|
873
1026
|
const status = !settled ? t("imageGenerating") : failed ? t("imageFailed") : t("imageGenerated");
|
|
874
1027
|
const error = failed ? block.content.find((item) => item?.type === "text" && typeof item.text === "string")?.text : void 0;
|
|
1028
|
+
const original = decodeImagePresentation(block?.meta)?.original;
|
|
875
1029
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
876
1030
|
className: "codexImageTool",
|
|
877
1031
|
"data-state": state,
|
|
@@ -901,6 +1055,9 @@ window.__ModuleLoader__.load({
|
|
|
901
1055
|
className: "codexImageToolGallery",
|
|
902
1056
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexGeneratedImage, {
|
|
903
1057
|
attachment: image.attachment,
|
|
1058
|
+
original,
|
|
1059
|
+
rpc,
|
|
1060
|
+
sessionId,
|
|
904
1061
|
loadImage,
|
|
905
1062
|
attachForEdit,
|
|
906
1063
|
getImageViewer,
|
|
@@ -922,6 +1079,7 @@ window.__ModuleLoader__.load({
|
|
|
922
1079
|
let failedPatch;
|
|
923
1080
|
let generation = 0;
|
|
924
1081
|
let contextModels = [];
|
|
1082
|
+
let verbosityModels = [];
|
|
925
1083
|
const nativeSnapshot = () => scope.getSnapshot();
|
|
926
1084
|
const read = () => {
|
|
927
1085
|
const native = nativeSnapshot();
|
|
@@ -931,10 +1089,12 @@ window.__ModuleLoader__.load({
|
|
|
931
1089
|
quickQuotaMode: normalizeQuickQuotaMode(current.value?.[QUICK_QUOTA_MODE_FIELD], current.value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
932
1090
|
searchProvider: normalizeSearchProvider(current.value?.[SEARCH_PROVIDER_FIELD]),
|
|
933
1091
|
speedMode: normalizeSpeedMode(current.value?.[SPEED_MODE_FIELD]),
|
|
1092
|
+
outputVerbosity: normalizeOutputVerbosity(current.value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
934
1093
|
contextMode: normalizeContextMode(current.value?.[CONTEXT_MODE_FIELD]),
|
|
935
1094
|
customContextWindow: normalizeCustomContextWindow(current.value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
936
1095
|
customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(current.value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
937
1096
|
contextModels,
|
|
1097
|
+
verbosityModels,
|
|
938
1098
|
writable: !updating && current.status === "ready" && current.writable === true,
|
|
939
1099
|
error
|
|
940
1100
|
});
|
|
@@ -952,6 +1112,7 @@ window.__ModuleLoader__.load({
|
|
|
952
1112
|
});
|
|
953
1113
|
const acceptFallback = (value) => {
|
|
954
1114
|
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1115
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
955
1116
|
fallbackStatus = "ready";
|
|
956
1117
|
fallback = {
|
|
957
1118
|
status: "ready",
|
|
@@ -959,6 +1120,7 @@ window.__ModuleLoader__.load({
|
|
|
959
1120
|
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
960
1121
|
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
961
1122
|
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
|
|
1123
|
+
[OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
962
1124
|
[CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
|
|
963
1125
|
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
964
1126
|
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
|
|
@@ -977,8 +1139,10 @@ window.__ModuleLoader__.load({
|
|
|
977
1139
|
try {
|
|
978
1140
|
const value = unwrap(await rpc.call(CHANNEL, "preferences/status", {}));
|
|
979
1141
|
if (current !== generation) return;
|
|
980
|
-
if (nativeSnapshot().status === "ready")
|
|
981
|
-
|
|
1142
|
+
if (nativeSnapshot().status === "ready") {
|
|
1143
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1144
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1145
|
+
} else acceptFallback(value);
|
|
982
1146
|
publish();
|
|
983
1147
|
} catch {
|
|
984
1148
|
if (current !== generation || nativeSnapshot().status === "ready") return;
|
|
@@ -1034,6 +1198,18 @@ window.__ModuleLoader__.load({
|
|
|
1034
1198
|
}
|
|
1035
1199
|
const usePreferenceSnapshot = (preference) => (0, react.useSyncExternalStore)(preference.subscribe, preference.getSnapshot);
|
|
1036
1200
|
const notifyQuickQuota = () => window.dispatchEvent(new Event(QUICK_QUOTA_REFRESH_EVENT));
|
|
1201
|
+
const formatRunway = (seconds, t) => {
|
|
1202
|
+
if (!Number.isFinite(seconds) || seconds <= 0) return void 0;
|
|
1203
|
+
const minutes = Math.max(1, Math.round(seconds / 60));
|
|
1204
|
+
const days = Math.floor(minutes / 1440);
|
|
1205
|
+
const hours = Math.floor(minutes % 1440 / 60);
|
|
1206
|
+
if (days > 0) return hours > 0 ? fill(t("runwayDaysHours"), {
|
|
1207
|
+
days,
|
|
1208
|
+
hours
|
|
1209
|
+
}) : fill(t("runwayDays"), { days });
|
|
1210
|
+
if (hours > 0) return fill(t("runwayHours"), { hours });
|
|
1211
|
+
return fill(t("runwayMinutes"), { minutes });
|
|
1212
|
+
};
|
|
1037
1213
|
function useQuickQuota(rpc, enabled, model) {
|
|
1038
1214
|
const [quota, setQuota] = (0, react.useState)();
|
|
1039
1215
|
(0, react.useEffect)(() => {
|
|
@@ -1109,7 +1285,12 @@ window.__ModuleLoader__.load({
|
|
|
1109
1285
|
children: [
|
|
1110
1286
|
choice("off", t("quickQuotaOff")),
|
|
1111
1287
|
choice(QUICK_QUOTA_MODE_PERCENT, t("quickQuotaPercent")),
|
|
1112
|
-
choice("bar", t("quickQuotaBar"))
|
|
1288
|
+
choice("bar", t("quickQuotaBar")),
|
|
1289
|
+
choice(QUICK_QUOTA_MODE_FORECAST, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1290
|
+
t("quickQuotaForecast"),
|
|
1291
|
+
" ",
|
|
1292
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("quickQuotaBeta") })
|
|
1293
|
+
] }))
|
|
1113
1294
|
]
|
|
1114
1295
|
})]
|
|
1115
1296
|
});
|
|
@@ -1145,7 +1326,11 @@ window.__ModuleLoader__.load({
|
|
|
1145
1326
|
className: "codexSubscriptionSearchChoices",
|
|
1146
1327
|
role: "radiogroup",
|
|
1147
1328
|
"aria-label": t("searchTitle"),
|
|
1148
|
-
children: [
|
|
1329
|
+
children: [
|
|
1330
|
+
choice(SEARCH_PROVIDER_AUTO, t("searchAuto"), t("searchAutoHint")),
|
|
1331
|
+
choice("dsh", t("searchDsh"), t("searchDshHint")),
|
|
1332
|
+
choice(SEARCH_PROVIDER_CODEX, t("searchCodex"), t("searchCodexHint"))
|
|
1333
|
+
]
|
|
1149
1334
|
})]
|
|
1150
1335
|
});
|
|
1151
1336
|
}
|
|
@@ -1310,11 +1495,16 @@ window.__ModuleLoader__.load({
|
|
|
1310
1495
|
const current = (0, react.useSyncExternalStore)((listener) => directory.subscribe(listener), () => directory.getSnapshot()).current;
|
|
1311
1496
|
const codex = current?.provider === "openai-codex";
|
|
1312
1497
|
const quotaEnabled = preferenceSnapshot.status === "ready" && preferenceSnapshot.quickQuotaMode !== "off" && codex;
|
|
1498
|
+
const forecastMode = preferenceSnapshot.quickQuotaMode === QUICK_QUOTA_MODE_FORECAST;
|
|
1313
1499
|
const quota = useQuickQuota(rpc, quotaEnabled, current?.model);
|
|
1314
1500
|
if (!quotaEnabled || quota === void 0) return null;
|
|
1315
1501
|
const value = Math.round(Number(quota.remainingPercent) * 10) / 10;
|
|
1316
1502
|
const display = percent(value);
|
|
1317
|
-
const
|
|
1503
|
+
const duration = quota.forecast?.status === "ready" ? formatRunway(quota.forecast.runwaySeconds, t) : void 0;
|
|
1504
|
+
const label = duration === void 0 ? fill(t("quickQuotaStatus"), { value: display }) : fill(t("quickQuotaForecastStatus"), {
|
|
1505
|
+
value: display,
|
|
1506
|
+
duration
|
|
1507
|
+
});
|
|
1318
1508
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1319
1509
|
className: "codexComposerQuota",
|
|
1320
1510
|
role: "status",
|
|
@@ -1325,7 +1515,7 @@ window.__ModuleLoader__.load({
|
|
|
1325
1515
|
max: 100,
|
|
1326
1516
|
value,
|
|
1327
1517
|
"aria-hidden": "true"
|
|
1328
|
-
}) : `${display}%`
|
|
1518
|
+
}) : forecastMode && duration !== void 0 ? `${display}% · ${quota.forecast.survivesReset ? "≥" : "≈"}${duration}` : `${display}%`
|
|
1329
1519
|
});
|
|
1330
1520
|
}
|
|
1331
1521
|
function CodexModelSelect({ locked, available, directory, load, select, preference, t }) {
|
|
@@ -1363,6 +1553,31 @@ window.__ModuleLoader__.load({
|
|
|
1363
1553
|
const speedSupported = state.current?.provider === "openai-codex" && supportsCodexFastMode(state.current?.model);
|
|
1364
1554
|
const speedWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
1365
1555
|
const fast = speedSupported && preferenceSnapshot.speedMode === "fast";
|
|
1556
|
+
const verbositySupported = state.current?.provider === "openai-codex" && preferenceSnapshot.verbosityModels.includes(state.current?.model);
|
|
1557
|
+
const verbosityWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
1558
|
+
const verbosityItems = [
|
|
1559
|
+
{
|
|
1560
|
+
id: OUTPUT_VERBOSITY_DEFAULT,
|
|
1561
|
+
label: t("verbosityDefault"),
|
|
1562
|
+
description: t("verbosityDefaultHint")
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
id: "low",
|
|
1566
|
+
label: t("verbosityLow"),
|
|
1567
|
+
description: t("verbosityLowHint")
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
id: OUTPUT_VERBOSITY_MEDIUM,
|
|
1571
|
+
label: t("verbosityMedium"),
|
|
1572
|
+
description: t("verbosityMediumHint")
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
id: OUTPUT_VERBOSITY_HIGH,
|
|
1576
|
+
label: t("verbosityHigh"),
|
|
1577
|
+
description: t("verbosityHighHint")
|
|
1578
|
+
}
|
|
1579
|
+
];
|
|
1580
|
+
const verbosityLabel = verbosityItems.find((item) => item.id === preferenceSnapshot.outputVerbosity)?.label ?? t("verbosityDefault");
|
|
1366
1581
|
const busy = state.status === "selecting";
|
|
1367
1582
|
(0, react.useEffect)(() => {
|
|
1368
1583
|
if (available) load();
|
|
@@ -1380,7 +1595,12 @@ window.__ModuleLoader__.load({
|
|
|
1380
1595
|
}, [open]);
|
|
1381
1596
|
(0, react.useEffect)(() => {
|
|
1382
1597
|
if (!speedSupported && pane === "speed") setPane("root");
|
|
1383
|
-
|
|
1598
|
+
if (!verbositySupported && pane === "verbosity") setPane("root");
|
|
1599
|
+
}, [
|
|
1600
|
+
pane,
|
|
1601
|
+
speedSupported,
|
|
1602
|
+
verbositySupported
|
|
1603
|
+
]);
|
|
1384
1604
|
if (!available) return null;
|
|
1385
1605
|
const close = (restoreFocus = false) => {
|
|
1386
1606
|
setOpen(false);
|
|
@@ -1413,6 +1633,10 @@ window.__ModuleLoader__.load({
|
|
|
1413
1633
|
close(true);
|
|
1414
1634
|
preference.set({ [SPEED_MODE_FIELD]: speedMode });
|
|
1415
1635
|
};
|
|
1636
|
+
const chooseVerbosity = (outputVerbosity) => {
|
|
1637
|
+
close(true);
|
|
1638
|
+
preference.set({ [OUTPUT_VERBOSITY_FIELD]: outputVerbosity });
|
|
1639
|
+
};
|
|
1416
1640
|
const option = ({ key, label, description, selected, disabled, onClick }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1417
1641
|
type: "button",
|
|
1418
1642
|
role: "menuitemradio",
|
|
@@ -1545,6 +1769,19 @@ window.__ModuleLoader__.load({
|
|
|
1545
1769
|
onClick: () => chooseSpeed(SPEED_MODE_FAST)
|
|
1546
1770
|
})]
|
|
1547
1771
|
});
|
|
1772
|
+
else if (pane === "verbosity") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1773
|
+
className: "codexModelSelectSubmenu",
|
|
1774
|
+
role: "menu",
|
|
1775
|
+
"aria-label": t("verbosityTitle"),
|
|
1776
|
+
children: verbosityItems.map((item) => option({
|
|
1777
|
+
key: item.id,
|
|
1778
|
+
label: item.label,
|
|
1779
|
+
description: item.description,
|
|
1780
|
+
selected: preferenceSnapshot.outputVerbosity === item.id,
|
|
1781
|
+
disabled: !verbosityWritable,
|
|
1782
|
+
onClick: () => chooseVerbosity(item.id)
|
|
1783
|
+
}))
|
|
1784
|
+
});
|
|
1548
1785
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1549
1786
|
className: "codexModelSelect",
|
|
1550
1787
|
ref: rootRef,
|
|
@@ -1590,6 +1827,7 @@ window.__ModuleLoader__.load({
|
|
|
1590
1827
|
cell("model", t("modelLabel"), modelLabel),
|
|
1591
1828
|
reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
|
|
1592
1829
|
speedSupported && cell("speed", t("speedTitle"), t(fast ? "speedFast" : "speedStandard")),
|
|
1830
|
+
verbositySupported && cell("verbosity", t("verbosityTitle"), verbosityLabel),
|
|
1593
1831
|
submenu
|
|
1594
1832
|
]
|
|
1595
1833
|
}) : null]
|
|
@@ -2183,7 +2421,10 @@ window.__ModuleLoader__.load({
|
|
|
2183
2421
|
}),
|
|
2184
2422
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2185
2423
|
className: "codexSubscriptionLimitMeta",
|
|
2186
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children:
|
|
2424
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window.forecast?.status === "ready" ? fill(t("quotaForecast"), {
|
|
2425
|
+
symbol: window.forecast.survivesReset ? "≥" : "≈",
|
|
2426
|
+
duration: formatRunway(window.forecast.runwaySeconds, t)
|
|
2427
|
+
}) : windowLabel(window.windowSeconds, t) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetTime, {
|
|
2187
2428
|
resetsAt: window.resetsAt,
|
|
2188
2429
|
t
|
|
2189
2430
|
})]
|
|
@@ -2339,43 +2580,50 @@ window.__ModuleLoader__.load({
|
|
|
2339
2580
|
t
|
|
2340
2581
|
})
|
|
2341
2582
|
}, CodexSection));
|
|
2342
|
-
ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
|
|
2343
|
-
name: "conversation.input.right",
|
|
2344
|
-
id: "codex-subscription-quota",
|
|
2345
|
-
order: 15,
|
|
2346
|
-
locale: NS,
|
|
2347
|
-
inject: (sessionId) => ({
|
|
2348
|
-
preference,
|
|
2349
|
-
rpc: connection.rpc,
|
|
2350
|
-
t,
|
|
2351
|
-
directory: ctx.modelDirectories.directoryFor(sessionId).store
|
|
2352
|
-
})
|
|
2353
|
-
}, CodexComposerQuota));
|
|
2354
2583
|
const sessions = ctx.get("sessions");
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2584
|
+
const installDirectorySlots = (scope) => {
|
|
2585
|
+
const modelDirectories = scope.get("modelDirectories");
|
|
2586
|
+
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
2587
|
+
name: "conversation.input.right",
|
|
2588
|
+
id: "codex-subscription-quota",
|
|
2589
|
+
order: 15,
|
|
2590
|
+
locale: NS,
|
|
2591
|
+
inject: (sessionId) => ({
|
|
2592
|
+
preference,
|
|
2593
|
+
rpc: connection.rpc,
|
|
2594
|
+
t,
|
|
2595
|
+
directory: modelDirectories.directoryFor(sessionId).store
|
|
2596
|
+
})
|
|
2597
|
+
}, CodexComposerQuota));
|
|
2598
|
+
scope.slots.inject("conversation.input.model", () => scope.slots.register({
|
|
2599
|
+
name: "conversation.input.model",
|
|
2600
|
+
priority: -10,
|
|
2601
|
+
locale: NS,
|
|
2602
|
+
inject: (sessionId) => {
|
|
2603
|
+
const directory = modelDirectories.directoryFor(sessionId);
|
|
2604
|
+
const available = sessions.subagentAddress(sessionId) === void 0;
|
|
2605
|
+
return {
|
|
2606
|
+
available,
|
|
2607
|
+
directory: directory.store,
|
|
2608
|
+
load: () => {
|
|
2609
|
+
if (available) directory.load();
|
|
2610
|
+
},
|
|
2611
|
+
select: (selection) => available ? directory.select(selection).then(() => true, () => false) : Promise.resolve(false),
|
|
2612
|
+
preference
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
}, CodexModelSelect));
|
|
2616
|
+
};
|
|
2617
|
+
if (ctx.get("remote.session") === void 0) installDirectorySlots(ctx);
|
|
2618
|
+
else ctx.inject(["remote.session"], installDirectorySlots);
|
|
2373
2619
|
const conversation = ctx.get("conversation");
|
|
2374
2620
|
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
2375
2621
|
name: "tool.call.toolview",
|
|
2376
2622
|
key: "codex_image_generate",
|
|
2377
2623
|
locale: NS,
|
|
2378
2624
|
inject: (sessionId) => ({
|
|
2625
|
+
sessionId,
|
|
2626
|
+
rpc: connection.rpc,
|
|
2379
2627
|
t,
|
|
2380
2628
|
loadImage: (attachment) => conversation.resolveImage(sessionId, attachment),
|
|
2381
2629
|
getImageViewer: () => {
|