@oar-sh/oar 0.9.24 → 0.9.26
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/.github/extensions/web-relay/skills/reasoning-stream.mjs +3 -1
- package/CHANGELOG.md +284 -0
- package/README.md +12 -11
- package/package.json +5 -1
- package/server/claude-worker/claude-remote-relay-tool.mjs +15 -0
- package/server/claude-worker/claude-sdk-adapter.mjs +8 -4
- package/server/claude-worker/claude-session-process.mjs +4 -0
- package/server/claude-worker/claude-turn-publisher.mjs +25 -11
- package/server/claude-worker/sdk-message-normalizer.mjs +29 -1
- package/server/copilot-worker/copilot-prompt-context.mjs +2 -1
- package/server/copilot-worker/copilot-sdk-session-process.mjs +11 -9
- package/server/cursor-worker/cursor-turn-runner.mjs +3 -1
- package/server/cursor-worker/sdk-message-normalizer.mjs +13 -0
- package/server/db-schema.mjs +19 -0
- package/server/grok-worker/grok-turn-runner.mjs +3 -1
- package/server/grok-worker/sdk-message-normalizer.mjs +3 -0
- package/server/migrations/0039-media-index.mjs +167 -0
- package/server/migrations/0040-image-session-defaults.mjs +93 -0
- package/server/public/app/api-client.js +58 -0
- package/server/public/app/ask-user-view.js +2 -1
- package/server/public/app/attachments-view.js +66 -9
- package/server/public/app/bootstrap.js +85 -25
- package/server/public/app/chat-actions-menu-state.mjs +1 -0
- package/server/public/app/context-media-tab.js +143 -0
- package/server/public/app/context-usage-view.mjs +2 -2
- package/server/public/app/conversation-view.js +90 -5
- package/server/public/app/image-composer-ui.js +518 -0
- package/server/public/app/image-turn-placeholder.mjs +233 -0
- package/server/public/app/journal-view.js +12 -2
- package/server/public/app/live-activity-cap.mjs +3 -3
- package/server/public/app/markdown-math.mjs +471 -0
- package/server/public/app/media-gallery-model.mjs +202 -0
- package/server/public/app/media-gallery-ui.js +524 -0
- package/server/public/app/media-view.js +79 -0
- package/server/public/app/openai-image-composer.mjs +492 -0
- package/server/public/app/openai-image-cost-ui.js +426 -0
- package/server/public/app/openai-image-spend.mjs +443 -0
- package/server/public/app/plan-usage-view.mjs +38 -6
- package/server/public/app/pwa-install.js +25 -4
- package/server/public/app/relay-error-ctas.mjs +5 -0
- package/server/public/app/relay-prompt-sanitizer.mjs +3 -0
- package/server/public/app/relay-restart-ui.js +2 -2
- package/server/public/app/remote-relays-settings.js +33 -6
- package/server/public/app/router.js +49 -237
- package/server/public/app/session-history-ui.js +2 -0
- package/server/public/app/settings-modal.js +4 -0
- package/server/public/app/settings-tabs.js +10 -1
- package/server/public/app/socket-handlers.js +26 -0
- package/server/public/app/store.js +2 -0
- package/server/public/app/stream-view-preference.mjs +1 -1
- package/server/public/app/tab-strip-fade.mjs +1 -1
- package/server/public/app/thoughts-preference.mjs +1 -1
- package/server/public/app/tmux-inspector-view.js +29 -16
- package/server/public/app/viewer-gallery.mjs +23 -1
- package/server/public/index.html +517 -123
- package/server/relay-tools.md +1 -0
- package/server/repositories/image-conversation-repository.mjs +69 -0
- package/server/repositories/media-repository.mjs +305 -0
- package/server/routes/media-routes.mjs +361 -0
- package/server/routes/messages-routes.mjs +1410 -360
- package/server/routes/relay-board-routes.mjs +46 -1
- package/server/routes/remote-relay-routes.mjs +1 -1
- package/server/routes/sessions-routes.mjs +361 -14
- package/server/server-runtime.mjs +21 -0
- package/server/services/database-file.mjs +6 -4
- package/server/services/generated-image-cleanup-service.mjs +2 -1
- package/server/services/generated-image-files.mjs +110 -0
- package/server/services/image-input-paths.mjs +389 -0
- package/server/services/image-operation-service.mjs +6 -2
- package/server/services/media-extract.mjs +653 -0
- package/server/services/media-index-service.mjs +221 -0
- package/server/services/openai-image-preview-turns.mjs +330 -0
- package/server/services/openai-image-spend-service.mjs +516 -0
- package/server/services/openai-image-stream.mjs +170 -0
- package/server/services/plan-usage-openai-image.mjs +148 -0
- package/server/services/relay-prompt-sanitizer.mjs +7 -0
- package/server/services/relay-restart-queue.mjs +1 -1
- package/server/services/remote-relay-caller-context.mjs +6 -0
- package/server/services/remote-relay-dispatcher.mjs +409 -23
- package/server/services/remote-relay-registry-service.mjs +10 -2
- package/server/services/session-worker-stop-service.mjs +50 -18
- package/server/services/token-usage-service.mjs +15 -0
- package/shared/image-header.mjs +90 -0
- package/shared/math-instructions.mjs +30 -0
- package/shared/openai-image-options.mjs +299 -0
- package/shared/openai-image-presets.mjs +175 -0
- package/shared/openai-image-previews.mjs +40 -0
- package/shared/openai-image-prices.mjs +291 -0
- package/shared/openai-image-spend.mjs +90 -0
- package/shared/remote-relay-contract.mjs +126 -4
- package/shared/worker-runtime/direct-openai-image.mjs +96 -50
- package/server/public/app/math-dollars.mjs +0 -89
package/server/public/index.html
CHANGED
|
@@ -211,18 +211,17 @@
|
|
|
211
211
|
<title>OAR — Open Agent Relay</title>
|
|
212
212
|
<script>document.write('<scr'+'ipt src="'+__APP_BASE+'/socket.io/socket.io.js"><\/scr'+'ipt>');</script>
|
|
213
213
|
<script src="https://cdn.jsdelivr.net/npm/marked@15.0.12/marked.min.js"></script>
|
|
214
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.
|
|
215
|
-
<script src="https://cdn.jsdelivr.net/npm/katex@0.
|
|
216
|
-
<script src="https://cdn.jsdelivr.net/npm/katex@0.
|
|
217
|
-
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/contrib/auto-render.min.js"></script>
|
|
214
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.19.1/dist/katex.min.css" integrity="sha384-WwGtaC6ywCHxA5cstpj/3+xIZvTez8dq2IcBQaXRkenHZ7FVVq1ZROtURwfbtTlG" crossorigin="anonymous">
|
|
215
|
+
<script src="https://cdn.jsdelivr.net/npm/katex@0.19.1/dist/katex.min.js" integrity="sha384-a1WQdjRj162i159OYq041X6I4K8NenkrI09LlPmiHg0YOb7CR+wJOraXwK9abpnE" crossorigin="anonymous"></script>
|
|
216
|
+
<script src="https://cdn.jsdelivr.net/npm/katex@0.19.1/dist/contrib/mhchem.min.js" integrity="sha384-fB8BH//9nBzROkMUsu/Dr35jWHIbnKesUo9rW0hfEgw8mZGnkAyBAjKX9F98OVuo" crossorigin="anonymous"></script>
|
|
218
217
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
|
219
218
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
220
219
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/nginx.min.js"></script>
|
|
221
220
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/powershell.min.js"></script>
|
|
222
221
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/x86asm.min.js"></script>
|
|
223
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.5.0/css/xterm.
|
|
224
|
-
<script src="https://cdn.jsdelivr.net/npm/xterm@5.5.0/lib/xterm.
|
|
225
|
-
<script src="https://cdn.jsdelivr.net/npm/
|
|
222
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.css" integrity="sha384-8Xk9wy/gzEDUKrXtrmCFa2bBuK3BpjpDuL/p0SeKQX19Khl/M+lHOgD/CyYf7efP" crossorigin="anonymous">
|
|
223
|
+
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.js" integrity="sha384-M169f14mRZOXm3hD/v2Ti0ThIT/RnAQagXA9nlE15yHAtrW19gdePJh/HaTzUOe/" crossorigin="anonymous"></script>
|
|
224
|
+
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0.10.0/lib/addon-fit.js" integrity="sha384-iF+jqbuti4XlB64clWgFWYEscb+UnSRv3VgVikGYZu+otNFnSHr7y7NcKfBnGizn" crossorigin="anonymous"></script>
|
|
226
225
|
<script>
|
|
227
226
|
if (window.hljs && typeof window.hljs.registerAliases === 'function') {
|
|
228
227
|
window.hljs.registerAliases(['pwsh', 'ps1'], { languageName: 'powershell' });
|
|
@@ -891,6 +890,8 @@
|
|
|
891
890
|
.inbox-count.is-urgent { background: var(--danger); color: #fff; }
|
|
892
891
|
body.inbox-view-active #input-area { display: none; }
|
|
893
892
|
body.inbox-view-active #pending-question-banner { display: none; }
|
|
893
|
+
body.media-view-active #input-area { display: none; }
|
|
894
|
+
body.media-view-active #pending-question-banner { display: none; }
|
|
894
895
|
.inbox-view { display: grid; gap: calc(7px * var(--ui-scale)); padding: calc(4px * var(--ui-scale)) 0 calc(12px * var(--ui-scale)); }
|
|
895
896
|
.inbox-filter { display: flex; gap: calc(3px * var(--ui-scale)); flex-wrap: wrap; }
|
|
896
897
|
.inbox-filter-option {
|
|
@@ -1837,6 +1838,31 @@
|
|
|
1837
1838
|
/* Two classes: .settings-help, later in this sheet, would grey it out. */
|
|
1838
1839
|
.settings-help.claude-api-field-error { color: var(--danger); }
|
|
1839
1840
|
.settings-help.claude-api-field-error[hidden] { display: none; }
|
|
1841
|
+
/* OpenAI's image cap and presets (openai-image-cost-ui.js). */
|
|
1842
|
+
.settings-help.openai-image-field-error { color: var(--danger); }
|
|
1843
|
+
.settings-help.openai-image-field-error[hidden] { display: none; }
|
|
1844
|
+
#openai-image-cap-input {
|
|
1845
|
+
background: var(--bg);
|
|
1846
|
+
color: var(--text);
|
|
1847
|
+
border: 1px solid var(--border);
|
|
1848
|
+
border-radius: calc(6px * var(--ui-scale));
|
|
1849
|
+
padding: calc(3px * var(--ui-scale)) calc(7px * var(--ui-scale));
|
|
1850
|
+
outline: none;
|
|
1851
|
+
font-size: var(--fs-meta-md);
|
|
1852
|
+
width: min(calc(140px * var(--ui-scale)), 100%);
|
|
1853
|
+
}
|
|
1854
|
+
#openai-image-cap-input[aria-invalid="true"] { border-color: var(--danger); }
|
|
1855
|
+
.openai-image-cap-row { display: flex; flex-wrap: wrap; gap: calc(6px * var(--ui-scale)); align-items: center; }
|
|
1856
|
+
#openai-image-spend-line[data-state="warning"] { color: var(--warn); }
|
|
1857
|
+
#openai-image-spend-line[data-state="error"] { color: var(--danger); }
|
|
1858
|
+
#openai-image-allow-today-btn[hidden],
|
|
1859
|
+
#openai-image-stop-allowing-btn[hidden] { display: none; }
|
|
1860
|
+
.openai-image-presets-list { list-style: none; margin: 0; padding: 0; width: 100%; display: flex; flex-direction: column; gap: calc(4px * var(--ui-scale)); }
|
|
1861
|
+
.openai-image-preset-row { display: flex; align-items: center; gap: calc(6px * var(--ui-scale)); min-width: 0; }
|
|
1862
|
+
.openai-image-preset-text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
|
|
1863
|
+
.openai-image-preset-text strong { font-weight: 600; overflow-wrap: anywhere; }
|
|
1864
|
+
.openai-image-preset-details { color: var(--muted); font-size: var(--fs-meta-sm); overflow-wrap: anywhere; }
|
|
1865
|
+
.openai-image-preset-tag { color: var(--muted); font-size: var(--fs-meta-xs); flex: 0 0 auto; }
|
|
1840
1866
|
/* The native spin buttons of a number field follow the theme: light ones
|
|
1841
1867
|
on a dark field read as a glitch. */
|
|
1842
1868
|
:root:not([data-theme="light"]) input[type="number"] { color-scheme: dark; }
|
|
@@ -1951,6 +1977,8 @@
|
|
|
1951
1977
|
}
|
|
1952
1978
|
.settings-section:first-child .settings-section-title { margin-top: 0; }
|
|
1953
1979
|
.settings-section-title + .settings-row { margin-top: 0; }
|
|
1980
|
+
/* Settings → Appearance: the one line saying where its settings live. */
|
|
1981
|
+
#appearance-browser-note { margin-bottom: calc(8px * var(--ui-scale)); }
|
|
1954
1982
|
/* A row inside a column block: the block's full width; the lead row (the
|
|
1955
1983
|
provider's on/off toggle) keeps a small gap to the fields below. */
|
|
1956
1984
|
.settings-row-full { width: 100%; }
|
|
@@ -2402,6 +2430,9 @@
|
|
|
2402
2430
|
The anchor class comes from JS rather than :has() so positioning works
|
|
2403
2431
|
everywhere the transcript renders. */
|
|
2404
2432
|
pre.has-code-copy { position: relative; }
|
|
2433
|
+
/* The button gets a strip of its own above the first line, so a long line
|
|
2434
|
+
never runs under it. */
|
|
2435
|
+
pre.has-code-copy > code { padding-top: calc(0.72rem + 12px * var(--ui-scale) + 4px); }
|
|
2405
2436
|
.code-copy-btn {
|
|
2406
2437
|
position: absolute;
|
|
2407
2438
|
top: calc(4px * var(--ui-scale));
|
|
@@ -2443,8 +2474,8 @@
|
|
|
2443
2474
|
vertical-align: bottom;
|
|
2444
2475
|
-webkit-overflow-scrolling: touch;
|
|
2445
2476
|
}
|
|
2446
|
-
.
|
|
2447
|
-
|
|
2477
|
+
/* A formula KaTeX could not set is shown as its source, line breaks kept. */
|
|
2478
|
+
.math-source {
|
|
2448
2479
|
white-space: pre-wrap;
|
|
2449
2480
|
}
|
|
2450
2481
|
.msg-bubble code:not(pre code) {
|
|
@@ -2499,6 +2530,27 @@
|
|
|
2499
2530
|
width: 100%; max-width: 100%; box-sizing: border-box;
|
|
2500
2531
|
min-width: 0;
|
|
2501
2532
|
}
|
|
2533
|
+
/* A running image turn in the live bubble (image-turn-placeholder.mjs): the
|
|
2534
|
+
image area keeps the size's aspect ratio from the first second, so a
|
|
2535
|
+
partial arriving does not move the transcript. */
|
|
2536
|
+
.image-turn-placeholder { display: flex; flex-direction: column; gap: calc(4px * var(--ui-scale)); margin: calc(2px * var(--ui-scale)) 0 calc(6px * var(--ui-scale)); }
|
|
2537
|
+
.thinking-bubble:has(> .image-turn-placeholder) > .dots { display: none; }
|
|
2538
|
+
.image-turn-placeholder-meta { display: flex; align-items: baseline; flex-wrap: wrap; gap: calc(6px * var(--ui-scale)); color: var(--text); font-size: var(--fs-meta-md); }
|
|
2539
|
+
.image-turn-placeholder-timer { font-variant-numeric: tabular-nums; color: var(--muted); }
|
|
2540
|
+
.image-turn-placeholder-retry { color: var(--muted); font-style: italic; }
|
|
2541
|
+
.image-turn-placeholder-retry[hidden] { display: none; }
|
|
2542
|
+
.image-turn-placeholder-details { color: var(--muted); font-size: var(--fs-meta-sm); overflow-wrap: anywhere; }
|
|
2543
|
+
.image-turn-placeholder-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: calc(6px * var(--ui-scale)); width: min(100%, calc(360px * var(--ui-scale))); }
|
|
2544
|
+
.image-turn-placeholder-grid:not([data-count="1"]) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
2545
|
+
.image-turn-placeholder-tile {
|
|
2546
|
+
position: relative; overflow: hidden; border-radius: calc(10px * var(--ui-scale));
|
|
2547
|
+
border: 1px solid var(--border); background: var(--bg3);
|
|
2548
|
+
animation: image-turn-pulse 1.8s ease-in-out infinite;
|
|
2549
|
+
}
|
|
2550
|
+
.image-turn-placeholder-tile.has-preview { animation: none; }
|
|
2551
|
+
.image-turn-placeholder-tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
2552
|
+
@keyframes image-turn-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
|
|
2553
|
+
@media (prefers-reduced-motion: reduce) { .image-turn-placeholder-tile { animation: none; } }
|
|
2502
2554
|
/* Sticky inside the scroller: Stop on the live bubble is the only way to
|
|
2503
2555
|
stop a turn, and a long turn must stay stoppable without scrolling back
|
|
2504
2556
|
up. It sticks within its own bubble only, so it never rides over the
|
|
@@ -3315,6 +3367,190 @@
|
|
|
3315
3367
|
border-color: var(--accent);
|
|
3316
3368
|
color: var(--accent);
|
|
3317
3369
|
}
|
|
3370
|
+
/* The media gallery (media-gallery-ui.js): the 🧠 Media tab and the global
|
|
3371
|
+
Media view. A messenger's shared media: square tiles under month
|
|
3372
|
+
headers, 3 columns on a phone; a Files tab as a list. */
|
|
3373
|
+
.media-gallery {
|
|
3374
|
+
display: flex;
|
|
3375
|
+
flex-direction: column;
|
|
3376
|
+
gap: calc(8px * var(--ui-scale));
|
|
3377
|
+
min-width: 0;
|
|
3378
|
+
}
|
|
3379
|
+
.media-gallery[data-scope="global"] {
|
|
3380
|
+
padding: calc(12px * var(--ui-scale));
|
|
3381
|
+
max-width: calc(1100px * var(--ui-scale));
|
|
3382
|
+
margin: 0 auto;
|
|
3383
|
+
width: 100%;
|
|
3384
|
+
box-sizing: border-box;
|
|
3385
|
+
}
|
|
3386
|
+
.media-gallery-tabs,
|
|
3387
|
+
.media-gallery-chips,
|
|
3388
|
+
.context-tab-strip {
|
|
3389
|
+
display: flex;
|
|
3390
|
+
align-items: center;
|
|
3391
|
+
gap: calc(4px * var(--ui-scale));
|
|
3392
|
+
flex-wrap: wrap;
|
|
3393
|
+
}
|
|
3394
|
+
.media-gallery-tab,
|
|
3395
|
+
.media-gallery-chip,
|
|
3396
|
+
.context-tab {
|
|
3397
|
+
flex: 0 0 auto;
|
|
3398
|
+
border: 1px solid var(--border);
|
|
3399
|
+
background: var(--bg2);
|
|
3400
|
+
color: var(--text);
|
|
3401
|
+
border-radius: calc(8px * var(--ui-scale));
|
|
3402
|
+
height: calc(28px * var(--ui-scale));
|
|
3403
|
+
padding: 0 calc(10px * var(--ui-scale));
|
|
3404
|
+
font-size: var(--fs-meta-md);
|
|
3405
|
+
white-space: nowrap;
|
|
3406
|
+
cursor: pointer;
|
|
3407
|
+
}
|
|
3408
|
+
.media-gallery-tab[aria-selected="true"],
|
|
3409
|
+
.media-gallery-chip[aria-pressed="true"],
|
|
3410
|
+
.context-tab[aria-selected="true"] {
|
|
3411
|
+
border-color: var(--accent);
|
|
3412
|
+
color: var(--accent);
|
|
3413
|
+
}
|
|
3414
|
+
.context-tab-count {
|
|
3415
|
+
margin-left: calc(4px * var(--ui-scale));
|
|
3416
|
+
color: var(--muted);
|
|
3417
|
+
}
|
|
3418
|
+
.context-tab-strip {
|
|
3419
|
+
margin-bottom: calc(10px * var(--ui-scale));
|
|
3420
|
+
}
|
|
3421
|
+
.media-gallery-filters {
|
|
3422
|
+
display: flex;
|
|
3423
|
+
flex-wrap: wrap;
|
|
3424
|
+
align-items: center;
|
|
3425
|
+
gap: calc(6px * var(--ui-scale));
|
|
3426
|
+
}
|
|
3427
|
+
.media-gallery-select,
|
|
3428
|
+
.media-gallery-search {
|
|
3429
|
+
height: calc(28px * var(--ui-scale));
|
|
3430
|
+
border: 1px solid var(--border);
|
|
3431
|
+
border-radius: calc(8px * var(--ui-scale));
|
|
3432
|
+
background: var(--bg2);
|
|
3433
|
+
color: var(--text);
|
|
3434
|
+
font-size: var(--fs-meta-md);
|
|
3435
|
+
padding: 0 calc(6px * var(--ui-scale));
|
|
3436
|
+
max-width: 100%;
|
|
3437
|
+
}
|
|
3438
|
+
.media-gallery-select[data-media-filter="session"] {
|
|
3439
|
+
max-width: calc(260px * var(--ui-scale));
|
|
3440
|
+
}
|
|
3441
|
+
.media-gallery-search {
|
|
3442
|
+
flex: 1 1 calc(180px * var(--ui-scale));
|
|
3443
|
+
min-width: 0;
|
|
3444
|
+
}
|
|
3445
|
+
.media-gallery-toggle {
|
|
3446
|
+
display: inline-flex;
|
|
3447
|
+
align-items: center;
|
|
3448
|
+
gap: calc(4px * var(--ui-scale));
|
|
3449
|
+
font-size: var(--fs-meta-md);
|
|
3450
|
+
color: var(--muted);
|
|
3451
|
+
}
|
|
3452
|
+
.media-gallery-status p {
|
|
3453
|
+
margin: calc(4px * var(--ui-scale)) 0;
|
|
3454
|
+
color: var(--muted);
|
|
3455
|
+
font-size: var(--fs-meta-md);
|
|
3456
|
+
}
|
|
3457
|
+
.media-month-label {
|
|
3458
|
+
position: sticky;
|
|
3459
|
+
top: 0;
|
|
3460
|
+
z-index: 1;
|
|
3461
|
+
margin: 0;
|
|
3462
|
+
padding: calc(6px * var(--ui-scale)) calc(2px * var(--ui-scale));
|
|
3463
|
+
background: var(--bg);
|
|
3464
|
+
color: var(--muted);
|
|
3465
|
+
font-size: var(--fs-meta-md);
|
|
3466
|
+
font-weight: 600;
|
|
3467
|
+
}
|
|
3468
|
+
.media-grid {
|
|
3469
|
+
display: grid;
|
|
3470
|
+
grid-template-columns: repeat(auto-fill, minmax(calc(140px * var(--ui-scale)), 1fr));
|
|
3471
|
+
gap: 2px;
|
|
3472
|
+
}
|
|
3473
|
+
.media-tile {
|
|
3474
|
+
position: relative;
|
|
3475
|
+
aspect-ratio: 1;
|
|
3476
|
+
padding: 0;
|
|
3477
|
+
border: 0;
|
|
3478
|
+
background: var(--bg3);
|
|
3479
|
+
overflow: hidden;
|
|
3480
|
+
cursor: pointer;
|
|
3481
|
+
content-visibility: auto;
|
|
3482
|
+
contain-intrinsic-size: calc(140px * var(--ui-scale));
|
|
3483
|
+
}
|
|
3484
|
+
.media-tile img,
|
|
3485
|
+
.media-tile video {
|
|
3486
|
+
width: 100%;
|
|
3487
|
+
height: 100%;
|
|
3488
|
+
object-fit: cover;
|
|
3489
|
+
display: block;
|
|
3490
|
+
pointer-events: none;
|
|
3491
|
+
}
|
|
3492
|
+
.media-tile:focus-visible {
|
|
3493
|
+
outline: 2px solid var(--accent);
|
|
3494
|
+
outline-offset: -2px;
|
|
3495
|
+
}
|
|
3496
|
+
.media-tile-archived img,
|
|
3497
|
+
.media-tile-archived video {
|
|
3498
|
+
opacity: 0.6;
|
|
3499
|
+
}
|
|
3500
|
+
.media-tile-badge,
|
|
3501
|
+
.media-tile-play {
|
|
3502
|
+
position: absolute;
|
|
3503
|
+
font-size: calc(12px * var(--ui-scale));
|
|
3504
|
+
line-height: 1;
|
|
3505
|
+
padding: calc(3px * var(--ui-scale)) calc(4px * var(--ui-scale));
|
|
3506
|
+
border-radius: calc(6px * var(--ui-scale));
|
|
3507
|
+
background: rgba(0, 0, 0, 0.55);
|
|
3508
|
+
color: #fff;
|
|
3509
|
+
}
|
|
3510
|
+
.media-tile-badge { right: calc(4px * var(--ui-scale)); bottom: calc(4px * var(--ui-scale)); }
|
|
3511
|
+
.media-tile-play { left: calc(4px * var(--ui-scale)); bottom: calc(4px * var(--ui-scale)); }
|
|
3512
|
+
.media-file-list {
|
|
3513
|
+
display: flex;
|
|
3514
|
+
flex-direction: column;
|
|
3515
|
+
}
|
|
3516
|
+
.media-file-row {
|
|
3517
|
+
display: flex;
|
|
3518
|
+
align-items: center;
|
|
3519
|
+
gap: calc(10px * var(--ui-scale));
|
|
3520
|
+
padding: calc(8px * var(--ui-scale)) calc(4px * var(--ui-scale));
|
|
3521
|
+
border: 0;
|
|
3522
|
+
border-bottom: 1px solid var(--border);
|
|
3523
|
+
background: transparent;
|
|
3524
|
+
color: var(--text);
|
|
3525
|
+
text-align: left;
|
|
3526
|
+
cursor: pointer;
|
|
3527
|
+
}
|
|
3528
|
+
.media-file-icon { font-size: calc(22px * var(--ui-scale)); }
|
|
3529
|
+
.media-file-text { display: flex; flex-direction: column; min-width: 0; }
|
|
3530
|
+
.media-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3531
|
+
.media-file-meta { color: var(--muted); font-size: var(--fs-meta-md); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3532
|
+
.media-gallery-more {
|
|
3533
|
+
align-self: center;
|
|
3534
|
+
border: 1px solid var(--border);
|
|
3535
|
+
background: var(--bg2);
|
|
3536
|
+
color: var(--text);
|
|
3537
|
+
border-radius: calc(8px * var(--ui-scale));
|
|
3538
|
+
padding: calc(4px * var(--ui-scale)) calc(12px * var(--ui-scale));
|
|
3539
|
+
cursor: pointer;
|
|
3540
|
+
}
|
|
3541
|
+
.media-gallery-sentinel { height: 1px; }
|
|
3542
|
+
@media (max-width: 680px) {
|
|
3543
|
+
.media-grid { grid-template-columns: repeat(3, 1fr); }
|
|
3544
|
+
.media-gallery[data-scope="global"] { padding: calc(8px * var(--ui-scale)) calc(4px * var(--ui-scale)); }
|
|
3545
|
+
.media-gallery-select[data-media-filter="session"] { max-width: 100%; flex: 1 1 100%; }
|
|
3546
|
+
.media-gallery-tabs,
|
|
3547
|
+
.media-gallery-chips,
|
|
3548
|
+
.context-tab-strip {
|
|
3549
|
+
flex-wrap: nowrap;
|
|
3550
|
+
overflow-x: auto;
|
|
3551
|
+
scrollbar-width: none;
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3318
3554
|
.plan-usage-card-titles {
|
|
3319
3555
|
display: flex;
|
|
3320
3556
|
flex-direction: column;
|
|
@@ -3411,6 +3647,17 @@
|
|
|
3411
3647
|
background: var(--bg3);
|
|
3412
3648
|
}
|
|
3413
3649
|
.plan-usage-meter-secondary .plan-usage-bar { height: calc(6px * var(--ui-scale)); border-radius: calc(3px * var(--ui-scale)); }
|
|
3650
|
+
/* A bar with a mark on it (the OpenAI images card's 80 % warning line). */
|
|
3651
|
+
.plan-usage-bar-marked { position: relative; }
|
|
3652
|
+
.plan-usage-bar-mark {
|
|
3653
|
+
position: absolute;
|
|
3654
|
+
top: 0;
|
|
3655
|
+
bottom: 0;
|
|
3656
|
+
width: 2px;
|
|
3657
|
+
margin-left: -1px;
|
|
3658
|
+
background: var(--text);
|
|
3659
|
+
opacity: 0.55;
|
|
3660
|
+
}
|
|
3414
3661
|
.plan-usage-bar-fill {
|
|
3415
3662
|
display: block;
|
|
3416
3663
|
height: 100%;
|
|
@@ -4294,7 +4541,12 @@
|
|
|
4294
4541
|
#mode-select,
|
|
4295
4542
|
#model-select,
|
|
4296
4543
|
#reasoning-effort-select,
|
|
4297
|
-
#context-tier-select
|
|
4544
|
+
#context-tier-select,
|
|
4545
|
+
#image-size-custom-input,
|
|
4546
|
+
#image-preset-select,
|
|
4547
|
+
#image-count-select,
|
|
4548
|
+
#image-format-select,
|
|
4549
|
+
#image-background-select {
|
|
4298
4550
|
background: var(--bg3); border: 1px solid var(--border); color: var(--text);
|
|
4299
4551
|
border-radius: calc(8px * var(--ui-scale)); height: calc(30px * var(--ui-scale)); padding: 0 calc(8px * var(--ui-scale)); font-size: var(--fs-core-control);
|
|
4300
4552
|
width: 100%; min-width: 0; outline: none;
|
|
@@ -4302,7 +4554,64 @@
|
|
|
4302
4554
|
#mode-select:focus,
|
|
4303
4555
|
#model-select:focus,
|
|
4304
4556
|
#reasoning-effort-select:focus,
|
|
4305
|
-
#context-tier-select:focus
|
|
4557
|
+
#context-tier-select:focus,
|
|
4558
|
+
#image-size-custom-input:focus,
|
|
4559
|
+
#image-preset-select:focus,
|
|
4560
|
+
#image-count-select:focus,
|
|
4561
|
+
#image-format-select:focus,
|
|
4562
|
+
#image-background-select:focus { border-color: var(--accent); }
|
|
4563
|
+
/* An image model's custom W×H under the Size select, and Count, Format and
|
|
4564
|
+
Background side by side: three narrow selects fit the 340px popover and
|
|
4565
|
+
the phone's bottom sheet alike. */
|
|
4566
|
+
#image-size-custom-input { box-sizing: border-box; font-family: var(--mono, monospace); }
|
|
4567
|
+
/* No iOS focus zoom (see #conv-filter-input). */
|
|
4568
|
+
@media (pointer: coarse), (max-width: 680px) {
|
|
4569
|
+
#image-size-custom-input { font-size: max(16px, 1rem); }
|
|
4570
|
+
}
|
|
4571
|
+
#image-size-custom-input[aria-invalid="true"] { border-color: var(--danger); }
|
|
4572
|
+
.image-size-custom-row { display: flex; flex-direction: column; gap: calc(3px * var(--ui-scale)); margin-top: calc(4px * var(--ui-scale)); }
|
|
4573
|
+
.image-size-custom-row[hidden],
|
|
4574
|
+
.image-size-custom-error[hidden],
|
|
4575
|
+
.composer-settings-image-row[hidden],
|
|
4576
|
+
.composer-settings-image-row .composer-settings-field[hidden] { display: none; }
|
|
4577
|
+
.image-size-custom-error { color: var(--danger); font-size: var(--fs-meta-sm); overflow-wrap: anywhere; }
|
|
4578
|
+
.composer-settings-image-row { display: flex; gap: calc(6px * var(--ui-scale)); min-width: 0; }
|
|
4579
|
+
/* An image model's Preset select with "Save as preset…" beside it, and
|
|
4580
|
+
what a pick skipped or a save answered under them. */
|
|
4581
|
+
#image-preset-field[hidden],
|
|
4582
|
+
.image-preset-note[hidden] { display: none; }
|
|
4583
|
+
.image-preset-row { display: flex; gap: calc(6px * var(--ui-scale)); min-width: 0; align-items: center; }
|
|
4584
|
+
.image-preset-row #image-preset-select { flex: 1 1 auto; }
|
|
4585
|
+
.image-preset-save-btn {
|
|
4586
|
+
flex: 0 0 auto;
|
|
4587
|
+
background: var(--bg3); border: 1px solid var(--border); color: var(--text);
|
|
4588
|
+
border-radius: calc(8px * var(--ui-scale)); height: calc(30px * var(--ui-scale)); padding: 0 calc(8px * var(--ui-scale));
|
|
4589
|
+
font-size: var(--fs-core-control); cursor: pointer; white-space: nowrap;
|
|
4590
|
+
}
|
|
4591
|
+
.image-preset-save-btn:hover { border-color: var(--accent); }
|
|
4592
|
+
.image-preset-save-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
4593
|
+
.image-preset-note { color: var(--muted); font-size: var(--fs-meta-sm); overflow-wrap: anywhere; }
|
|
4594
|
+
.image-preset-note[data-state="error"] { color: var(--danger); }
|
|
4595
|
+
/* Today's OpenAI image spend in an image chat: amber from the warning
|
|
4596
|
+
mark, red once the cap stops image turns. */
|
|
4597
|
+
#openai-image-spend-banner {
|
|
4598
|
+
background: var(--bg2);
|
|
4599
|
+
background: color-mix(in srgb, var(--warn) 14%, var(--bg2));
|
|
4600
|
+
border: 1px solid var(--warn);
|
|
4601
|
+
color: var(--warn);
|
|
4602
|
+
border-radius: calc(8px * var(--ui-scale));
|
|
4603
|
+
padding: calc(3px * var(--ui-scale)) calc(8px * var(--ui-scale));
|
|
4604
|
+
margin-bottom: calc(5px * var(--ui-scale));
|
|
4605
|
+
font-size: var(--fs-meta-sm);
|
|
4606
|
+
overflow-wrap: anywhere;
|
|
4607
|
+
}
|
|
4608
|
+
#openai-image-spend-banner[hidden] { display: none; }
|
|
4609
|
+
#openai-image-spend-banner[data-kind="reached"] {
|
|
4610
|
+
background: color-mix(in srgb, var(--danger) 14%, var(--bg2));
|
|
4611
|
+
border-color: var(--danger);
|
|
4612
|
+
color: var(--danger);
|
|
4613
|
+
}
|
|
4614
|
+
.composer-settings-image-row .composer-settings-field { flex: 1 1 0; }
|
|
4306
4615
|
/* Live background-task fold above the composer. The summary reuses the
|
|
4307
4616
|
relay tones so its running state matches the sidebar dot / burger bars. */
|
|
4308
4617
|
#background-tasks-panel {
|
|
@@ -4761,8 +5070,7 @@
|
|
|
4761
5070
|
background: var(--bg); color: var(--text); border: 1px solid var(--border);
|
|
4762
5071
|
border-radius: calc(6px * var(--ui-scale)); padding: calc(2px * var(--ui-scale)) calc(4px * var(--ui-scale)); font-size: var(--fs-meta-sm);
|
|
4763
5072
|
}
|
|
4764
|
-
|
|
4765
|
-
.remote-relays-self-name { font-family: var(--mono, monospace); color: var(--text); }
|
|
5073
|
+
#settings-panel-relays #pwa-app-name-input,
|
|
4766
5074
|
#remote-relays-public-url-input,
|
|
4767
5075
|
#remote-relays-add-url-input,
|
|
4768
5076
|
#remote-relays-add-token-input {
|
|
@@ -6790,6 +7098,10 @@
|
|
|
6790
7098
|
/* CWD-pick mode is launched from the summary / new-chat modals (z 12050),
|
|
6791
7099
|
so the browser must stack above them; #relay-toast stays on top at 12600. */
|
|
6792
7100
|
#repo-browser-modal.cwd-pick-mode { z-index: 12400; }
|
|
7101
|
+
/* A picture opened from the 🧠 Media tab shows above that modal, and its
|
|
7102
|
+
annotate editor above the picture. */
|
|
7103
|
+
#file-preview-modal.over-summary { z-index: 12200; }
|
|
7104
|
+
body:has(#file-preview-modal.over-summary) #image-annotate-modal { z-index: 12300; }
|
|
6793
7105
|
.repo-cwd-pick-bar {
|
|
6794
7106
|
display: flex;
|
|
6795
7107
|
align-items: center;
|
|
@@ -7872,19 +8184,22 @@
|
|
|
7872
8184
|
width is the scroll padding too, so a tab scrolled into view (the
|
|
7873
8185
|
selected one, a focused one) clears it. */
|
|
7874
8186
|
.settings-tab-strip,
|
|
7875
|
-
.plan-usage-tab-strip
|
|
8187
|
+
.plan-usage-tab-strip,
|
|
8188
|
+
.context-tab-strip,
|
|
8189
|
+
.media-gallery-tabs,
|
|
8190
|
+
.media-gallery-chips {
|
|
7876
8191
|
--tab-strip-fade: calc(44px * var(--ui-scale));
|
|
7877
8192
|
scroll-padding-inline: var(--tab-strip-fade);
|
|
7878
8193
|
}
|
|
7879
|
-
:is(.settings-tab-strip, .plan-usage-tab-strip)[data-fade="right"] {
|
|
8194
|
+
:is(.settings-tab-strip, .plan-usage-tab-strip, .context-tab-strip, .media-gallery-tabs, .media-gallery-chips)[data-fade="right"] {
|
|
7880
8195
|
-webkit-mask-image: linear-gradient(to left, transparent, #000 var(--tab-strip-fade));
|
|
7881
8196
|
mask-image: linear-gradient(to left, transparent, #000 var(--tab-strip-fade));
|
|
7882
8197
|
}
|
|
7883
|
-
:is(.settings-tab-strip, .plan-usage-tab-strip)[data-fade="both"] {
|
|
8198
|
+
:is(.settings-tab-strip, .plan-usage-tab-strip, .context-tab-strip, .media-gallery-tabs, .media-gallery-chips)[data-fade="both"] {
|
|
7884
8199
|
-webkit-mask-image: linear-gradient(to right, transparent, #000 var(--tab-strip-fade), #000 calc(100% - var(--tab-strip-fade)), transparent);
|
|
7885
8200
|
mask-image: linear-gradient(to right, transparent, #000 var(--tab-strip-fade), #000 calc(100% - var(--tab-strip-fade)), transparent);
|
|
7886
8201
|
}
|
|
7887
|
-
:is(.settings-tab-strip, .plan-usage-tab-strip)[data-fade="left"] {
|
|
8202
|
+
:is(.settings-tab-strip, .plan-usage-tab-strip, .context-tab-strip, .media-gallery-tabs, .media-gallery-chips)[data-fade="left"] {
|
|
7888
8203
|
-webkit-mask-image: linear-gradient(to right, transparent, #000 var(--tab-strip-fade));
|
|
7889
8204
|
mask-image: linear-gradient(to right, transparent, #000 var(--tab-strip-fade));
|
|
7890
8205
|
}
|
|
@@ -8266,6 +8581,7 @@
|
|
|
8266
8581
|
<button id="chat-menu-watching" class="chat-actions-menu-item chat-menu-meta-chip" type="button" role="menuitem" hidden>👁 Watching sessions…</button>
|
|
8267
8582
|
<button id="chat-menu-schedules" class="chat-actions-menu-item chat-menu-meta-chip" type="button" role="menuitem" hidden>⏰ Schedules…</button>
|
|
8268
8583
|
<button id="chat-menu-origin" class="chat-actions-menu-item chat-menu-meta-chip" type="button" role="menuitem" hidden>↗ Started by an agent</button>
|
|
8584
|
+
<div id="chat-menu-image-cost" class="chat-actions-menu-meta" data-testid="chat-menu-image-cost" hidden><span id="chat-menu-image-cost-value" class="chat-actions-menu-meta-secondary">OpenAI images: …</span></div>
|
|
8269
8585
|
<button id="chat-menu-edit-title" class="chat-actions-menu-item" type="button" role="menuitem">✍️ Edit conversation title</button>
|
|
8270
8586
|
<button id="chat-menu-questions" class="chat-actions-menu-item chat-menu-twin" type="button" role="menuitem" hidden>📓 Questions</button>
|
|
8271
8587
|
<button id="chat-menu-pins" class="chat-actions-menu-item chat-menu-twin" type="button" role="menuitem" hidden>📍 Pinned messages</button>
|
|
@@ -8287,7 +8603,8 @@
|
|
|
8287
8603
|
<button id="chat-menu-change-cwd" class="chat-actions-menu-item" type="button" role="menuitem">🗂️ Change CWD</button>
|
|
8288
8604
|
<button id="chat-menu-git-changes" class="chat-actions-menu-item" type="button" role="menuitem">🌿 Git changes</button>
|
|
8289
8605
|
<button id="chat-menu-open-cloud-session" class="chat-actions-menu-item" type="button" role="menuitem" hidden>☁️ Open on claude.ai</button>
|
|
8290
|
-
<button id="chat-menu-
|
|
8606
|
+
<button id="chat-menu-media" class="chat-actions-menu-item" type="button" role="menuitem">🖼️ Media</button>
|
|
8607
|
+
<button id="chat-menu-settings" class="chat-actions-menu-item" type="button" role="menuitem">⚙️ Settings</button>
|
|
8291
8608
|
<button id="chat-menu-about" class="chat-actions-menu-item" type="button" role="menuitem">ℹ️ About OAR</button>
|
|
8292
8609
|
<button id="chat-menu-restart-relay" class="chat-actions-menu-item" type="button" role="menuitem">🌄 Restart web relay</button>
|
|
8293
8610
|
<button id="chat-menu-suspend-host" class="chat-actions-menu-item" type="button" role="menuitem" onclick="openSuspendHostConfirmation()">💤 Suspend host</button>
|
|
@@ -8310,6 +8627,8 @@
|
|
|
8310
8627
|
<div id="share-preview-banner" role="note"></div>
|
|
8311
8628
|
<div id="model-banner"></div>
|
|
8312
8629
|
<div id="usage-limit-banner" role="status" aria-live="polite" hidden></div>
|
|
8630
|
+
<!-- Today's OpenAI image spend in an image chat (openai-image-cost-ui.js). -->
|
|
8631
|
+
<div id="openai-image-spend-banner" data-testid="openai-image-spend-banner" role="status" aria-live="polite" hidden></div>
|
|
8313
8632
|
<div id="cloud-session-line" aria-label="Cloud session" hidden></div>
|
|
8314
8633
|
<div id="model-metadata-blocker" aria-live="polite">
|
|
8315
8634
|
<span id="model-metadata-blocker-text">Model metadata is unavailable. Refresh to choose a model and reasoning effort.</span>
|
|
@@ -8367,6 +8686,15 @@
|
|
|
8367
8686
|
</select>
|
|
8368
8687
|
<div id="model-lock-note" hidden></div>
|
|
8369
8688
|
</div>
|
|
8689
|
+
<!-- An image model's presets (image-composer-ui.js). -->
|
|
8690
|
+
<div id="image-preset-field" class="composer-settings-field" data-field="image-preset" hidden>
|
|
8691
|
+
<label class="composer-settings-field-label" for="image-preset-select">Preset</label>
|
|
8692
|
+
<div class="image-preset-row">
|
|
8693
|
+
<select id="image-preset-select" data-testid="image-preset-select" title="Image preset"><option value="">None</option></select>
|
|
8694
|
+
<button id="image-preset-save-btn" data-testid="image-preset-save" type="button" class="image-preset-save-btn" title="Save the image options below as a preset">Save as preset…</button>
|
|
8695
|
+
</div>
|
|
8696
|
+
<div id="image-preset-note" data-testid="image-preset-note" class="image-preset-note" role="status" aria-live="polite" hidden></div>
|
|
8697
|
+
</div>
|
|
8370
8698
|
<div class="composer-settings-field" data-field="effort">
|
|
8371
8699
|
<label id="reasoning-effort-label" class="composer-settings-field-label" for="reasoning-effort-select">Effort</label>
|
|
8372
8700
|
<select id="reasoning-effort-select" title="Reasoning effort" disabled>
|
|
@@ -8378,6 +8706,26 @@
|
|
|
8378
8706
|
<select id="context-tier-select" title="Context window">
|
|
8379
8707
|
<option value="default">—</option>
|
|
8380
8708
|
</select>
|
|
8709
|
+
<!-- An image model's "Custom…" size (image-composer-ui.js). -->
|
|
8710
|
+
<div id="image-size-custom-row" class="image-size-custom-row" hidden>
|
|
8711
|
+
<input id="image-size-custom-input" type="text" inputmode="text" autocomplete="off" autocapitalize="off" spellcheck="false" placeholder="2048x1152" aria-label="Custom image size, width x height" aria-describedby="image-size-custom-error">
|
|
8712
|
+
<div id="image-size-custom-error" class="image-size-custom-error" role="alert" hidden></div>
|
|
8713
|
+
</div>
|
|
8714
|
+
</div>
|
|
8715
|
+
<!-- An image model's Count, Format and Background (image-composer-ui.js). -->
|
|
8716
|
+
<div id="image-options-row" class="composer-settings-image-row" hidden>
|
|
8717
|
+
<div class="composer-settings-field" data-field="image-count">
|
|
8718
|
+
<label class="composer-settings-field-label" for="image-count-select">Count</label>
|
|
8719
|
+
<select id="image-count-select" title="Images per turn"></select>
|
|
8720
|
+
</div>
|
|
8721
|
+
<div class="composer-settings-field" data-field="image-format">
|
|
8722
|
+
<label class="composer-settings-field-label" for="image-format-select">Format</label>
|
|
8723
|
+
<select id="image-format-select" title="Image format"></select>
|
|
8724
|
+
</div>
|
|
8725
|
+
<div class="composer-settings-field" data-field="image-background">
|
|
8726
|
+
<label class="composer-settings-field-label" for="image-background-select">Background</label>
|
|
8727
|
+
<select id="image-background-select" title="Image background"></select>
|
|
8728
|
+
</div>
|
|
8381
8729
|
</div>
|
|
8382
8730
|
<!-- Subscription | API key in a Claude chat (claude-billing-toggle-ui.js). -->
|
|
8383
8731
|
<div id="claude-billing-toggle" class="claude-billing-toggle composer-settings-field" data-field="billing" hidden></div>
|
|
@@ -8499,6 +8847,16 @@
|
|
|
8499
8847
|
tabindex="0"
|
|
8500
8848
|
data-settings-tab="general"
|
|
8501
8849
|
>General</button>
|
|
8850
|
+
<button
|
|
8851
|
+
id="settings-tab-appearance"
|
|
8852
|
+
class="settings-tab"
|
|
8853
|
+
type="button"
|
|
8854
|
+
role="tab"
|
|
8855
|
+
aria-selected="false"
|
|
8856
|
+
aria-controls="settings-panel-appearance"
|
|
8857
|
+
tabindex="-1"
|
|
8858
|
+
data-settings-tab="appearance"
|
|
8859
|
+
>Appearance</button>
|
|
8502
8860
|
<button
|
|
8503
8861
|
id="settings-tab-providers"
|
|
8504
8862
|
class="settings-tab"
|
|
@@ -8569,68 +8927,6 @@
|
|
|
8569
8927
|
aria-labelledby="settings-tab-general"
|
|
8570
8928
|
data-settings-panel="general"
|
|
8571
8929
|
>
|
|
8572
|
-
<section class="settings-section" id="settings-section-appearance" aria-labelledby="settings-section-appearance-title">
|
|
8573
|
-
<h3 class="settings-section-title" id="settings-section-appearance-title">Appearance</h3>
|
|
8574
|
-
<div class="settings-row">
|
|
8575
|
-
<label for="theme-select">Theme</label>
|
|
8576
|
-
<select id="theme-select" onchange="updateTheme(this.value)">
|
|
8577
|
-
<option value="dark">Dark</option>
|
|
8578
|
-
<option value="light">Light</option>
|
|
8579
|
-
</select>
|
|
8580
|
-
</div>
|
|
8581
|
-
<div class="settings-row" style="margin-bottom: 0;">
|
|
8582
|
-
<label for="font-scale-select">Text scaling</label>
|
|
8583
|
-
<select id="font-scale-select" onchange="updateFontScaleFromSelect(this.value)" aria-label="Text scaling"></select>
|
|
8584
|
-
</div>
|
|
8585
|
-
<div class="settings-row settings-gap">
|
|
8586
|
-
<label for="thoughts-expanded-toggle">Expand thoughts while an agent works</label>
|
|
8587
|
-
<input
|
|
8588
|
-
id="thoughts-expanded-toggle"
|
|
8589
|
-
type="checkbox"
|
|
8590
|
-
onchange="updateThoughtsExpandedSetting(this.checked)"
|
|
8591
|
-
aria-label="Expand thoughts while an agent works"
|
|
8592
|
-
checked
|
|
8593
|
-
>
|
|
8594
|
-
</div>
|
|
8595
|
-
<div class="settings-help settings-gap-xs">Open thoughts in the live turn, in sub-agent bubbles and in the sub-agent viewer. Saved in this browser.</div>
|
|
8596
|
-
<div class="settings-row settings-row-column settings-gap">
|
|
8597
|
-
<label for="live-activity-cap-slider">Tool lines shown while an agent works <span id="live-activity-cap-value">50 lines</span></label>
|
|
8598
|
-
<input
|
|
8599
|
-
id="live-activity-cap-slider"
|
|
8600
|
-
type="range"
|
|
8601
|
-
min="10"
|
|
8602
|
-
max="510"
|
|
8603
|
-
step="10"
|
|
8604
|
-
value="50"
|
|
8605
|
-
aria-label="Tool lines shown while an agent works"
|
|
8606
|
-
aria-valuetext="50 lines"
|
|
8607
|
-
oninput="previewLiveActivityCap(this.value)"
|
|
8608
|
-
onchange="updateLiveActivityCap(this.value)"
|
|
8609
|
-
>
|
|
8610
|
-
</div>
|
|
8611
|
-
<div class="settings-help settings-gap-xs">Per agent: the main agent and each sub-agent keep this many of their newest tool lines in the live bubble. The relay keeps up to 500 per agent. Saved in this browser.</div>
|
|
8612
|
-
<div class="settings-row settings-gap">
|
|
8613
|
-
<label for="stream-view-toggle">Stream view: thoughts, tool calls and the reply in order</label>
|
|
8614
|
-
<input
|
|
8615
|
-
id="stream-view-toggle"
|
|
8616
|
-
type="checkbox"
|
|
8617
|
-
onchange="updateStreamViewSetting(this.checked)"
|
|
8618
|
-
aria-label="Stream view: thoughts, tool calls and the reply in order"
|
|
8619
|
-
>
|
|
8620
|
-
</div>
|
|
8621
|
-
<div class="settings-help settings-gap-xs">Turns recorded before this version keep the grouped layout. Saved in this browser.</div>
|
|
8622
|
-
<div class="settings-row settings-gap">
|
|
8623
|
-
<label for="show-suspend-host-toggle">Show Suspend host action</label>
|
|
8624
|
-
<input
|
|
8625
|
-
id="show-suspend-host-toggle"
|
|
8626
|
-
type="checkbox"
|
|
8627
|
-
onchange="updateShowSuspendHostSetting(this.checked)"
|
|
8628
|
-
aria-label="Show Suspend host action"
|
|
8629
|
-
checked
|
|
8630
|
-
>
|
|
8631
|
-
</div>
|
|
8632
|
-
<div class="settings-help settings-gap-xs">Shows or hides the menu action in this browser only. Suspend works only when the relay runs on Windows; a queued suspend still shows its banner here either way.</div>
|
|
8633
|
-
</section>
|
|
8634
8930
|
<section class="settings-section" id="settings-section-reading" aria-labelledby="settings-section-reading-title">
|
|
8635
8931
|
<h3 class="settings-section-title" id="settings-section-reading-title">Reading</h3>
|
|
8636
8932
|
<div class="settings-row settings-gap">
|
|
@@ -8745,44 +9041,8 @@
|
|
|
8745
9041
|
<div id="model-refresh-providers" class="settings-gap" role="group" aria-label="Providers checked for new models"></div>
|
|
8746
9042
|
<div class="settings-help settings-gap-xs">The relay asks each switched-on provider for its model list this often. A provider whose list was refreshed in the meantime (Refresh in Select Models, a settings save, a sign-in) waits a full interval again, and a failed check is tried again after an hour at the earliest. Whether a new model starts on is set per provider in Select Models. A setting of this relay.</div>
|
|
8747
9043
|
</section>
|
|
8748
|
-
<section class="settings-section" id="settings-section-
|
|
8749
|
-
<h3 class="settings-section-title" id="settings-section-
|
|
8750
|
-
<div class="settings-row settings-row-column settings-gap">
|
|
8751
|
-
<label for="pwa-app-name-input">Relay name</label>
|
|
8752
|
-
<input
|
|
8753
|
-
id="pwa-app-name-input"
|
|
8754
|
-
type="text"
|
|
8755
|
-
maxlength="60"
|
|
8756
|
-
placeholder="OAR"
|
|
8757
|
-
aria-label="Relay name"
|
|
8758
|
-
onchange="updatePwaAppName(this.value)"
|
|
8759
|
-
>
|
|
8760
|
-
<div class="settings-help">Shown to other relays and used as the installed app's name. On Android, a rename reaches an already-installed app after a short delay, with one confirmation prompt showing the new name. A setting of this relay.</div>
|
|
8761
|
-
</div>
|
|
8762
|
-
<div class="settings-row settings-gap">
|
|
8763
|
-
<label for="restart-resume-toggle">After a relay restart, tell interrupted sessions to carry on</label>
|
|
8764
|
-
<input
|
|
8765
|
-
id="restart-resume-toggle"
|
|
8766
|
-
type="checkbox"
|
|
8767
|
-
onchange="updateRestartResumeSettingFromToggle(this.checked)"
|
|
8768
|
-
aria-label="After a relay restart, tell interrupted sessions to carry on"
|
|
8769
|
-
>
|
|
8770
|
-
</div>
|
|
8771
|
-
<div class="settings-help settings-gap-xs">Most turns a restart interrupts run again by themselves. A turn that cannot (the agent had already taken the message, or had started on its own after a background task) just stops. With this on, such a session gets one relay note once the relay is back, saying when it restarted and asking the agent to check what it was doing and carry on. Your message is never sent again; idle, archived and usage-limit-paused sessions get nothing. Off by default; a setting of this relay.</div>
|
|
8772
|
-
<div class="settings-row settings-gap">
|
|
8773
|
-
<label for="relay-restart-max-wait-select">Ask after a queued relay restart has waited</label>
|
|
8774
|
-
<select id="relay-restart-max-wait-select" onchange="updateRelayRestartMaxWaitSetting(this.value)" aria-label="Ask after a queued relay restart has waited">
|
|
8775
|
-
<option value="5">5 min</option>
|
|
8776
|
-
<option value="10">10 min</option>
|
|
8777
|
-
<option value="15">15 min</option>
|
|
8778
|
-
<option value="30" selected>30 min</option>
|
|
8779
|
-
<option value="60">1 h</option>
|
|
8780
|
-
<option value="120">2 h</option>
|
|
8781
|
-
<option value="240">4 h</option>
|
|
8782
|
-
<option value="0">No limit</option>
|
|
8783
|
-
</select>
|
|
8784
|
-
</div>
|
|
8785
|
-
<div class="settings-help settings-gap-xs">A queued relay restart waits for the running turns, and new messages wait for the restart. After this long the banner asks whether to restart now, keep waiting or cancel; it never restarts while the turns run, and still restarts as soon as they end. No limit waits until the turns end. A setting of this relay.</div>
|
|
9044
|
+
<section class="settings-section" id="settings-section-computer" aria-labelledby="settings-section-computer-title">
|
|
9045
|
+
<h3 class="settings-section-title" id="settings-section-computer-title">This computer</h3>
|
|
8786
9046
|
<div class="settings-row settings-row-column settings-gap">
|
|
8787
9047
|
<label for="default-session-workspace-root-input">Default CWD for new sessions</label>
|
|
8788
9048
|
<input
|
|
@@ -8859,6 +9119,80 @@
|
|
|
8859
9119
|
</div>
|
|
8860
9120
|
</section>
|
|
8861
9121
|
</div>
|
|
9122
|
+
<div
|
|
9123
|
+
id="settings-panel-appearance"
|
|
9124
|
+
class="settings-panel"
|
|
9125
|
+
role="tabpanel"
|
|
9126
|
+
tabindex="0"
|
|
9127
|
+
aria-labelledby="settings-tab-appearance"
|
|
9128
|
+
data-settings-panel="appearance"
|
|
9129
|
+
hidden
|
|
9130
|
+
>
|
|
9131
|
+
<div id="appearance-browser-note" class="settings-help">These settings are kept in this browser; other devices keep their own.</div>
|
|
9132
|
+
<div class="settings-row">
|
|
9133
|
+
<label for="theme-select">Theme</label>
|
|
9134
|
+
<select id="theme-select" onchange="updateTheme(this.value)" aria-describedby="appearance-browser-note">
|
|
9135
|
+
<option value="dark">Dark</option>
|
|
9136
|
+
<option value="light">Light</option>
|
|
9137
|
+
</select>
|
|
9138
|
+
</div>
|
|
9139
|
+
<div class="settings-row" style="margin-bottom: 0;">
|
|
9140
|
+
<label for="font-scale-select">Text scaling</label>
|
|
9141
|
+
<select id="font-scale-select" onchange="updateFontScaleFromSelect(this.value)" aria-label="Text scaling" aria-describedby="appearance-browser-note"></select>
|
|
9142
|
+
</div>
|
|
9143
|
+
<div class="settings-row settings-gap">
|
|
9144
|
+
<label for="thoughts-expanded-toggle">Expand thoughts while an agent works</label>
|
|
9145
|
+
<input
|
|
9146
|
+
id="thoughts-expanded-toggle"
|
|
9147
|
+
aria-describedby="appearance-browser-note"
|
|
9148
|
+
type="checkbox"
|
|
9149
|
+
onchange="updateThoughtsExpandedSetting(this.checked)"
|
|
9150
|
+
aria-label="Expand thoughts while an agent works"
|
|
9151
|
+
checked
|
|
9152
|
+
>
|
|
9153
|
+
</div>
|
|
9154
|
+
<div class="settings-help settings-gap-xs">Open thoughts in the live turn, in sub-agent bubbles and in the sub-agent viewer.</div>
|
|
9155
|
+
<div class="settings-row settings-row-column settings-gap">
|
|
9156
|
+
<label for="live-activity-cap-slider">Tool lines shown while an agent works <span id="live-activity-cap-value">50 lines</span></label>
|
|
9157
|
+
<input
|
|
9158
|
+
id="live-activity-cap-slider"
|
|
9159
|
+
aria-describedby="appearance-browser-note"
|
|
9160
|
+
type="range"
|
|
9161
|
+
min="10"
|
|
9162
|
+
max="510"
|
|
9163
|
+
step="10"
|
|
9164
|
+
value="50"
|
|
9165
|
+
aria-label="Tool lines shown while an agent works"
|
|
9166
|
+
aria-valuetext="50 lines"
|
|
9167
|
+
oninput="previewLiveActivityCap(this.value)"
|
|
9168
|
+
onchange="updateLiveActivityCap(this.value)"
|
|
9169
|
+
>
|
|
9170
|
+
</div>
|
|
9171
|
+
<div class="settings-help settings-gap-xs">Per agent: the main agent and each sub-agent keep this many of their newest tool lines in the live bubble. The relay keeps up to 500 per agent.</div>
|
|
9172
|
+
<div class="settings-row settings-gap">
|
|
9173
|
+
<label for="stream-view-toggle">Stream view: thoughts, tool calls and the reply in order</label>
|
|
9174
|
+
<input
|
|
9175
|
+
id="stream-view-toggle"
|
|
9176
|
+
aria-describedby="appearance-browser-note"
|
|
9177
|
+
type="checkbox"
|
|
9178
|
+
onchange="updateStreamViewSetting(this.checked)"
|
|
9179
|
+
aria-label="Stream view: thoughts, tool calls and the reply in order"
|
|
9180
|
+
>
|
|
9181
|
+
</div>
|
|
9182
|
+
<div class="settings-help settings-gap-xs">Turns recorded before this version keep the grouped layout.</div>
|
|
9183
|
+
<div class="settings-row settings-gap">
|
|
9184
|
+
<label for="show-suspend-host-toggle">Show Suspend host action</label>
|
|
9185
|
+
<input
|
|
9186
|
+
id="show-suspend-host-toggle"
|
|
9187
|
+
aria-describedby="appearance-browser-note"
|
|
9188
|
+
type="checkbox"
|
|
9189
|
+
onchange="updateShowSuspendHostSetting(this.checked)"
|
|
9190
|
+
aria-label="Show Suspend host action"
|
|
9191
|
+
checked
|
|
9192
|
+
>
|
|
9193
|
+
</div>
|
|
9194
|
+
<div class="settings-help settings-gap-xs">Shows or hides the menu action in this browser only. Suspend works only when the relay runs on Windows; a queued suspend still shows its banner here either way.</div>
|
|
9195
|
+
</div>
|
|
8862
9196
|
<div
|
|
8863
9197
|
id="settings-panel-providers"
|
|
8864
9198
|
class="settings-panel"
|
|
@@ -9036,6 +9370,37 @@
|
|
|
9036
9370
|
</div>
|
|
9037
9371
|
<div class="settings-help">Leave the key blank to keep the saved key, or enter a new one to replace it. Provider changes also update conversations that have not sent a message yet. The Base URL is useful for OpenAI-compatible endpoints or for pointing to the capture proxy (<code>node server/tools/capture-proxy.mjs</code>) to inspect requests.</div>
|
|
9038
9372
|
</div>
|
|
9373
|
+
<!-- Image turns: the daily cap, today's spend and the presets (openai-image-cost-ui.js). -->
|
|
9374
|
+
<div id="openai-image-spend-section" class="settings-row settings-row-column settings-gap" data-testid="openai-image-spend-section">
|
|
9375
|
+
<label for="openai-image-cap-input">Daily image cap (USD)</label>
|
|
9376
|
+
<div class="openai-image-cap-row">
|
|
9377
|
+
<input
|
|
9378
|
+
id="openai-image-cap-input"
|
|
9379
|
+
data-testid="openai-image-cap-input"
|
|
9380
|
+
type="number"
|
|
9381
|
+
inputmode="decimal"
|
|
9382
|
+
min="0"
|
|
9383
|
+
max="10000"
|
|
9384
|
+
step="0.01"
|
|
9385
|
+
value="5"
|
|
9386
|
+
aria-label="Daily image cap in US dollars, 0 for no cap"
|
|
9387
|
+
aria-describedby="openai-image-spend-error openai-image-cap-help"
|
|
9388
|
+
>
|
|
9389
|
+
<button id="openai-image-cap-save-btn" data-testid="openai-image-cap-save" type="button" class="summary-btn">Save cap</button>
|
|
9390
|
+
</div>
|
|
9391
|
+
<div id="openai-image-spend-error" data-testid="openai-image-spend-error" class="settings-help openai-image-field-error" role="alert" hidden></div>
|
|
9392
|
+
<div id="openai-image-cap-help" class="settings-help">What image turns may cost this relay per day (relay time), estimates included. Once today's spend reaches it, new image turns are refused until tomorrow or until you allow more for today; a running turn finishes. 0 means no cap.</div>
|
|
9393
|
+
<div id="openai-image-spend-line" data-testid="openai-image-spend-line" class="settings-help settings-provider-status" role="status">Today's image spend is not known yet.</div>
|
|
9394
|
+
<div class="settings-actions">
|
|
9395
|
+
<button id="openai-image-allow-today-btn" data-testid="openai-image-allow-today" type="button" class="summary-btn" hidden>Allow past the cap for today</button>
|
|
9396
|
+
<button id="openai-image-stop-allowing-btn" data-testid="openai-image-stop-allowing" type="button" class="summary-btn" hidden>Stop allowing</button>
|
|
9397
|
+
</div>
|
|
9398
|
+
<div id="openai-image-spend-status" class="settings-help" role="status" aria-live="polite"></div>
|
|
9399
|
+
<label class="settings-gap-sm" id="openai-image-presets-label">Image presets</label>
|
|
9400
|
+
<ul id="openai-image-presets-list" data-testid="openai-image-presets-list" class="openai-image-presets-list" aria-labelledby="openai-image-presets-label"></ul>
|
|
9401
|
+
<div id="openai-image-presets-error" class="settings-help openai-image-field-error" role="alert" hidden></div>
|
|
9402
|
+
<div id="openai-image-presets-note" class="settings-help"></div>
|
|
9403
|
+
</div>
|
|
9039
9404
|
</div>
|
|
9040
9405
|
<div
|
|
9041
9406
|
id="settings-provider-panel-claude"
|
|
@@ -9560,11 +9925,16 @@
|
|
|
9560
9925
|
hidden
|
|
9561
9926
|
>
|
|
9562
9927
|
<div id="remote-relays-self-section" class="settings-row settings-row-column settings-gap">
|
|
9563
|
-
<label>
|
|
9564
|
-
<
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9928
|
+
<label for="pwa-app-name-input">Relay name</label>
|
|
9929
|
+
<input
|
|
9930
|
+
id="pwa-app-name-input"
|
|
9931
|
+
type="text"
|
|
9932
|
+
maxlength="60"
|
|
9933
|
+
placeholder="OAR"
|
|
9934
|
+
aria-label="Relay name"
|
|
9935
|
+
onchange="updatePwaAppName(this.value)"
|
|
9936
|
+
>
|
|
9937
|
+
<div class="settings-help">Shown to other relays and used as the installed app's name. On Android, a rename reaches an already-installed app after a short delay, with one confirmation prompt showing the new name. A setting of this relay.</div>
|
|
9568
9938
|
</div>
|
|
9569
9939
|
<div class="settings-row settings-row-column settings-gap">
|
|
9570
9940
|
<label for="remote-relays-public-url-input">Public address</label>
|
|
@@ -9582,6 +9952,30 @@
|
|
|
9582
9952
|
<div class="settings-help">How other relays reach this one — the address you open this relay at from another device. Needed for "Also add this relay there".</div>
|
|
9583
9953
|
<div id="remote-relays-self-status" class="settings-help settings-provider-status" role="status" aria-live="polite" hidden></div>
|
|
9584
9954
|
</div>
|
|
9955
|
+
<div class="settings-row settings-gap">
|
|
9956
|
+
<label for="restart-resume-toggle">After a relay restart, tell interrupted sessions to carry on</label>
|
|
9957
|
+
<input
|
|
9958
|
+
id="restart-resume-toggle"
|
|
9959
|
+
type="checkbox"
|
|
9960
|
+
onchange="updateRestartResumeSettingFromToggle(this.checked)"
|
|
9961
|
+
aria-label="After a relay restart, tell interrupted sessions to carry on"
|
|
9962
|
+
>
|
|
9963
|
+
</div>
|
|
9964
|
+
<div class="settings-help settings-gap-xs">Most turns a restart interrupts run again by themselves. A turn that cannot (the agent had already taken the message, or had started on its own after a background task) just stops. With this on, such a session gets one relay note once the relay is back, saying when it restarted and asking the agent to check what it was doing and carry on. Your message is never sent again; idle, archived and usage-limit-paused sessions get nothing. Off by default; a setting of this relay.</div>
|
|
9965
|
+
<div class="settings-row settings-gap">
|
|
9966
|
+
<label for="relay-restart-max-wait-select">Ask after a queued relay restart has waited</label>
|
|
9967
|
+
<select id="relay-restart-max-wait-select" onchange="updateRelayRestartMaxWaitSetting(this.value)" aria-label="Ask after a queued relay restart has waited">
|
|
9968
|
+
<option value="5">5 min</option>
|
|
9969
|
+
<option value="10">10 min</option>
|
|
9970
|
+
<option value="15">15 min</option>
|
|
9971
|
+
<option value="30" selected>30 min</option>
|
|
9972
|
+
<option value="60">1 h</option>
|
|
9973
|
+
<option value="120">2 h</option>
|
|
9974
|
+
<option value="240">4 h</option>
|
|
9975
|
+
<option value="0">No limit</option>
|
|
9976
|
+
</select>
|
|
9977
|
+
</div>
|
|
9978
|
+
<div class="settings-help settings-gap-xs">A queued relay restart waits for the running turns, and new messages wait for the restart. After this long the banner asks whether to restart now, keep waiting or cancel; it never restarts while the turns run, and still restarts as soon as they end. No limit waits until the turns end. A setting of this relay.</div>
|
|
9585
9979
|
<div class="settings-row settings-gap">
|
|
9586
9980
|
<label for="remote-relays-inbound-toggle">Accept prompts from other relays' agents</label>
|
|
9587
9981
|
<input
|