oysterun 1.5.5 → 1.5.7-beta.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/dev/client/web/index.html +1736 -151
- package/dev/client/web-chat/dist/assets/{ReactPrism-9mfIwAdN.js → ReactPrism-DNQ9nZSp.js} +1 -1
- package/dev/client/web-chat/dist/assets/{ReactPrism-9mfIwAdN.js.map → ReactPrism-DNQ9nZSp.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-4B1xHv-h.css → index-BFaINJYC.css} +1 -1
- package/dev/client/web-chat/dist/assets/{index-CpnKlml1.js → index-D3mRy5zG.js} +92 -92
- package/dev/client/web-chat/dist/assets/index-D3mRy5zG.js.map +1 -0
- package/dev/client/web-chat/dist/assets/{index-DWS0uvcS.js → index-Dt0tJQEo.js} +2 -2
- package/dev/client/web-chat/dist/assets/{index-DWS0uvcS.js.map → index-Dt0tJQEo.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-DKemUlfN.js → index-kph-A9_0.js} +1 -1
- package/dev/client/web-chat/dist/assets/{index-DKemUlfN.js.map → index-kph-A9_0.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{pdf-_pQ2yOcq.js → pdf-Dz-8X_5I.js} +3 -3
- package/dev/client/web-chat/dist/assets/{pdf-_pQ2yOcq.js.map → pdf-Dz-8X_5I.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-_J72Rkyo.js → web-8cohp67o.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-_J72Rkyo.js.map → web-8cohp67o.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-hiRi-dhx.js → web-z_YJW2TC.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-hiRi-dhx.js.map → web-z_YJW2TC.js.map} +1 -1
- package/dev/client/web-chat/dist/index.html +2 -2
- package/docs/routec/dev/cloud_deplyments.md +138 -0
- package/docs/routec/dev/provider_catalog_readiness.md +71 -0
- package/docs/routec/dev/scheduler_mail_skill.md +3 -0
- package/docs/routec/form_UI_fields.md +3 -4
- package/docs/routec/skill_installation.md +35 -0
- package/host-service/assets/product-skills/Oysterun/SKILL.md +9 -0
- package/host-service/assets/voice-input/D1.wav +0 -0
- package/host-service/browser-root-project-index.mjs +126 -2
- package/host-service/config.mjs +7 -0
- package/host-service/folder-browser.mjs +8 -9
- package/host-service/package.json +4 -2
- package/host-service/portable-scheduler-definitions.mjs +16 -15
- package/host-service/provider-auth.mjs +10 -1
- package/host-service/routec-matrix-storage-adapter.mjs +4 -0
- package/host-service/server.mjs +570 -154
- package/host-service/session-manager.mjs +1 -0
- package/host-service/templates/demo-agents/oysterun-github-tracker/.oysterun/schedulers.json +0 -24
- package/host-service/voice-input-owner-capture.mjs +225 -0
- package/host-service/voice-input-recording-collector.mjs +369 -0
- package/host-service/voice-input-service.mjs +755 -0
- package/host-service/voice-input-usage-contract.mjs +63 -0
- package/host-service/voice-input-usage-store.mjs +409 -0
- package/package.json +2 -1
- package/dev/client/web-chat/dist/assets/index-CpnKlml1.js.map +0 -1
|
@@ -2061,6 +2061,117 @@
|
|
|
2061
2061
|
line-height: 1.35;
|
|
2062
2062
|
}
|
|
2063
2063
|
|
|
2064
|
+
.settings-list-page .voice-input-secret-input {
|
|
2065
|
+
-webkit-text-security: disc;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
.settings-list-page .voice-input-secret-input::placeholder {
|
|
2069
|
+
-webkit-text-security: none;
|
|
2070
|
+
color: var(--tc-surface-low);
|
|
2071
|
+
opacity: 1;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
.settings-list-page .voice-input-token-status {
|
|
2075
|
+
text-align: left;
|
|
2076
|
+
overflow-wrap: anywhere;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
.settings-list-page .voice-input-sample-player {
|
|
2080
|
+
display: block;
|
|
2081
|
+
width: 100%;
|
|
2082
|
+
max-width: 520px;
|
|
2083
|
+
height: 44px;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
.settings-list-page .voice-input-sample-expected {
|
|
2087
|
+
display: inline-block;
|
|
2088
|
+
margin-left: 4px;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
.settings-list-page .voice-input-warning {
|
|
2092
|
+
color: var(--danger, #c53030);
|
|
2093
|
+
font-weight: 700;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
.settings-list-page .host-voice-input-toggle:disabled {
|
|
2097
|
+
cursor: not-allowed;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
.settings-list-page .voice-input-usage-summary {
|
|
2101
|
+
display: grid;
|
|
2102
|
+
gap: 8px;
|
|
2103
|
+
margin-top: 14px;
|
|
2104
|
+
padding-top: 14px;
|
|
2105
|
+
border-top: 1px solid var(--line);
|
|
2106
|
+
color: var(--ink);
|
|
2107
|
+
font-size: 13px;
|
|
2108
|
+
line-height: 1.45;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
.settings-list-page .voice-input-usage-summary.hidden {
|
|
2112
|
+
display: none;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
.settings-list-page .voice-input-usage-detail-link {
|
|
2116
|
+
justify-self: start;
|
|
2117
|
+
min-height: 38px;
|
|
2118
|
+
padding: 6px 0;
|
|
2119
|
+
border: 0;
|
|
2120
|
+
color: var(--accent-strong, #0b6f64);
|
|
2121
|
+
background: transparent;
|
|
2122
|
+
font-weight: 800;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
.voice-input-usage-page {
|
|
2126
|
+
width: min(100%, 920px);
|
|
2127
|
+
margin: 0 auto;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
.voice-input-usage-table-wrap {
|
|
2131
|
+
width: 100%;
|
|
2132
|
+
overflow-x: auto;
|
|
2133
|
+
border: 1px solid var(--line);
|
|
2134
|
+
border-radius: 8px;
|
|
2135
|
+
background: #fff;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
.voice-input-usage-table {
|
|
2139
|
+
width: 100%;
|
|
2140
|
+
min-width: 680px;
|
|
2141
|
+
border-collapse: collapse;
|
|
2142
|
+
color: var(--ink);
|
|
2143
|
+
font-size: 14px;
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
.voice-input-usage-table th,
|
|
2147
|
+
.voice-input-usage-table td {
|
|
2148
|
+
padding: 12px 14px;
|
|
2149
|
+
border-bottom: 1px solid var(--line);
|
|
2150
|
+
text-align: right;
|
|
2151
|
+
white-space: nowrap;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
.voice-input-usage-table th:first-child,
|
|
2155
|
+
.voice-input-usage-table td:first-child {
|
|
2156
|
+
text-align: left;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
.voice-input-usage-table thead th {
|
|
2160
|
+
background: #f3eee6;
|
|
2161
|
+
font-size: 12px;
|
|
2162
|
+
font-weight: 850;
|
|
2163
|
+
text-transform: uppercase;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
.voice-input-usage-table tbody th {
|
|
2167
|
+
font-weight: 750;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
.voice-input-usage-table tbody tr:last-child th,
|
|
2171
|
+
.voice-input-usage-table tbody tr:last-child td {
|
|
2172
|
+
border-bottom: 0;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2064
2175
|
.settings-list-page .field {
|
|
2065
2176
|
padding: 14px;
|
|
2066
2177
|
border: 1px solid var(--line);
|
|
@@ -8496,6 +8607,16 @@
|
|
|
8496
8607
|
</button>
|
|
8497
8608
|
</div>
|
|
8498
8609
|
<div class="field-hint" id="runtime-hint"></div>
|
|
8610
|
+
<button
|
|
8611
|
+
id="create-provider-retry-btn"
|
|
8612
|
+
class="btn-ghost btn-compact hidden"
|
|
8613
|
+
type="button"
|
|
8614
|
+
onClick=${call(
|
|
8615
|
+
"retryHostPreferencesProviderSection"
|
|
8616
|
+
)}
|
|
8617
|
+
>
|
|
8618
|
+
Retry
|
|
8619
|
+
</button>
|
|
8499
8620
|
</div>
|
|
8500
8621
|
</div>
|
|
8501
8622
|
<label
|
|
@@ -8659,6 +8780,13 @@
|
|
|
8659
8780
|
data-session-setup-web-shared="web.enabled"
|
|
8660
8781
|
/>
|
|
8661
8782
|
</label>
|
|
8783
|
+
<div
|
|
8784
|
+
id="create-website-authority-hint"
|
|
8785
|
+
class="field-hint field-warning"
|
|
8786
|
+
>
|
|
8787
|
+
Website is available only for agents in the Browser
|
|
8788
|
+
Root.
|
|
8789
|
+
</div>
|
|
8662
8790
|
</div>
|
|
8663
8791
|
<label
|
|
8664
8792
|
class="kv-label"
|
|
@@ -9109,6 +9237,168 @@
|
|
|
9109
9237
|
</div>
|
|
9110
9238
|
</div>
|
|
9111
9239
|
</section>
|
|
9240
|
+
<section class="table-panel">
|
|
9241
|
+
<div class="table-title">
|
|
9242
|
+
<div class="table-title-main">
|
|
9243
|
+
<strong id="host-voice-input-title">
|
|
9244
|
+
Voice Input
|
|
9245
|
+
</strong>
|
|
9246
|
+
<div class="table-title-copy">
|
|
9247
|
+
Record from the Chat composer and append a GPT-4o
|
|
9248
|
+
transcript for review before sending.
|
|
9249
|
+
</div>
|
|
9250
|
+
</div>
|
|
9251
|
+
<span class="pill" id="host-voice-input-state-pill">
|
|
9252
|
+
Disabled
|
|
9253
|
+
</span>
|
|
9254
|
+
</div>
|
|
9255
|
+
<div class="kv-table">
|
|
9256
|
+
<div class="kv-label">OpenAI API Token</div>
|
|
9257
|
+
<div class="kv-value">
|
|
9258
|
+
<div class="value-stack">
|
|
9259
|
+
<div class="control-cell">
|
|
9260
|
+
<input
|
|
9261
|
+
id="host-voice-input-token"
|
|
9262
|
+
class="voice-input-secret-input"
|
|
9263
|
+
type="text"
|
|
9264
|
+
inputmode="text"
|
|
9265
|
+
autocomplete="off"
|
|
9266
|
+
autocapitalize="none"
|
|
9267
|
+
autocorrect="off"
|
|
9268
|
+
spellcheck=${false}
|
|
9269
|
+
placeholder="Enter a new token"
|
|
9270
|
+
/>
|
|
9271
|
+
<button
|
|
9272
|
+
class="btn-primary btn-compact"
|
|
9273
|
+
id="host-voice-input-discard-token-draft-btn"
|
|
9274
|
+
type="button"
|
|
9275
|
+
onClick=${call(
|
|
9276
|
+
"discardHostVoiceInputTokenDraft"
|
|
9277
|
+
)}
|
|
9278
|
+
>
|
|
9279
|
+
Discard New Token
|
|
9280
|
+
</button>
|
|
9281
|
+
<button
|
|
9282
|
+
class="btn-primary btn-compact"
|
|
9283
|
+
id="host-voice-input-remove-saved-token-btn"
|
|
9284
|
+
type="button"
|
|
9285
|
+
onClick=${call(
|
|
9286
|
+
"removeHostVoiceInputSavedToken"
|
|
9287
|
+
)}
|
|
9288
|
+
>
|
|
9289
|
+
Remove Saved Token
|
|
9290
|
+
</button>
|
|
9291
|
+
</div>
|
|
9292
|
+
<div
|
|
9293
|
+
class="field-hint mono-path voice-input-token-status"
|
|
9294
|
+
id="host-voice-input-token-status"
|
|
9295
|
+
>
|
|
9296
|
+
No token saved.
|
|
9297
|
+
</div>
|
|
9298
|
+
<div
|
|
9299
|
+
class="field-hint voice-input-warning"
|
|
9300
|
+
id="host-voice-input-client-warning"
|
|
9301
|
+
></div>
|
|
9302
|
+
</div>
|
|
9303
|
+
</div>
|
|
9304
|
+
<div class="kv-label">Sample</div>
|
|
9305
|
+
<div class="kv-value">
|
|
9306
|
+
<div class="value-stack">
|
|
9307
|
+
<audio
|
|
9308
|
+
class="voice-input-sample-player"
|
|
9309
|
+
id="host-voice-input-sample-player"
|
|
9310
|
+
controls
|
|
9311
|
+
preload="metadata"
|
|
9312
|
+
></audio>
|
|
9313
|
+
<div
|
|
9314
|
+
class="field-hint"
|
|
9315
|
+
id="host-voice-input-sample-status"
|
|
9316
|
+
></div>
|
|
9317
|
+
<div class="field-hint">
|
|
9318
|
+
<strong>Expected transcript:</strong>
|
|
9319
|
+
<span
|
|
9320
|
+
class="voice-input-sample-expected"
|
|
9321
|
+
id="host-voice-input-sample-expected"
|
|
9322
|
+
>
|
|
9323
|
+
How much money can I withdraw per day from the
|
|
9324
|
+
ATM?
|
|
9325
|
+
</span>
|
|
9326
|
+
</div>
|
|
9327
|
+
<div class="toolbar">
|
|
9328
|
+
<button
|
|
9329
|
+
class="btn-primary"
|
|
9330
|
+
id="host-voice-input-test-btn"
|
|
9331
|
+
type="button"
|
|
9332
|
+
onClick=${call("testHostVoiceInput")}
|
|
9333
|
+
>
|
|
9334
|
+
Test & Save Token
|
|
9335
|
+
</button>
|
|
9336
|
+
</div>
|
|
9337
|
+
<div
|
|
9338
|
+
class="field-hint"
|
|
9339
|
+
id="host-voice-input-test-status"
|
|
9340
|
+
></div>
|
|
9341
|
+
<div
|
|
9342
|
+
class="mono-path"
|
|
9343
|
+
id="host-voice-input-test-transcript"
|
|
9344
|
+
></div>
|
|
9345
|
+
</div>
|
|
9346
|
+
</div>
|
|
9347
|
+
<div class="kv-label">Availability</div>
|
|
9348
|
+
<div class="kv-value settings-checkbox-row-value">
|
|
9349
|
+
<div class="toggle-row">
|
|
9350
|
+
<span>
|
|
9351
|
+
<strong>Enable Voice Input</strong>
|
|
9352
|
+
<div
|
|
9353
|
+
class="field-hint"
|
|
9354
|
+
id="host-voice-input-availability"
|
|
9355
|
+
>
|
|
9356
|
+
Test and save a valid OpenAI API token first.
|
|
9357
|
+
</div>
|
|
9358
|
+
</span>
|
|
9359
|
+
<button
|
|
9360
|
+
class="scheduler-row-toggle host-voice-input-toggle"
|
|
9361
|
+
id="host-voice-input-enabled-toggle"
|
|
9362
|
+
type="button"
|
|
9363
|
+
role="switch"
|
|
9364
|
+
aria-checked="false"
|
|
9365
|
+
aria-disabled="true"
|
|
9366
|
+
aria-label="Enable Voice Input"
|
|
9367
|
+
onClick=${call("toggleHostVoiceInputEnabled")}
|
|
9368
|
+
>
|
|
9369
|
+
<span aria-hidden="true"></span>
|
|
9370
|
+
</button>
|
|
9371
|
+
</div>
|
|
9372
|
+
<div
|
|
9373
|
+
class="field-hint voice-input-warning"
|
|
9374
|
+
id="host-voice-input-enable-warning"
|
|
9375
|
+
>
|
|
9376
|
+
Test and save a valid OpenAI API token before
|
|
9377
|
+
enabling Voice Input.
|
|
9378
|
+
</div>
|
|
9379
|
+
<div
|
|
9380
|
+
class="voice-input-usage-summary hidden"
|
|
9381
|
+
id="host-voice-input-usage-summary"
|
|
9382
|
+
>
|
|
9383
|
+
<div id="host-voice-input-usage-24h"></div>
|
|
9384
|
+
<div id="host-voice-input-usage-7d"></div>
|
|
9385
|
+
<div id="host-voice-input-usage-30d"></div>
|
|
9386
|
+
<div
|
|
9387
|
+
class="field-hint voice-input-warning hidden"
|
|
9388
|
+
id="host-voice-input-usage-error"
|
|
9389
|
+
></div>
|
|
9390
|
+
<button
|
|
9391
|
+
class="btn-ghost voice-input-usage-detail-link"
|
|
9392
|
+
id="host-voice-input-usage-detail-btn"
|
|
9393
|
+
type="button"
|
|
9394
|
+
onClick=${call("openHostVoiceInputUsageDetail")}
|
|
9395
|
+
>
|
|
9396
|
+
View Usage Stats Detail
|
|
9397
|
+
</button>
|
|
9398
|
+
</div>
|
|
9399
|
+
</div>
|
|
9400
|
+
</div>
|
|
9401
|
+
</section>
|
|
9112
9402
|
<section class="table-panel">
|
|
9113
9403
|
<div class="table-title">
|
|
9114
9404
|
<div class="table-title-main">
|
|
@@ -9785,6 +10075,55 @@
|
|
|
9785
10075
|
`;
|
|
9786
10076
|
}
|
|
9787
10077
|
|
|
10078
|
+
function VoiceInputUsageView() {
|
|
10079
|
+
return html`
|
|
10080
|
+
<section
|
|
10081
|
+
id="voice-input-usage-view"
|
|
10082
|
+
class="view view-page-scroll"
|
|
10083
|
+
data-oysterun-voice-input-usage-page="true"
|
|
10084
|
+
>
|
|
10085
|
+
<div class="page-screen">
|
|
10086
|
+
<section class="panel page-form-panel voice-input-usage-page">
|
|
10087
|
+
<div
|
|
10088
|
+
class="field-hint"
|
|
10089
|
+
id="voice-input-usage-generated-at"
|
|
10090
|
+
></div>
|
|
10091
|
+
<div
|
|
10092
|
+
class="error-box hidden"
|
|
10093
|
+
id="voice-input-usage-error"
|
|
10094
|
+
></div>
|
|
10095
|
+
<div
|
|
10096
|
+
class="voice-input-usage-table-wrap"
|
|
10097
|
+
id="voice-input-usage-table-wrap"
|
|
10098
|
+
>
|
|
10099
|
+
<table class="voice-input-usage-table">
|
|
10100
|
+
<thead>
|
|
10101
|
+
<tr>
|
|
10102
|
+
<th scope="col">Metric</th>
|
|
10103
|
+
<th scope="col">24 hours</th>
|
|
10104
|
+
<th scope="col">7 days</th>
|
|
10105
|
+
<th scope="col">30 days</th>
|
|
10106
|
+
</tr>
|
|
10107
|
+
</thead>
|
|
10108
|
+
<tbody id="voice-input-usage-table-body"></tbody>
|
|
10109
|
+
</table>
|
|
10110
|
+
</div>
|
|
10111
|
+
<div class="toolbar">
|
|
10112
|
+
<button
|
|
10113
|
+
class="btn-primary hidden"
|
|
10114
|
+
id="voice-input-usage-retry-btn"
|
|
10115
|
+
type="button"
|
|
10116
|
+
onClick=${call("retryHostVoiceInputUsage")}
|
|
10117
|
+
>
|
|
10118
|
+
Retry
|
|
10119
|
+
</button>
|
|
10120
|
+
</div>
|
|
10121
|
+
</section>
|
|
10122
|
+
</div>
|
|
10123
|
+
</section>
|
|
10124
|
+
`;
|
|
10125
|
+
}
|
|
10126
|
+
|
|
9788
10127
|
function ChangePasswordView() {
|
|
9789
10128
|
return html`
|
|
9790
10129
|
<section id="change-password-view" class="view view-page-scroll">
|
|
@@ -10573,19 +10912,6 @@ Terminal output will appear here.</pre
|
|
|
10573
10912
|
class="session-profile-action-stack"
|
|
10574
10913
|
data-session-profile-action-block="session_identity"
|
|
10575
10914
|
>
|
|
10576
|
-
<label
|
|
10577
|
-
class="toggle-row"
|
|
10578
|
-
data-session-profile-identity-update-config-row="session_identity"
|
|
10579
|
-
>
|
|
10580
|
-
<span>
|
|
10581
|
-
<strong>Update .oysterun/config.json</strong>
|
|
10582
|
-
</span>
|
|
10583
|
-
<input
|
|
10584
|
-
id="agent-profile-identity-update-config"
|
|
10585
|
-
type="checkbox"
|
|
10586
|
-
data-session-profile-update-config="session_identity"
|
|
10587
|
-
/>
|
|
10588
|
-
</label>
|
|
10589
10915
|
<button
|
|
10590
10916
|
class="btn-secondary session-profile-save-row"
|
|
10591
10917
|
id="agent-profile-identity-save-btn"
|
|
@@ -11399,6 +11725,7 @@ Waiting for Claude login output…</pre
|
|
|
11399
11725
|
<${SessionLoopView} />
|
|
11400
11726
|
<${SessionSetupView} />
|
|
11401
11727
|
<${HostPreferencesView} />
|
|
11728
|
+
<${VoiceInputUsageView} />
|
|
11402
11729
|
<${ChangePasswordView} />
|
|
11403
11730
|
<${TerminalView} />
|
|
11404
11731
|
<${FolderPickerView} />
|
|
@@ -13325,6 +13652,12 @@ Waiting for Claude login output…</pre
|
|
|
13325
13652
|
let lastCreateStartActivationAt = 0;
|
|
13326
13653
|
let createFormPreferenceVersion = 0;
|
|
13327
13654
|
let latestCreateFolderConfigRequestId = 0;
|
|
13655
|
+
let createWebsiteAuthorityState = {
|
|
13656
|
+
folderPath: "",
|
|
13657
|
+
projectId: "",
|
|
13658
|
+
eligible: false,
|
|
13659
|
+
reason: "Website is available only for agents in the Browser Root.",
|
|
13660
|
+
};
|
|
13328
13661
|
let createFormDraftRouteKey = "";
|
|
13329
13662
|
let createSubmitState = {
|
|
13330
13663
|
inFlight: false,
|
|
@@ -13375,8 +13708,37 @@ Waiting for Claude login output…</pre
|
|
|
13375
13708
|
preview: null,
|
|
13376
13709
|
roots: {},
|
|
13377
13710
|
};
|
|
13711
|
+
const PROVIDER_CATALOG_STATUS_UNKNOWN = "unknown";
|
|
13712
|
+
const PROVIDER_CATALOG_STATUS_PENDING = "pending";
|
|
13713
|
+
const PROVIDER_CATALOG_STATUS_READY = "ready";
|
|
13714
|
+
const PROVIDER_CATALOG_STATUS_UNAVAILABLE = "unavailable";
|
|
13715
|
+
const PROVIDER_CATALOG_STATUS_REQUEST_FAILED = "request_failed";
|
|
13716
|
+
|
|
13717
|
+
function getProviderCatalogStatusForProviders(providers) {
|
|
13718
|
+
return providers.some(
|
|
13719
|
+
(entry) =>
|
|
13720
|
+
entry.commandAvailable === true && entry.runtimeSupported === true
|
|
13721
|
+
)
|
|
13722
|
+
? PROVIDER_CATALOG_STATUS_READY
|
|
13723
|
+
: PROVIDER_CATALOG_STATUS_UNAVAILABLE;
|
|
13724
|
+
}
|
|
13725
|
+
|
|
13726
|
+
function isProviderCatalogInitialPending() {
|
|
13727
|
+
return (
|
|
13728
|
+
providerCatalogState.status === PROVIDER_CATALOG_STATUS_UNKNOWN ||
|
|
13729
|
+
providerCatalogState.status === PROVIDER_CATALOG_STATUS_PENDING
|
|
13730
|
+
);
|
|
13731
|
+
}
|
|
13732
|
+
|
|
13733
|
+
function isProviderCatalogRequestFailed() {
|
|
13734
|
+
return (
|
|
13735
|
+
providerCatalogState.status === PROVIDER_CATALOG_STATUS_REQUEST_FAILED
|
|
13736
|
+
);
|
|
13737
|
+
}
|
|
13738
|
+
|
|
13378
13739
|
function createProviderCatalogState() {
|
|
13379
13740
|
return {
|
|
13741
|
+
status: PROVIDER_CATALOG_STATUS_UNKNOWN,
|
|
13380
13742
|
loaded: false,
|
|
13381
13743
|
loading: false,
|
|
13382
13744
|
error: "",
|
|
@@ -13446,6 +13808,7 @@ Waiting for Claude login output…</pre
|
|
|
13446
13808
|
notificationSoundWebEnabled = true,
|
|
13447
13809
|
notificationSoundAppEnabled = true,
|
|
13448
13810
|
dailyTelemetryEnabled = false,
|
|
13811
|
+
voiceInputEnabled = false,
|
|
13449
13812
|
defaultWebsiteAccess = HOST_DEFAULT_SESSION_DEFAULTS.web.access,
|
|
13450
13813
|
defaultNotificationsEnabled = HOST_DEFAULT_SESSION_DEFAULTS
|
|
13451
13814
|
.notifications.enabled,
|
|
@@ -13472,6 +13835,7 @@ Waiting for Claude login output…</pre
|
|
|
13472
13835
|
notificationSoundWebEnabled,
|
|
13473
13836
|
notificationSoundAppEnabled,
|
|
13474
13837
|
dailyTelemetryEnabled,
|
|
13838
|
+
voiceInputEnabled,
|
|
13475
13839
|
defaultWebsiteAccess,
|
|
13476
13840
|
defaultNotificationsEnabled,
|
|
13477
13841
|
defaultRuntimeCapabilities: normalizeRuntimeCapabilityState(
|
|
@@ -13503,6 +13867,34 @@ Waiting for Claude login output…</pre
|
|
|
13503
13867
|
dailyTelemetryEnabled: false,
|
|
13504
13868
|
dailyTelemetryConsentRecordedAt: "",
|
|
13505
13869
|
dailyTelemetryHostIdPresent: false,
|
|
13870
|
+
voiceInputEnabled: false,
|
|
13871
|
+
voiceInputAvailable: false,
|
|
13872
|
+
voiceInputCanEnable: false,
|
|
13873
|
+
voiceInputTokenConfigured: false,
|
|
13874
|
+
voiceInputTokenValidated: false,
|
|
13875
|
+
voiceInputTokenMasked: "",
|
|
13876
|
+
voiceInputTokenDraft: "",
|
|
13877
|
+
voiceInputValidatedAt: "",
|
|
13878
|
+
voiceInputValidatedModel: "",
|
|
13879
|
+
voiceInputValidatedSampleExact: null,
|
|
13880
|
+
voiceInputModel: "gpt-4o-transcribe",
|
|
13881
|
+
voiceInputSampleExpected:
|
|
13882
|
+
"How much money can I withdraw per day from the ATM?",
|
|
13883
|
+
voiceInputSampleLoading: false,
|
|
13884
|
+
voiceInputSampleLoaded: false,
|
|
13885
|
+
voiceInputSampleError: "",
|
|
13886
|
+
voiceInputTestRunning: false,
|
|
13887
|
+
voiceInputTokenClearing: false,
|
|
13888
|
+
voiceInputTestStatus: "",
|
|
13889
|
+
voiceInputTestError: "",
|
|
13890
|
+
voiceInputTestTranscript: "",
|
|
13891
|
+
voiceInputTestLatencyMs: null,
|
|
13892
|
+
voiceInputNativeAppVersion: "",
|
|
13893
|
+
voiceInputNativeAppVersionLoaded: false,
|
|
13894
|
+
voiceInputUsage: null,
|
|
13895
|
+
voiceInputUsageLoading: false,
|
|
13896
|
+
voiceInputUsageLoaded: false,
|
|
13897
|
+
voiceInputUsageError: "",
|
|
13506
13898
|
defaultWebsiteAccess: HOST_DEFAULT_SESSION_DEFAULTS.web.access,
|
|
13507
13899
|
defaultNotificationsEnabled:
|
|
13508
13900
|
HOST_DEFAULT_SESSION_DEFAULTS.notifications.enabled,
|
|
@@ -13576,6 +13968,7 @@ Waiting for Claude login output…</pre
|
|
|
13576
13968
|
};
|
|
13577
13969
|
}
|
|
13578
13970
|
let providerCatalogState = createProviderCatalogState();
|
|
13971
|
+
let providerCatalogLoadPromise = null;
|
|
13579
13972
|
let providerModelRefreshState = {
|
|
13580
13973
|
provider: "",
|
|
13581
13974
|
refreshing: false,
|
|
@@ -13601,6 +13994,10 @@ Waiting for Claude login output…</pre
|
|
|
13601
13994
|
let browserSurfaceState = createBrowserSurfaceState();
|
|
13602
13995
|
let browserSurfaceLaunchRequestId = 0;
|
|
13603
13996
|
let hostPreferencesState = createHostPreferencesState();
|
|
13997
|
+
let hostVoiceInputSampleObjectUrl = "";
|
|
13998
|
+
let hostVoiceInputSampleLoadPromise = null;
|
|
13999
|
+
let hostVoiceInputNativeAppVersionLoadPromise = null;
|
|
14000
|
+
let hostVoiceInputUsageLoadPromise = null;
|
|
13604
14001
|
let hostRestartHandoffTimer = null;
|
|
13605
14002
|
let hostRestartLoginGatePollTimer = null;
|
|
13606
14003
|
let hostRestartLoginGatePollGeneration = 0;
|
|
@@ -14026,6 +14423,7 @@ Waiting for Claude login output…</pre
|
|
|
14026
14423
|
$("host-notification-app-sound-toggle")?.checked !== false,
|
|
14027
14424
|
dailyTelemetryEnabled:
|
|
14028
14425
|
$("host-daily-telemetry-toggle")?.checked === true,
|
|
14426
|
+
voiceInputEnabled: getHostVoiceInputEnabledControlValue(),
|
|
14029
14427
|
defaultWebsiteAccess: hostPreferencesState.defaultWebsiteAccess,
|
|
14030
14428
|
defaultNotificationsEnabled:
|
|
14031
14429
|
$("host-default-notifications-enabled")?.checked !== false,
|
|
@@ -14080,6 +14478,7 @@ Waiting for Claude login output…</pre
|
|
|
14080
14478
|
notificationSoundWebEnabled: draft.notificationSoundWebEnabled,
|
|
14081
14479
|
notificationSoundAppEnabled: draft.notificationSoundAppEnabled,
|
|
14082
14480
|
dailyTelemetryEnabled: draft.dailyTelemetryEnabled,
|
|
14481
|
+
voiceInputEnabled: draft.voiceInputEnabled,
|
|
14083
14482
|
defaultWebsiteAccess: draft.defaultWebsiteAccess,
|
|
14084
14483
|
defaultNotificationsEnabled: draft.defaultNotificationsEnabled,
|
|
14085
14484
|
defaultRuntimeCapabilities: normalizeRuntimeCapabilityState(
|
|
@@ -14112,6 +14511,7 @@ Waiting for Claude login output…</pre
|
|
|
14112
14511
|
a.notificationSoundWebEnabled === b.notificationSoundWebEnabled &&
|
|
14113
14512
|
a.notificationSoundAppEnabled === b.notificationSoundAppEnabled &&
|
|
14114
14513
|
a.dailyTelemetryEnabled === b.dailyTelemetryEnabled &&
|
|
14514
|
+
a.voiceInputEnabled === b.voiceInputEnabled &&
|
|
14115
14515
|
a.defaultWebsiteAccess === b.defaultWebsiteAccess &&
|
|
14116
14516
|
a.defaultNotificationsEnabled === b.defaultNotificationsEnabled &&
|
|
14117
14517
|
JSON.stringify(a.defaultRuntimeCapabilities) ===
|
|
@@ -14171,6 +14571,7 @@ Waiting for Claude login output…</pre
|
|
|
14171
14571
|
const normalized = normalizeClientRoute(route);
|
|
14172
14572
|
return (
|
|
14173
14573
|
normalized.screen === "host-preferences" ||
|
|
14574
|
+
normalized.screen === "voice-input-usage" ||
|
|
14174
14575
|
(normalized.screen === "folder-picker" &&
|
|
14175
14576
|
normalized.targetInputId === HOST_PREFERENCES_FOLDER_PICKER_TARGET)
|
|
14176
14577
|
);
|
|
@@ -14186,6 +14587,8 @@ Waiting for Claude login output…</pre
|
|
|
14186
14587
|
defaultBrowsePath: savedDraft.defaultBrowsePath,
|
|
14187
14588
|
notificationSoundWebEnabled: savedDraft.notificationSoundWebEnabled,
|
|
14188
14589
|
notificationSoundAppEnabled: savedDraft.notificationSoundAppEnabled,
|
|
14590
|
+
dailyTelemetryEnabled: savedDraft.dailyTelemetryEnabled,
|
|
14591
|
+
voiceInputEnabled: savedDraft.voiceInputEnabled,
|
|
14189
14592
|
defaultWebsiteAccess: savedDraft.defaultWebsiteAccess,
|
|
14190
14593
|
defaultNotificationsEnabled: savedDraft.defaultNotificationsEnabled,
|
|
14191
14594
|
defaultRuntimeCapabilities: normalizeRuntimeCapabilityState(
|
|
@@ -14221,6 +14624,7 @@ Waiting for Claude login output…</pre
|
|
|
14221
14624
|
const normalized = normalizeClientRoute(route);
|
|
14222
14625
|
return (
|
|
14223
14626
|
normalized.screen === "host-preferences" ||
|
|
14627
|
+
normalized.screen === "voice-input-usage" ||
|
|
14224
14628
|
normalized.screen === "agent-profile"
|
|
14225
14629
|
);
|
|
14226
14630
|
}
|
|
@@ -14229,6 +14633,14 @@ Waiting for Claude login output…</pre
|
|
|
14229
14633
|
const current = normalizeClientRoute(currentRoute);
|
|
14230
14634
|
const next = normalizeClientRoute(nextRoute);
|
|
14231
14635
|
if (current.screen === next.screen) return true;
|
|
14636
|
+
if (
|
|
14637
|
+
(current.screen === "host-preferences" &&
|
|
14638
|
+
next.screen === "voice-input-usage") ||
|
|
14639
|
+
(current.screen === "voice-input-usage" &&
|
|
14640
|
+
next.screen === "host-preferences")
|
|
14641
|
+
) {
|
|
14642
|
+
return true;
|
|
14643
|
+
}
|
|
14232
14644
|
if (
|
|
14233
14645
|
current.screen === "host-preferences" &&
|
|
14234
14646
|
next.screen === "folder-picker" &&
|
|
@@ -14340,11 +14752,8 @@ Waiting for Claude login output…</pre
|
|
|
14340
14752
|
liveSession.sessionName || liveSession.session_name || ""
|
|
14341
14753
|
).trim();
|
|
14342
14754
|
const draftName = String(agentProfileRenameState.draft || "").trim();
|
|
14343
|
-
const updateConfig =
|
|
14344
|
-
$("agent-profile-identity-update-config")?.checked === true;
|
|
14345
14755
|
return (
|
|
14346
14756
|
agentProfileRenameState.dirty === true ||
|
|
14347
|
-
updateConfig === true ||
|
|
14348
14757
|
(Boolean(draftName) && draftName !== currentName)
|
|
14349
14758
|
);
|
|
14350
14759
|
}
|
|
@@ -14384,7 +14793,10 @@ Waiting for Claude login output…</pre
|
|
|
14384
14793
|
|
|
14385
14794
|
function getP75DirtyFormState() {
|
|
14386
14795
|
const current = normalizeClientRoute(getCurrentRoute());
|
|
14387
|
-
if (
|
|
14796
|
+
if (
|
|
14797
|
+
current.screen === "host-preferences" ||
|
|
14798
|
+
current.screen === "voice-input-usage"
|
|
14799
|
+
) {
|
|
14388
14800
|
return hasUnsavedHostPreferencesChanges()
|
|
14389
14801
|
? {
|
|
14390
14802
|
screen: "host-preferences",
|
|
@@ -15124,6 +15536,9 @@ Waiting for Claude login output…</pre
|
|
|
15124
15536
|
// topbar/back handlers execute a declared route map instead of browser history.
|
|
15125
15537
|
function getFallbackRoute(route = currentRoute) {
|
|
15126
15538
|
const normalized = normalizeClientRoute(route);
|
|
15539
|
+
if (normalized.screen === "voice-input-usage") {
|
|
15540
|
+
return buildSettingsRoute();
|
|
15541
|
+
}
|
|
15127
15542
|
if (normalized.screen === "file-preview") {
|
|
15128
15543
|
// Source-aware File Preview routes return to their validated source first.
|
|
15129
15544
|
// Direct or invalid routes still fall back to the containing Explorer.
|
|
@@ -15184,6 +15599,7 @@ Waiting for Claude login output…</pre
|
|
|
15184
15599
|
const normalized = normalizeClientRoute(route);
|
|
15185
15600
|
return (
|
|
15186
15601
|
normalized.screen === "chat" ||
|
|
15602
|
+
normalized.screen === "voice-input-usage" ||
|
|
15187
15603
|
normalized.screen === "file-preview" ||
|
|
15188
15604
|
(normalized.screen === "mail" && Boolean(normalized.mailId)) ||
|
|
15189
15605
|
(normalized.screen === "folder-picker" &&
|
|
@@ -19213,12 +19629,13 @@ Waiting for Claude login output…</pre
|
|
|
19213
19629
|
entry,
|
|
19214
19630
|
providerId,
|
|
19215
19631
|
commandAvailable,
|
|
19632
|
+
authSupported,
|
|
19216
19633
|
canStartLogin
|
|
19217
19634
|
) {
|
|
19218
19635
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
19219
19636
|
return {
|
|
19220
19637
|
provider: providerId,
|
|
19221
|
-
supported:
|
|
19638
|
+
supported: authSupported,
|
|
19222
19639
|
canStartLogin,
|
|
19223
19640
|
state: "unknown",
|
|
19224
19641
|
message: "",
|
|
@@ -19316,6 +19733,7 @@ Waiting for Claude login output…</pre
|
|
|
19316
19733
|
entry.auth_status,
|
|
19317
19734
|
providerId,
|
|
19318
19735
|
entry.command_available === true,
|
|
19736
|
+
entry.auth_supported === true,
|
|
19319
19737
|
entry.auth_start_supported === true
|
|
19320
19738
|
),
|
|
19321
19739
|
modelCatalogStatus:
|
|
@@ -19426,6 +19844,20 @@ Waiting for Claude login output…</pre
|
|
|
19426
19844
|
return getProviderCatalogEntry(providerId)?.commandAvailable === true;
|
|
19427
19845
|
}
|
|
19428
19846
|
|
|
19847
|
+
function describeProviderCommandAvailability(providerId) {
|
|
19848
|
+
if (isProviderCatalogInitialPending()) {
|
|
19849
|
+
return "Checking availability on this Host...";
|
|
19850
|
+
}
|
|
19851
|
+
if (isProviderCatalogRequestFailed()) {
|
|
19852
|
+
return "Could not load availability. Retry the provider check.";
|
|
19853
|
+
}
|
|
19854
|
+
return isProviderAvailable(providerId)
|
|
19855
|
+
? "Available on this Host."
|
|
19856
|
+
: `Unavailable on this Host. Blank disables ${getProviderDisplayLabel(
|
|
19857
|
+
providerId
|
|
19858
|
+
)} explicitly.`;
|
|
19859
|
+
}
|
|
19860
|
+
|
|
19429
19861
|
function getProviderAuthStatus(providerId) {
|
|
19430
19862
|
return getProviderCatalogEntry(providerId)?.authStatus || null;
|
|
19431
19863
|
}
|
|
@@ -19441,6 +19873,7 @@ Waiting for Claude login output…</pre
|
|
|
19441
19873
|
nextStatus,
|
|
19442
19874
|
providerId,
|
|
19443
19875
|
entry.commandAvailable === true,
|
|
19876
|
+
entry.authSupported === true,
|
|
19444
19877
|
entry.authStartSupported === true
|
|
19445
19878
|
),
|
|
19446
19879
|
}
|
|
@@ -19478,7 +19911,12 @@ Waiting for Claude login output…</pre
|
|
|
19478
19911
|
function buildDefaultProviderWarning(
|
|
19479
19912
|
savedProvider = hostPreferencesState.defaultProvider
|
|
19480
19913
|
) {
|
|
19481
|
-
if (
|
|
19914
|
+
if (
|
|
19915
|
+
!savedProvider ||
|
|
19916
|
+
isProviderCatalogInitialPending() ||
|
|
19917
|
+
isProviderCatalogRequestFailed() ||
|
|
19918
|
+
isProviderAvailable(savedProvider)
|
|
19919
|
+
) {
|
|
19482
19920
|
return "";
|
|
19483
19921
|
}
|
|
19484
19922
|
const effectiveProvider =
|
|
@@ -21160,6 +21598,10 @@ Waiting for Claude login output…</pre
|
|
|
21160
21598
|
return normalizeClientRoute({ screen: "host-preferences" });
|
|
21161
21599
|
}
|
|
21162
21600
|
|
|
21601
|
+
function buildVoiceInputUsageRoute() {
|
|
21602
|
+
return normalizeClientRoute({ screen: "voice-input-usage" });
|
|
21603
|
+
}
|
|
21604
|
+
|
|
21163
21605
|
function buildChangePasswordRoute() {
|
|
21164
21606
|
return normalizeClientRoute({ screen: "change-password" });
|
|
21165
21607
|
}
|
|
@@ -21424,6 +21866,9 @@ Waiting for Claude login output…</pre
|
|
|
21424
21866
|
if (screen === "host-preferences") {
|
|
21425
21867
|
return { screen: "host-preferences", warning };
|
|
21426
21868
|
}
|
|
21869
|
+
if (screen === "voice-input-usage") {
|
|
21870
|
+
return { screen: "voice-input-usage", warning };
|
|
21871
|
+
}
|
|
21427
21872
|
if (screen === "change-password") {
|
|
21428
21873
|
return { screen: "change-password", warning };
|
|
21429
21874
|
}
|
|
@@ -21655,6 +22100,9 @@ Waiting for Claude login output…</pre
|
|
|
21655
22100
|
if (pathname === "/app/settings") {
|
|
21656
22101
|
return buildSettingsRoute();
|
|
21657
22102
|
}
|
|
22103
|
+
if (pathname === "/app/host-preferences/voice-input-usage") {
|
|
22104
|
+
return buildVoiceInputUsageRoute();
|
|
22105
|
+
}
|
|
21658
22106
|
if (pathname === "/app/change-password") {
|
|
21659
22107
|
return buildChangePasswordRoute();
|
|
21660
22108
|
}
|
|
@@ -21782,6 +22230,8 @@ Waiting for Claude login output…</pre
|
|
|
21782
22230
|
}
|
|
21783
22231
|
} else if (normalized.screen === "host-preferences") {
|
|
21784
22232
|
url.pathname = "/app/settings";
|
|
22233
|
+
} else if (normalized.screen === "voice-input-usage") {
|
|
22234
|
+
url.pathname = "/app/host-preferences/voice-input-usage";
|
|
21785
22235
|
} else if (normalized.screen === "change-password") {
|
|
21786
22236
|
url.pathname = "/app/change-password";
|
|
21787
22237
|
} else if (normalized.screen === "terminal") {
|
|
@@ -22013,6 +22463,12 @@ Waiting for Claude login output…</pre
|
|
|
22013
22463
|
}
|
|
22014
22464
|
} else if (normalized.screen === "host-preferences") {
|
|
22015
22465
|
renderHostPreferences();
|
|
22466
|
+
if (hostPreferencesState.voiceInputEnabled) {
|
|
22467
|
+
void loadHostVoiceInputUsage({ force: true });
|
|
22468
|
+
}
|
|
22469
|
+
} else if (normalized.screen === "voice-input-usage") {
|
|
22470
|
+
renderHostVoiceInputUsageDetail();
|
|
22471
|
+
await loadHostVoiceInputUsage();
|
|
22016
22472
|
} else if (normalized.screen === "change-password") {
|
|
22017
22473
|
renderChangePasswordView();
|
|
22018
22474
|
} else if (normalized.screen === "terminal") {
|
|
@@ -24974,6 +25430,7 @@ Waiting for Claude login output…</pre
|
|
|
24974
25430
|
explorer: "file_explorer",
|
|
24975
25431
|
"session-setup": "session_setup",
|
|
24976
25432
|
"host-preferences": "host_preferences",
|
|
25433
|
+
"voice-input-usage": "host_preferences",
|
|
24977
25434
|
terminal: "terminal",
|
|
24978
25435
|
"folder-picker": "file_explorer",
|
|
24979
25436
|
"file-preview": "file_preview",
|
|
@@ -26803,6 +27260,7 @@ Waiting for Claude login output…</pre
|
|
|
26803
27260
|
function renderAgentProfileWebsiteAccessRow(liveSession) {
|
|
26804
27261
|
syncAgentProfileWebsiteAccessSession(liveSession);
|
|
26805
27262
|
const website = getLiveSessionWebsite(liveSession);
|
|
27263
|
+
const websiteAuthorized = website?.browser_root_authorized === true;
|
|
26806
27264
|
const enabled = website?.enabled === true;
|
|
26807
27265
|
const access = normalizeAgentWebAccess(website?.access);
|
|
26808
27266
|
const websitePassword = getOwnerVisibleWebsitePassword(website);
|
|
@@ -26836,16 +27294,27 @@ Waiting for Claude login output…</pre
|
|
|
26836
27294
|
type="checkbox"
|
|
26837
27295
|
data-session-profile-web-enabled="web.enabled"
|
|
26838
27296
|
${enabled ? "checked" : ""}
|
|
26839
|
-
${saving ? "disabled" : ""}
|
|
27297
|
+
${saving || !websiteAuthorized ? "disabled" : ""}
|
|
26840
27298
|
/>
|
|
26841
27299
|
</label>
|
|
27300
|
+
${
|
|
27301
|
+
websiteAuthorized
|
|
27302
|
+
? ""
|
|
27303
|
+
: `<div
|
|
27304
|
+
class="field-hint field-warning"
|
|
27305
|
+
data-session-profile-website-authority="outside_browser_root"
|
|
27306
|
+
>${esc(
|
|
27307
|
+
website?.reason_message ||
|
|
27308
|
+
"Website is available only for agents in the Browser Root."
|
|
27309
|
+
)}</div>`
|
|
27310
|
+
}
|
|
26842
27311
|
<label class="field compact-field" for="agent-profile-website-access">
|
|
26843
27312
|
<span>Access</span>
|
|
26844
27313
|
<select
|
|
26845
27314
|
id="agent-profile-website-access"
|
|
26846
27315
|
data-session-profile-web-access="web.access"
|
|
26847
27316
|
onchange="window.syncAgentProfileWebsitePasswordMode && window.syncAgentProfileWebsitePasswordMode()"
|
|
26848
|
-
${saving ? "disabled" : ""}
|
|
27317
|
+
${saving || !websiteAuthorized ? "disabled" : ""}
|
|
26849
27318
|
>${renderAgentWebAccessOptions(access)}</select>
|
|
26850
27319
|
</label>
|
|
26851
27320
|
<label
|
|
@@ -26863,7 +27332,11 @@ Waiting for Claude login output…</pre
|
|
|
26863
27332
|
value="${esc(websitePassword)}"
|
|
26864
27333
|
data-session-profile-web-local="web.password"
|
|
26865
27334
|
oninput="window.syncAgentProfileWebsitePasswordMode && window.syncAgentProfileWebsitePasswordMode()"
|
|
26866
|
-
${
|
|
27335
|
+
${
|
|
27336
|
+
access === "password" && !saving && websiteAuthorized
|
|
27337
|
+
? ""
|
|
27338
|
+
: "disabled"
|
|
27339
|
+
}
|
|
26867
27340
|
/>
|
|
26868
27341
|
<div
|
|
26869
27342
|
id="agent-profile-website-password-status"
|
|
@@ -26895,7 +27368,7 @@ Waiting for Claude login output…</pre
|
|
|
26895
27368
|
data-session-profile-save="website"
|
|
26896
27369
|
data-session-profile-web-access-save="explicit"
|
|
26897
27370
|
onclick="window.saveAgentProfileWebsiteAccess && window.saveAgentProfileWebsiteAccess()"
|
|
26898
|
-
${saving ? "disabled" : ""}
|
|
27371
|
+
${saving || !websiteAuthorized ? "disabled" : ""}
|
|
26899
27372
|
>${saving ? "Saving..." : "Save"}</button>
|
|
26900
27373
|
</div>
|
|
26901
27374
|
${
|
|
@@ -26914,6 +27387,9 @@ Waiting for Claude login output…</pre
|
|
|
26914
27387
|
}
|
|
26915
27388
|
|
|
26916
27389
|
function syncAgentProfileWebsitePasswordMode() {
|
|
27390
|
+
const liveSession = getSelectedLiveSession();
|
|
27391
|
+
const websiteAuthorized =
|
|
27392
|
+
getLiveSessionWebsite(liveSession)?.browser_root_authorized === true;
|
|
26917
27393
|
const access = normalizeAgentWebAccess(
|
|
26918
27394
|
$("agent-profile-website-access")?.value
|
|
26919
27395
|
);
|
|
@@ -26923,13 +27399,12 @@ Waiting for Claude login output…</pre
|
|
|
26923
27399
|
const passwordMode = access === "password";
|
|
26924
27400
|
if (row) row.classList.remove("hidden");
|
|
26925
27401
|
if (input) {
|
|
26926
|
-
input.disabled = !passwordMode;
|
|
27402
|
+
input.disabled = !websiteAuthorized || !passwordMode;
|
|
26927
27403
|
}
|
|
26928
27404
|
if (status) {
|
|
26929
|
-
status.textContent =
|
|
26930
|
-
access,
|
|
26931
|
-
|
|
26932
|
-
);
|
|
27405
|
+
status.textContent = websiteAuthorized
|
|
27406
|
+
? formatOwnerWebsitePasswordHint(access, input?.value || "")
|
|
27407
|
+
: "Website is available only for agents in the Browser Root.";
|
|
26933
27408
|
}
|
|
26934
27409
|
}
|
|
26935
27410
|
|
|
@@ -26938,6 +27413,19 @@ Waiting for Claude login output…</pre
|
|
|
26938
27413
|
if (!liveSession?.sessionId) return;
|
|
26939
27414
|
syncAgentProfileWebsiteAccessSession(liveSession);
|
|
26940
27415
|
if (agentProfileWebsiteAccessState.saving === true) return;
|
|
27416
|
+
const previousWebsite = getLiveSessionWebsite(liveSession);
|
|
27417
|
+
if (previousWebsite?.browser_root_authorized !== true) {
|
|
27418
|
+
agentProfileWebsiteAccessState = {
|
|
27419
|
+
...agentProfileWebsiteAccessState,
|
|
27420
|
+
saving: false,
|
|
27421
|
+
error:
|
|
27422
|
+
previousWebsite?.reason_message ||
|
|
27423
|
+
"Website is available only for agents in the Browser Root.",
|
|
27424
|
+
status: "",
|
|
27425
|
+
};
|
|
27426
|
+
renderAgentProfileView();
|
|
27427
|
+
return;
|
|
27428
|
+
}
|
|
26941
27429
|
const select = $("agent-profile-website-access");
|
|
26942
27430
|
const updateConfig = true;
|
|
26943
27431
|
const nextEnabled =
|
|
@@ -26947,7 +27435,6 @@ Waiting for Claude login output…</pre
|
|
|
26947
27435
|
nextAccess === "password"
|
|
26948
27436
|
? String($("agent-profile-website-password")?.value || "").trim()
|
|
26949
27437
|
: "";
|
|
26950
|
-
const previousWebsite = getLiveSessionWebsite(liveSession);
|
|
26951
27438
|
if (nextAccess === "password" && !nextWebsitePassword) {
|
|
26952
27439
|
agentProfileWebsiteAccessState = {
|
|
26953
27440
|
...agentProfileWebsiteAccessState,
|
|
@@ -29566,6 +30053,12 @@ Waiting for Claude login output…</pre
|
|
|
29566
30053
|
subtitle: "",
|
|
29567
30054
|
};
|
|
29568
30055
|
}
|
|
30056
|
+
if (screen === "voice-input-usage") {
|
|
30057
|
+
return {
|
|
30058
|
+
title: "Voice Input Usage",
|
|
30059
|
+
subtitle: "",
|
|
30060
|
+
};
|
|
30061
|
+
}
|
|
29569
30062
|
if (screen === "change-password") {
|
|
29570
30063
|
return {
|
|
29571
30064
|
title: "Change Password",
|
|
@@ -29926,6 +30419,10 @@ Waiting for Claude login output…</pre
|
|
|
29926
30419
|
"active",
|
|
29927
30420
|
screen === "host-preferences"
|
|
29928
30421
|
);
|
|
30422
|
+
$("voice-input-usage-view").classList.toggle(
|
|
30423
|
+
"active",
|
|
30424
|
+
screen === "voice-input-usage"
|
|
30425
|
+
);
|
|
29929
30426
|
$("change-password-view").classList.toggle(
|
|
29930
30427
|
"active",
|
|
29931
30428
|
screen === "change-password"
|
|
@@ -29979,6 +30476,14 @@ Waiting for Claude login output…</pre
|
|
|
29979
30476
|
}
|
|
29980
30477
|
if (screen === "host-preferences") {
|
|
29981
30478
|
renderHostPreferences();
|
|
30479
|
+
} else if (
|
|
30480
|
+
hostPreferencesState.voiceInputSampleLoaded ||
|
|
30481
|
+
hostVoiceInputSampleObjectUrl
|
|
30482
|
+
) {
|
|
30483
|
+
releaseHostVoiceInputSampleAudio();
|
|
30484
|
+
}
|
|
30485
|
+
if (screen === "voice-input-usage") {
|
|
30486
|
+
renderHostVoiceInputUsageDetail();
|
|
29982
30487
|
}
|
|
29983
30488
|
if (screen === "change-password") {
|
|
29984
30489
|
renderChangePasswordView();
|
|
@@ -30008,6 +30513,10 @@ Waiting for Claude login output…</pre
|
|
|
30008
30513
|
void navigateToRoute(buildSettingsRoute());
|
|
30009
30514
|
return;
|
|
30010
30515
|
}
|
|
30516
|
+
if (entry.screen === "voice-input-usage") {
|
|
30517
|
+
void navigateToRoute(buildVoiceInputUsageRoute());
|
|
30518
|
+
return;
|
|
30519
|
+
}
|
|
30011
30520
|
if (entry.screen === "change-password") {
|
|
30012
30521
|
void navigateToRoute(buildChangePasswordRoute());
|
|
30013
30522
|
return;
|
|
@@ -34274,6 +34783,11 @@ Waiting for Claude login output…</pre
|
|
|
34274
34783
|
const notificationSoundAppEnabled =
|
|
34275
34784
|
data.notification_sound_app_enabled !== false;
|
|
34276
34785
|
const dailyTelemetryEnabled = data.daily_telemetry_enabled === true;
|
|
34786
|
+
const voiceInput =
|
|
34787
|
+
data.voice_input && typeof data.voice_input === "object"
|
|
34788
|
+
? data.voice_input
|
|
34789
|
+
: {};
|
|
34790
|
+
const voiceInputEnabled = voiceInput.enabled === true;
|
|
34277
34791
|
const debugShowCapabilityUi = data.debug_show_capability_ui === true;
|
|
34278
34792
|
const showInterfaceStyleInSessionSetupProfile =
|
|
34279
34793
|
data.show_interface_style_in_session_setup_profile === true;
|
|
@@ -34310,6 +34824,7 @@ Waiting for Claude login output…</pre
|
|
|
34310
34824
|
notificationSoundWebEnabled,
|
|
34311
34825
|
notificationSoundAppEnabled,
|
|
34312
34826
|
dailyTelemetryEnabled,
|
|
34827
|
+
voiceInputEnabled,
|
|
34313
34828
|
defaultWebsiteAccess: normalizeAgentWebAccess(webDefaults.access),
|
|
34314
34829
|
defaultNotificationsEnabled: notificationDefaults.enabled !== false,
|
|
34315
34830
|
defaultRuntimeCapabilities: runtimeCapabilityDefaults,
|
|
@@ -34366,6 +34881,42 @@ Waiting for Claude login output…</pre
|
|
|
34366
34881
|
: "",
|
|
34367
34882
|
dailyTelemetryHostIdPresent:
|
|
34368
34883
|
data.daily_telemetry_host_id_present === true,
|
|
34884
|
+
voiceInputEnabled,
|
|
34885
|
+
voiceInputAvailable: voiceInput.available === true,
|
|
34886
|
+
voiceInputCanEnable: voiceInput.can_enable === true,
|
|
34887
|
+
voiceInputTokenConfigured: voiceInput.token_configured === true,
|
|
34888
|
+
voiceInputTokenValidated: voiceInput.token_validated === true,
|
|
34889
|
+
voiceInputTokenMasked:
|
|
34890
|
+
typeof voiceInput.token_masked === "string"
|
|
34891
|
+
? voiceInput.token_masked
|
|
34892
|
+
: "",
|
|
34893
|
+
voiceInputTokenDraft: "",
|
|
34894
|
+
voiceInputValidatedAt:
|
|
34895
|
+
typeof voiceInput.validated_at === "string"
|
|
34896
|
+
? voiceInput.validated_at
|
|
34897
|
+
: "",
|
|
34898
|
+
voiceInputValidatedModel:
|
|
34899
|
+
typeof voiceInput.validated_model === "string"
|
|
34900
|
+
? voiceInput.validated_model
|
|
34901
|
+
: "",
|
|
34902
|
+
voiceInputValidatedSampleExact:
|
|
34903
|
+
typeof voiceInput.validated_sample_exact === "boolean"
|
|
34904
|
+
? voiceInput.validated_sample_exact
|
|
34905
|
+
: null,
|
|
34906
|
+
voiceInputModel:
|
|
34907
|
+
typeof voiceInput.model === "string"
|
|
34908
|
+
? voiceInput.model
|
|
34909
|
+
: "gpt-4o-transcribe",
|
|
34910
|
+
voiceInputSampleExpected:
|
|
34911
|
+
typeof voiceInput.sample_expected === "string"
|
|
34912
|
+
? voiceInput.sample_expected
|
|
34913
|
+
: "How much money can I withdraw per day from the ATM?",
|
|
34914
|
+
voiceInputTestRunning: false,
|
|
34915
|
+
voiceInputTokenClearing: false,
|
|
34916
|
+
voiceInputTestStatus: "",
|
|
34917
|
+
voiceInputTestError: "",
|
|
34918
|
+
voiceInputTestTranscript: "",
|
|
34919
|
+
voiceInputTestLatencyMs: null,
|
|
34369
34920
|
defaultWebsiteAccess: normalizeAgentWebAccess(webDefaults.access),
|
|
34370
34921
|
defaultNotificationsEnabled: notificationDefaults.enabled !== false,
|
|
34371
34922
|
defaultRuntimeCapabilities: runtimeCapabilityDefaults,
|
|
@@ -34455,17 +35006,6 @@ Waiting for Claude login output…</pre
|
|
|
34455
35006
|
});
|
|
34456
35007
|
syncSessionSetupInterfaceStyleVisibility();
|
|
34457
35008
|
renderCreateTelegramFeatureVisibility();
|
|
34458
|
-
if (!providerCatalogState.loaded) {
|
|
34459
|
-
providerCatalogState = {
|
|
34460
|
-
...providerCatalogState,
|
|
34461
|
-
providers: KNOWN_PROVIDER_ORDER.map((providerId) => ({
|
|
34462
|
-
id: providerId,
|
|
34463
|
-
label: getProviderDisplayLabel(providerId),
|
|
34464
|
-
commandAvailable: false,
|
|
34465
|
-
runtimeSupported: true,
|
|
34466
|
-
})),
|
|
34467
|
-
};
|
|
34468
|
-
}
|
|
34469
35009
|
renderHostPreferences();
|
|
34470
35010
|
setCreateRuntime(getEffectiveCreateRuntime(createRuntime), {
|
|
34471
35011
|
preserveSelection: true,
|
|
@@ -34477,11 +35017,18 @@ Waiting for Claude login output…</pre
|
|
|
34477
35017
|
const normalizedProviders = Array.isArray(data?.providers)
|
|
34478
35018
|
? data.providers.map(normalizeProviderCatalogEntry).filter(Boolean)
|
|
34479
35019
|
: [];
|
|
35020
|
+
const providers = normalizedProviders.map((entry) => {
|
|
35021
|
+
const currentEntry = getProviderCatalogEntry(entry.id);
|
|
35022
|
+
return currentEntry?.authStatus?.checkedAt
|
|
35023
|
+
? { ...entry, authStatus: currentEntry.authStatus }
|
|
35024
|
+
: entry;
|
|
35025
|
+
});
|
|
34480
35026
|
providerCatalogState = {
|
|
35027
|
+
status: getProviderCatalogStatusForProviders(providers),
|
|
34481
35028
|
loaded: true,
|
|
34482
35029
|
loading: false,
|
|
34483
35030
|
error: "",
|
|
34484
|
-
providers
|
|
35031
|
+
providers,
|
|
34485
35032
|
};
|
|
34486
35033
|
hostPreferencesState = {
|
|
34487
35034
|
...hostPreferencesState,
|
|
@@ -34502,36 +35049,50 @@ Waiting for Claude login output…</pre
|
|
|
34502
35049
|
});
|
|
34503
35050
|
}
|
|
34504
35051
|
|
|
34505
|
-
|
|
34506
|
-
if (
|
|
35052
|
+
function loadProviderCatalog(opts = {}) {
|
|
35053
|
+
if (providerCatalogLoadPromise) return providerCatalogLoadPromise;
|
|
34507
35054
|
providerCatalogState = {
|
|
34508
35055
|
...providerCatalogState,
|
|
35056
|
+
status: providerCatalogState.loaded
|
|
35057
|
+
? providerCatalogState.status
|
|
35058
|
+
: PROVIDER_CATALOG_STATUS_PENDING,
|
|
34509
35059
|
loading: true,
|
|
34510
35060
|
error: "",
|
|
34511
35061
|
};
|
|
34512
35062
|
renderHostPreferences();
|
|
34513
|
-
|
|
34514
|
-
|
|
34515
|
-
|
|
34516
|
-
|
|
34517
|
-
|
|
34518
|
-
|
|
34519
|
-
|
|
34520
|
-
|
|
34521
|
-
|
|
34522
|
-
|
|
34523
|
-
|
|
34524
|
-
|
|
34525
|
-
|
|
34526
|
-
|
|
34527
|
-
|
|
35063
|
+
renderCreateRuntimeAvailability();
|
|
35064
|
+
providerCatalogLoadPromise = (async () => {
|
|
35065
|
+
try {
|
|
35066
|
+
const data = await readDashboardProviderCatalog({
|
|
35067
|
+
force: opts.force === true,
|
|
35068
|
+
});
|
|
35069
|
+
applyProviderCatalogData(data);
|
|
35070
|
+
return data;
|
|
35071
|
+
} catch (err) {
|
|
35072
|
+
if (await handleHostPreferencesAuthFailure(err)) return null;
|
|
35073
|
+
providerCatalogState = {
|
|
35074
|
+
...providerCatalogState,
|
|
35075
|
+
status: providerCatalogState.loaded
|
|
35076
|
+
? providerCatalogState.status
|
|
35077
|
+
: PROVIDER_CATALOG_STATUS_REQUEST_FAILED,
|
|
35078
|
+
loading: false,
|
|
35079
|
+
error: err.message || "Could not load provider availability.",
|
|
35080
|
+
};
|
|
35081
|
+
renderHostPreferences();
|
|
35082
|
+
renderCreateRuntimeAvailability();
|
|
35083
|
+
if (opts.quiet !== true) {
|
|
35084
|
+
showBanner(providerCatalogState.error, true);
|
|
35085
|
+
}
|
|
35086
|
+
return null;
|
|
35087
|
+
} finally {
|
|
35088
|
+
providerCatalogLoadPromise = null;
|
|
34528
35089
|
}
|
|
34529
|
-
}
|
|
35090
|
+
})();
|
|
35091
|
+
return providerCatalogLoadPromise;
|
|
34530
35092
|
}
|
|
34531
35093
|
|
|
34532
35094
|
function retryHostPreferencesProviderSection() {
|
|
34533
|
-
|
|
34534
|
-
void loadProviderCatalog({ force: true, quiet: true });
|
|
35095
|
+
return loadProviderCatalog({ force: true, quiet: true });
|
|
34535
35096
|
}
|
|
34536
35097
|
|
|
34537
35098
|
function clearProviderAuthJobPollTimer() {
|
|
@@ -34703,7 +35264,6 @@ Waiting for Claude login output…</pre
|
|
|
34703
35264
|
? response.provider.trim()
|
|
34704
35265
|
: "claude";
|
|
34705
35266
|
if (response.provider_auth) {
|
|
34706
|
-
invalidateDashboardDataCaches({ providers: true });
|
|
34707
35267
|
setProviderCatalogAuthStatus(providerId, response.provider_auth);
|
|
34708
35268
|
}
|
|
34709
35269
|
providerAuthModalState = {
|
|
@@ -34715,6 +35275,7 @@ Waiting for Claude login output…</pre
|
|
|
34715
35275
|
response.provider_auth,
|
|
34716
35276
|
providerId,
|
|
34717
35277
|
getProviderCatalogEntry(providerId)?.commandAvailable === true,
|
|
35278
|
+
getProviderCatalogEntry(providerId)?.authSupported === true,
|
|
34718
35279
|
getProviderCatalogEntry(providerId)?.authStartSupported === true
|
|
34719
35280
|
)
|
|
34720
35281
|
: getProviderAuthStatus(providerId),
|
|
@@ -34786,13 +35347,13 @@ Waiting for Claude login output…</pre
|
|
|
34786
35347
|
"GET",
|
|
34787
35348
|
`/provider-auth/status?provider=${encodeURIComponent(providerId)}`
|
|
34788
35349
|
);
|
|
34789
|
-
invalidateDashboardDataCaches({ providers: true });
|
|
34790
35350
|
setProviderCatalogAuthStatus(providerId, data.provider_auth || null);
|
|
34791
35351
|
if (providerAuthModalState.provider === providerId) {
|
|
34792
35352
|
const normalizedStatus = normalizeProviderAuthStatus(
|
|
34793
35353
|
data.provider_auth,
|
|
34794
35354
|
providerId,
|
|
34795
35355
|
getProviderCatalogEntry(providerId)?.commandAvailable === true,
|
|
35356
|
+
getProviderCatalogEntry(providerId)?.authSupported === true,
|
|
34796
35357
|
getProviderCatalogEntry(providerId)?.authStartSupported === true
|
|
34797
35358
|
);
|
|
34798
35359
|
providerAuthModalState = {
|
|
@@ -34961,6 +35522,7 @@ Waiting for Claude login output…</pre
|
|
|
34961
35522
|
data.provider_auth,
|
|
34962
35523
|
providerId,
|
|
34963
35524
|
getProviderCatalogEntry(providerId)?.commandAvailable === true,
|
|
35525
|
+
getProviderCatalogEntry(providerId)?.authSupported === true,
|
|
34964
35526
|
getProviderCatalogEntry(providerId)?.authStartSupported === true
|
|
34965
35527
|
),
|
|
34966
35528
|
job,
|
|
@@ -35646,7 +36208,11 @@ Waiting for Claude login output…</pre
|
|
|
35646
36208
|
if (!availableProviderIds.length) {
|
|
35647
36209
|
const option = document.createElement("option");
|
|
35648
36210
|
option.value = "";
|
|
35649
|
-
option.textContent =
|
|
36211
|
+
option.textContent = isProviderCatalogInitialPending()
|
|
36212
|
+
? "Checking providers..."
|
|
36213
|
+
: isProviderCatalogRequestFailed()
|
|
36214
|
+
? "Provider status unavailable"
|
|
36215
|
+
: "No available providers";
|
|
35650
36216
|
option.disabled = true;
|
|
35651
36217
|
option.selected = true;
|
|
35652
36218
|
select.appendChild(option);
|
|
@@ -35695,6 +36261,8 @@ Waiting for Claude login output…</pre
|
|
|
35695
36261
|
);
|
|
35696
36262
|
const runtimeLocked =
|
|
35697
36263
|
isResumeMode() && Boolean(pendingResumeSourceRuntime);
|
|
36264
|
+
const providerCatalogPending = isProviderCatalogInitialPending();
|
|
36265
|
+
const providerCatalogFailed = isProviderCatalogRequestFailed();
|
|
35698
36266
|
setVisible("runtime-claude", claudeVisible);
|
|
35699
36267
|
setVisible("runtime-codex", codexVisible);
|
|
35700
36268
|
setVisible("runtime-debug-fixture", debugFixtureVisible);
|
|
@@ -35740,6 +36308,26 @@ Waiting for Claude login output…</pre
|
|
|
35740
36308
|
}
|
|
35741
36309
|
refreshCreateStartButtonEnabled();
|
|
35742
36310
|
applyCreateSessionSetupProofAttributes();
|
|
36311
|
+
setVisible("create-provider-retry-btn", providerCatalogFailed);
|
|
36312
|
+
$("create-provider-retry-btn")?.toggleAttribute(
|
|
36313
|
+
"disabled",
|
|
36314
|
+
providerCatalogState.loading
|
|
36315
|
+
);
|
|
36316
|
+
if (providerCatalogPending || providerCatalogFailed) {
|
|
36317
|
+
if (modelSelect) {
|
|
36318
|
+
modelSelect.innerHTML = "";
|
|
36319
|
+
modelSelect.disabled = true;
|
|
36320
|
+
}
|
|
36321
|
+
$("claude-options").classList.add("hidden");
|
|
36322
|
+
$("codex-options").classList.add("hidden");
|
|
36323
|
+
if (runtimeHintEl) {
|
|
36324
|
+
runtimeHintEl.textContent = providerCatalogFailed
|
|
36325
|
+
? "Could not load provider status. Retry the provider check."
|
|
36326
|
+
: "Checking providers...";
|
|
36327
|
+
}
|
|
36328
|
+
renderCreateProviderAuthCard();
|
|
36329
|
+
return;
|
|
36330
|
+
}
|
|
35743
36331
|
if (!visibleProviderIds.length) {
|
|
35744
36332
|
if (modelSelect) {
|
|
35745
36333
|
modelSelect.innerHTML = "";
|
|
@@ -35894,6 +36482,711 @@ Waiting for Claude login output…</pre
|
|
|
35894
36482
|
};
|
|
35895
36483
|
}
|
|
35896
36484
|
|
|
36485
|
+
function getHostVoiceInputEnabledControlValue() {
|
|
36486
|
+
return (
|
|
36487
|
+
$("host-voice-input-enabled-toggle")?.getAttribute("aria-checked") ===
|
|
36488
|
+
"true"
|
|
36489
|
+
);
|
|
36490
|
+
}
|
|
36491
|
+
|
|
36492
|
+
function setHostVoiceInputEnabledControlValue(enabled) {
|
|
36493
|
+
const toggle = $("host-voice-input-enabled-toggle");
|
|
36494
|
+
if (!toggle) return;
|
|
36495
|
+
toggle.setAttribute("aria-checked", enabled ? "true" : "false");
|
|
36496
|
+
}
|
|
36497
|
+
|
|
36498
|
+
function isHostVoiceInputTokenCandidateTestable(value) {
|
|
36499
|
+
return typeof value === "string" && value.trim().length >= 10;
|
|
36500
|
+
}
|
|
36501
|
+
|
|
36502
|
+
const OYSTERUN_VOICE_INPUT_MINIMUM_NATIVE_APP_VERSION = "1.6.0";
|
|
36503
|
+
|
|
36504
|
+
function parseOysterunNumericVersion(value) {
|
|
36505
|
+
const match = String(value || "")
|
|
36506
|
+
.trim()
|
|
36507
|
+
.match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?$/);
|
|
36508
|
+
if (!match) return null;
|
|
36509
|
+
return [
|
|
36510
|
+
Number.parseInt(match[1], 10),
|
|
36511
|
+
Number.parseInt(match[2] || "0", 10),
|
|
36512
|
+
Number.parseInt(match[3] || "0", 10),
|
|
36513
|
+
];
|
|
36514
|
+
}
|
|
36515
|
+
|
|
36516
|
+
function isOysterunVersionBefore(value, minimum) {
|
|
36517
|
+
const version = parseOysterunNumericVersion(value);
|
|
36518
|
+
const required = parseOysterunNumericVersion(minimum);
|
|
36519
|
+
if (!version || !required) return false;
|
|
36520
|
+
for (let index = 0; index < required.length; index += 1) {
|
|
36521
|
+
if (version[index] < required[index]) return true;
|
|
36522
|
+
if (version[index] > required[index]) return false;
|
|
36523
|
+
}
|
|
36524
|
+
return false;
|
|
36525
|
+
}
|
|
36526
|
+
|
|
36527
|
+
async function loadHostVoiceInputNativeAppVersion() {
|
|
36528
|
+
if (!isOysterunCapacitorIOSRuntime()) {
|
|
36529
|
+
hostPreferencesState = {
|
|
36530
|
+
...hostPreferencesState,
|
|
36531
|
+
voiceInputNativeAppVersion: "",
|
|
36532
|
+
voiceInputNativeAppVersionLoaded: true,
|
|
36533
|
+
};
|
|
36534
|
+
return;
|
|
36535
|
+
}
|
|
36536
|
+
if (hostPreferencesState.voiceInputNativeAppVersionLoaded) return;
|
|
36537
|
+
if (hostVoiceInputNativeAppVersionLoadPromise) {
|
|
36538
|
+
return hostVoiceInputNativeAppVersionLoadPromise;
|
|
36539
|
+
}
|
|
36540
|
+
hostVoiceInputNativeAppVersionLoadPromise = (async () => {
|
|
36541
|
+
let version = "";
|
|
36542
|
+
const plugin = getOysterunCapacitorAppPlugin();
|
|
36543
|
+
if (plugin) {
|
|
36544
|
+
try {
|
|
36545
|
+
const appInfo = await plugin.getInfo();
|
|
36546
|
+
version =
|
|
36547
|
+
typeof appInfo?.version === "string"
|
|
36548
|
+
? appInfo.version.trim()
|
|
36549
|
+
: "";
|
|
36550
|
+
} catch (err) {
|
|
36551
|
+
console.warn(
|
|
36552
|
+
"[oysterun-voice-input] native app version unavailable",
|
|
36553
|
+
err
|
|
36554
|
+
);
|
|
36555
|
+
}
|
|
36556
|
+
}
|
|
36557
|
+
hostPreferencesState = {
|
|
36558
|
+
...hostPreferencesState,
|
|
36559
|
+
voiceInputNativeAppVersion: version,
|
|
36560
|
+
voiceInputNativeAppVersionLoaded: true,
|
|
36561
|
+
};
|
|
36562
|
+
if (getCurrentScreen() === "host-preferences") {
|
|
36563
|
+
renderHostVoiceInputPreferences({
|
|
36564
|
+
disabled:
|
|
36565
|
+
hostPreferencesState.loading || hostPreferencesState.saving,
|
|
36566
|
+
});
|
|
36567
|
+
}
|
|
36568
|
+
})().finally(() => {
|
|
36569
|
+
hostVoiceInputNativeAppVersionLoadPromise = null;
|
|
36570
|
+
});
|
|
36571
|
+
return hostVoiceInputNativeAppVersionLoadPromise;
|
|
36572
|
+
}
|
|
36573
|
+
|
|
36574
|
+
function getHostVoiceInputClientWarning() {
|
|
36575
|
+
if (isOysterunCapacitorIOSRuntime()) {
|
|
36576
|
+
const appVersion =
|
|
36577
|
+
hostPreferencesState.voiceInputNativeAppVersion || "";
|
|
36578
|
+
if (
|
|
36579
|
+
hostPreferencesState.voiceInputNativeAppVersionLoaded &&
|
|
36580
|
+
isOysterunVersionBefore(
|
|
36581
|
+
appVersion,
|
|
36582
|
+
OYSTERUN_VOICE_INPUT_MINIMUM_NATIVE_APP_VERSION
|
|
36583
|
+
)
|
|
36584
|
+
) {
|
|
36585
|
+
return `Voice Input recording requires Oysterun App 1.6 or newer. This App is ${appVersion}. Update the App before using this feature.`;
|
|
36586
|
+
}
|
|
36587
|
+
const capacitor = window.Capacitor;
|
|
36588
|
+
if (
|
|
36589
|
+
typeof capacitor?.isPluginAvailable === "function" &&
|
|
36590
|
+
capacitor.isPluginAvailable("OysterunVoiceRecorder")
|
|
36591
|
+
) {
|
|
36592
|
+
return "";
|
|
36593
|
+
}
|
|
36594
|
+
return "This Oysterun app build does not include native voice recording. Token testing remains available here.";
|
|
36595
|
+
}
|
|
36596
|
+
if (window.isSecureContext !== true) {
|
|
36597
|
+
return "Microphone recording requires HTTPS or a supported native app. Token testing remains available here.";
|
|
36598
|
+
}
|
|
36599
|
+
if (!navigator.mediaDevices?.getUserMedia) {
|
|
36600
|
+
return "This browser does not expose microphone recording. Token testing remains available here.";
|
|
36601
|
+
}
|
|
36602
|
+
if (typeof MediaRecorder === "undefined") {
|
|
36603
|
+
return "This browser does not support the required recorder. Token testing remains available here.";
|
|
36604
|
+
}
|
|
36605
|
+
return "";
|
|
36606
|
+
}
|
|
36607
|
+
|
|
36608
|
+
function applyHostVoiceInputStatusPayload(
|
|
36609
|
+
voiceInput,
|
|
36610
|
+
{ syncSavedDraft = true } = {}
|
|
36611
|
+
) {
|
|
36612
|
+
if (!voiceInput || typeof voiceInput !== "object") return;
|
|
36613
|
+
const voiceInputEnabled = voiceInput.enabled === true;
|
|
36614
|
+
hostPreferencesState = {
|
|
36615
|
+
...hostPreferencesState,
|
|
36616
|
+
voiceInputEnabled,
|
|
36617
|
+
voiceInputAvailable: voiceInput.available === true,
|
|
36618
|
+
voiceInputCanEnable: voiceInput.can_enable === true,
|
|
36619
|
+
voiceInputTokenConfigured: voiceInput.token_configured === true,
|
|
36620
|
+
voiceInputTokenValidated: voiceInput.token_validated === true,
|
|
36621
|
+
voiceInputTokenMasked:
|
|
36622
|
+
typeof voiceInput.token_masked === "string"
|
|
36623
|
+
? voiceInput.token_masked
|
|
36624
|
+
: "",
|
|
36625
|
+
voiceInputValidatedAt:
|
|
36626
|
+
typeof voiceInput.validated_at === "string"
|
|
36627
|
+
? voiceInput.validated_at
|
|
36628
|
+
: "",
|
|
36629
|
+
voiceInputValidatedModel:
|
|
36630
|
+
typeof voiceInput.validated_model === "string"
|
|
36631
|
+
? voiceInput.validated_model
|
|
36632
|
+
: "",
|
|
36633
|
+
voiceInputValidatedSampleExact:
|
|
36634
|
+
typeof voiceInput.validated_sample_exact === "boolean"
|
|
36635
|
+
? voiceInput.validated_sample_exact
|
|
36636
|
+
: null,
|
|
36637
|
+
voiceInputModel:
|
|
36638
|
+
typeof voiceInput.model === "string"
|
|
36639
|
+
? voiceInput.model
|
|
36640
|
+
: hostPreferencesState.voiceInputModel,
|
|
36641
|
+
voiceInputSampleExpected:
|
|
36642
|
+
typeof voiceInput.sample_expected === "string"
|
|
36643
|
+
? voiceInput.sample_expected
|
|
36644
|
+
: hostPreferencesState.voiceInputSampleExpected,
|
|
36645
|
+
...(syncSavedDraft
|
|
36646
|
+
? {
|
|
36647
|
+
savedDraft: {
|
|
36648
|
+
...(hostPreferencesState.savedDraft ||
|
|
36649
|
+
buildHostPreferencesDraft()),
|
|
36650
|
+
voiceInputEnabled,
|
|
36651
|
+
},
|
|
36652
|
+
}
|
|
36653
|
+
: {}),
|
|
36654
|
+
};
|
|
36655
|
+
}
|
|
36656
|
+
|
|
36657
|
+
function releaseHostVoiceInputSampleAudio() {
|
|
36658
|
+
const player = $("host-voice-input-sample-player");
|
|
36659
|
+
if (player) {
|
|
36660
|
+
player.pause();
|
|
36661
|
+
player.removeAttribute("src");
|
|
36662
|
+
player.load();
|
|
36663
|
+
}
|
|
36664
|
+
if (hostVoiceInputSampleObjectUrl) {
|
|
36665
|
+
URL.revokeObjectURL(hostVoiceInputSampleObjectUrl);
|
|
36666
|
+
hostVoiceInputSampleObjectUrl = "";
|
|
36667
|
+
}
|
|
36668
|
+
hostVoiceInputSampleLoadPromise = null;
|
|
36669
|
+
hostPreferencesState = {
|
|
36670
|
+
...hostPreferencesState,
|
|
36671
|
+
voiceInputSampleLoading: false,
|
|
36672
|
+
voiceInputSampleLoaded: false,
|
|
36673
|
+
voiceInputSampleError: "",
|
|
36674
|
+
};
|
|
36675
|
+
}
|
|
36676
|
+
|
|
36677
|
+
function ensureHostVoiceInputSampleAudio() {
|
|
36678
|
+
if (
|
|
36679
|
+
hostPreferencesState.voiceInputSampleLoaded ||
|
|
36680
|
+
hostVoiceInputSampleLoadPromise
|
|
36681
|
+
) {
|
|
36682
|
+
return hostVoiceInputSampleLoadPromise || Promise.resolve();
|
|
36683
|
+
}
|
|
36684
|
+
hostPreferencesState = {
|
|
36685
|
+
...hostPreferencesState,
|
|
36686
|
+
voiceInputSampleLoading: true,
|
|
36687
|
+
voiceInputSampleError: "",
|
|
36688
|
+
};
|
|
36689
|
+
hostVoiceInputSampleLoadPromise = (async () => {
|
|
36690
|
+
try {
|
|
36691
|
+
const response = await apiRawWithAuthRetry(
|
|
36692
|
+
"GET",
|
|
36693
|
+
"/dev/preferences/voice-input/sample"
|
|
36694
|
+
);
|
|
36695
|
+
const blob = await response.blob();
|
|
36696
|
+
if (!blob.size) {
|
|
36697
|
+
throw new Error("Voice Input sample audio is empty.");
|
|
36698
|
+
}
|
|
36699
|
+
if (hostVoiceInputSampleObjectUrl) {
|
|
36700
|
+
URL.revokeObjectURL(hostVoiceInputSampleObjectUrl);
|
|
36701
|
+
}
|
|
36702
|
+
hostVoiceInputSampleObjectUrl = URL.createObjectURL(blob);
|
|
36703
|
+
hostPreferencesState = {
|
|
36704
|
+
...hostPreferencesState,
|
|
36705
|
+
voiceInputSampleLoading: false,
|
|
36706
|
+
voiceInputSampleLoaded: true,
|
|
36707
|
+
voiceInputSampleError: "",
|
|
36708
|
+
};
|
|
36709
|
+
} catch (err) {
|
|
36710
|
+
if (await handleHostPreferencesAuthFailure(err)) return;
|
|
36711
|
+
hostPreferencesState = {
|
|
36712
|
+
...hostPreferencesState,
|
|
36713
|
+
voiceInputSampleLoading: false,
|
|
36714
|
+
voiceInputSampleLoaded: false,
|
|
36715
|
+
voiceInputSampleError:
|
|
36716
|
+
err.message || "Could not load Voice Input sample audio.",
|
|
36717
|
+
};
|
|
36718
|
+
} finally {
|
|
36719
|
+
hostVoiceInputSampleLoadPromise = null;
|
|
36720
|
+
if (getCurrentScreen() === "host-preferences") {
|
|
36721
|
+
renderHostVoiceInputPreferences({
|
|
36722
|
+
disabled:
|
|
36723
|
+
hostPreferencesState.loading || hostPreferencesState.saving,
|
|
36724
|
+
});
|
|
36725
|
+
}
|
|
36726
|
+
}
|
|
36727
|
+
})();
|
|
36728
|
+
return hostVoiceInputSampleLoadPromise;
|
|
36729
|
+
}
|
|
36730
|
+
|
|
36731
|
+
function formatVoiceInputUsageTokens(value) {
|
|
36732
|
+
const normalized = Number(value);
|
|
36733
|
+
return Number.isFinite(normalized)
|
|
36734
|
+
? Math.max(0, Math.round(normalized)).toLocaleString("en-US")
|
|
36735
|
+
: "0";
|
|
36736
|
+
}
|
|
36737
|
+
|
|
36738
|
+
function formatVoiceInputUsageCost(value) {
|
|
36739
|
+
const normalized = Number(value);
|
|
36740
|
+
const usd = Number.isFinite(normalized)
|
|
36741
|
+
? Math.max(0, normalized) / 1_000_000_000
|
|
36742
|
+
: 0;
|
|
36743
|
+
return `US$${usd.toFixed(6)}`;
|
|
36744
|
+
}
|
|
36745
|
+
|
|
36746
|
+
function formatVoiceInputUsageDuration(value) {
|
|
36747
|
+
const milliseconds = Number(value);
|
|
36748
|
+
if (!Number.isFinite(milliseconds) || milliseconds <= 0) return "0 s";
|
|
36749
|
+
const seconds = milliseconds / 1000;
|
|
36750
|
+
if (seconds < 60) return `${seconds.toFixed(seconds < 10 ? 1 : 0)} s`;
|
|
36751
|
+
const minutes = seconds / 60;
|
|
36752
|
+
if (minutes < 60) return `${minutes.toFixed(1)} min`;
|
|
36753
|
+
return `${(minutes / 60).toFixed(1)} hr`;
|
|
36754
|
+
}
|
|
36755
|
+
|
|
36756
|
+
function formatVoiceInputUsageSummary(label, windowStats) {
|
|
36757
|
+
if (!windowStats) return `${label}: No usage data.`;
|
|
36758
|
+
const unknownCostRequests = Number(
|
|
36759
|
+
windowStats.unknown_cost_requests || 0
|
|
36760
|
+
);
|
|
36761
|
+
return `${label}: ${formatVoiceInputUsageTokens(
|
|
36762
|
+
windowStats.total_tokens
|
|
36763
|
+
)} tokens used · Estimated cost: ${formatVoiceInputUsageCost(
|
|
36764
|
+
windowStats.estimated_cost_nano_usd
|
|
36765
|
+
)}${
|
|
36766
|
+
unknownCostRequests > 0
|
|
36767
|
+
? ` · ${unknownCostRequests.toLocaleString("en-US")} request${
|
|
36768
|
+
unknownCostRequests === 1 ? "" : "s"
|
|
36769
|
+
} not included`
|
|
36770
|
+
: ""
|
|
36771
|
+
}`;
|
|
36772
|
+
}
|
|
36773
|
+
|
|
36774
|
+
function renderHostVoiceInputUsageSummary() {
|
|
36775
|
+
const container = $("host-voice-input-usage-summary");
|
|
36776
|
+
if (!container) return;
|
|
36777
|
+
const enabled = hostPreferencesState.voiceInputEnabled === true;
|
|
36778
|
+
container.classList.toggle("hidden", !enabled);
|
|
36779
|
+
if (!enabled) return;
|
|
36780
|
+
const usage = hostPreferencesState.voiceInputUsage;
|
|
36781
|
+
const loading =
|
|
36782
|
+
hostPreferencesState.voiceInputUsageLoading === true && !usage;
|
|
36783
|
+
const error = hostPreferencesState.voiceInputUsageError || "";
|
|
36784
|
+
setText(
|
|
36785
|
+
"host-voice-input-usage-24h",
|
|
36786
|
+
loading
|
|
36787
|
+
? "Last 24 hours: Loading usage..."
|
|
36788
|
+
: formatVoiceInputUsageSummary(
|
|
36789
|
+
"Last 24 hours",
|
|
36790
|
+
usage?.windows?.["24h"]
|
|
36791
|
+
)
|
|
36792
|
+
);
|
|
36793
|
+
setText(
|
|
36794
|
+
"host-voice-input-usage-7d",
|
|
36795
|
+
loading
|
|
36796
|
+
? "Last 7 days: Loading usage..."
|
|
36797
|
+
: formatVoiceInputUsageSummary(
|
|
36798
|
+
"Last 7 days",
|
|
36799
|
+
usage?.windows?.["7d"]
|
|
36800
|
+
)
|
|
36801
|
+
);
|
|
36802
|
+
setText(
|
|
36803
|
+
"host-voice-input-usage-30d",
|
|
36804
|
+
loading
|
|
36805
|
+
? "Last 30 days: Loading usage..."
|
|
36806
|
+
: formatVoiceInputUsageSummary(
|
|
36807
|
+
"Last 30 days",
|
|
36808
|
+
usage?.windows?.["30d"]
|
|
36809
|
+
)
|
|
36810
|
+
);
|
|
36811
|
+
setText("host-voice-input-usage-error", error);
|
|
36812
|
+
$("host-voice-input-usage-error")?.classList.toggle("hidden", !error);
|
|
36813
|
+
$("host-voice-input-usage-detail-btn")?.toggleAttribute(
|
|
36814
|
+
"disabled",
|
|
36815
|
+
loading
|
|
36816
|
+
);
|
|
36817
|
+
}
|
|
36818
|
+
|
|
36819
|
+
function getVoiceInputUsageDetailRows(usage) {
|
|
36820
|
+
const windows = ["24h", "7d", "30d"].map(
|
|
36821
|
+
(windowId) => usage?.windows?.[windowId] || {}
|
|
36822
|
+
);
|
|
36823
|
+
return [
|
|
36824
|
+
[
|
|
36825
|
+
"Requests",
|
|
36826
|
+
...windows.map((item) =>
|
|
36827
|
+
formatVoiceInputUsageTokens(item.request_count)
|
|
36828
|
+
),
|
|
36829
|
+
],
|
|
36830
|
+
[
|
|
36831
|
+
"Successful transcriptions",
|
|
36832
|
+
...windows.map((item) =>
|
|
36833
|
+
formatVoiceInputUsageTokens(item.successful_transcriptions)
|
|
36834
|
+
),
|
|
36835
|
+
],
|
|
36836
|
+
[
|
|
36837
|
+
"Failed requests",
|
|
36838
|
+
...windows.map((item) =>
|
|
36839
|
+
formatVoiceInputUsageTokens(item.failed_requests)
|
|
36840
|
+
),
|
|
36841
|
+
],
|
|
36842
|
+
[
|
|
36843
|
+
"Token tests",
|
|
36844
|
+
...windows.map((item) =>
|
|
36845
|
+
formatVoiceInputUsageTokens(item.token_tests)
|
|
36846
|
+
),
|
|
36847
|
+
],
|
|
36848
|
+
[
|
|
36849
|
+
"Recorded audio",
|
|
36850
|
+
...windows.map((item) =>
|
|
36851
|
+
formatVoiceInputUsageDuration(item.recorded_duration_ms)
|
|
36852
|
+
),
|
|
36853
|
+
],
|
|
36854
|
+
[
|
|
36855
|
+
"Input tokens",
|
|
36856
|
+
...windows.map((item) =>
|
|
36857
|
+
formatVoiceInputUsageTokens(item.input_tokens)
|
|
36858
|
+
),
|
|
36859
|
+
],
|
|
36860
|
+
[
|
|
36861
|
+
"Output tokens",
|
|
36862
|
+
...windows.map((item) =>
|
|
36863
|
+
formatVoiceInputUsageTokens(item.output_tokens)
|
|
36864
|
+
),
|
|
36865
|
+
],
|
|
36866
|
+
[
|
|
36867
|
+
"Total tokens",
|
|
36868
|
+
...windows.map((item) =>
|
|
36869
|
+
formatVoiceInputUsageTokens(item.total_tokens)
|
|
36870
|
+
),
|
|
36871
|
+
],
|
|
36872
|
+
[
|
|
36873
|
+
"Average provider latency",
|
|
36874
|
+
...windows.map((item) =>
|
|
36875
|
+
item.average_provider_latency_ms === null ||
|
|
36876
|
+
item.average_provider_latency_ms === undefined
|
|
36877
|
+
? "--"
|
|
36878
|
+
: `${formatVoiceInputUsageTokens(
|
|
36879
|
+
item.average_provider_latency_ms
|
|
36880
|
+
)} ms`
|
|
36881
|
+
),
|
|
36882
|
+
],
|
|
36883
|
+
[
|
|
36884
|
+
"Estimated cost",
|
|
36885
|
+
...windows.map((item) =>
|
|
36886
|
+
formatVoiceInputUsageCost(item.estimated_cost_nano_usd)
|
|
36887
|
+
),
|
|
36888
|
+
],
|
|
36889
|
+
[
|
|
36890
|
+
"Requests not included in cost",
|
|
36891
|
+
...windows.map((item) =>
|
|
36892
|
+
formatVoiceInputUsageTokens(item.unknown_cost_requests)
|
|
36893
|
+
),
|
|
36894
|
+
],
|
|
36895
|
+
];
|
|
36896
|
+
}
|
|
36897
|
+
|
|
36898
|
+
function renderHostVoiceInputUsageDetail() {
|
|
36899
|
+
const usage = hostPreferencesState.voiceInputUsage;
|
|
36900
|
+
const loading = hostPreferencesState.voiceInputUsageLoading === true;
|
|
36901
|
+
const error = hostPreferencesState.voiceInputUsageError || "";
|
|
36902
|
+
setText(
|
|
36903
|
+
"voice-input-usage-generated-at",
|
|
36904
|
+
usage?.generated_at
|
|
36905
|
+
? `Updated ${new Date(usage.generated_at).toLocaleString()}`
|
|
36906
|
+
: loading
|
|
36907
|
+
? "Loading usage..."
|
|
36908
|
+
: ""
|
|
36909
|
+
);
|
|
36910
|
+
setText("voice-input-usage-error", error);
|
|
36911
|
+
$("voice-input-usage-error")?.classList.toggle("hidden", !error);
|
|
36912
|
+
$("voice-input-usage-retry-btn")?.classList.toggle("hidden", !error);
|
|
36913
|
+
const tableWrap = $("voice-input-usage-table-wrap");
|
|
36914
|
+
tableWrap?.classList.toggle("hidden", !usage);
|
|
36915
|
+
const tableBody = $("voice-input-usage-table-body");
|
|
36916
|
+
if (!tableBody || !usage) return;
|
|
36917
|
+
const rows = getVoiceInputUsageDetailRows(usage).map((cells) => {
|
|
36918
|
+
const row = document.createElement("tr");
|
|
36919
|
+
cells.forEach((cell, index) => {
|
|
36920
|
+
const element = document.createElement(index === 0 ? "th" : "td");
|
|
36921
|
+
element.textContent = cell;
|
|
36922
|
+
if (index === 0) element.scope = "row";
|
|
36923
|
+
row.appendChild(element);
|
|
36924
|
+
});
|
|
36925
|
+
return row;
|
|
36926
|
+
});
|
|
36927
|
+
tableBody.replaceChildren(...rows);
|
|
36928
|
+
}
|
|
36929
|
+
|
|
36930
|
+
async function loadHostVoiceInputUsage({ force = false } = {}) {
|
|
36931
|
+
if (hostVoiceInputUsageLoadPromise) {
|
|
36932
|
+
return hostVoiceInputUsageLoadPromise;
|
|
36933
|
+
}
|
|
36934
|
+
if (
|
|
36935
|
+
!force &&
|
|
36936
|
+
hostPreferencesState.voiceInputUsageLoaded &&
|
|
36937
|
+
hostPreferencesState.voiceInputUsage
|
|
36938
|
+
) {
|
|
36939
|
+
return hostPreferencesState.voiceInputUsage;
|
|
36940
|
+
}
|
|
36941
|
+
hostPreferencesState = {
|
|
36942
|
+
...hostPreferencesState,
|
|
36943
|
+
voiceInputUsageLoading: true,
|
|
36944
|
+
voiceInputUsageError: "",
|
|
36945
|
+
};
|
|
36946
|
+
renderHostVoiceInputUsageSummary();
|
|
36947
|
+
renderHostVoiceInputUsageDetail();
|
|
36948
|
+
hostVoiceInputUsageLoadPromise = (async () => {
|
|
36949
|
+
try {
|
|
36950
|
+
const usage = await apiWithAuthRetry(
|
|
36951
|
+
"GET",
|
|
36952
|
+
"/dev/preferences/voice-input/usage"
|
|
36953
|
+
);
|
|
36954
|
+
hostPreferencesState = {
|
|
36955
|
+
...hostPreferencesState,
|
|
36956
|
+
voiceInputUsage: usage,
|
|
36957
|
+
voiceInputUsageLoading: false,
|
|
36958
|
+
voiceInputUsageLoaded: true,
|
|
36959
|
+
voiceInputUsageError: "",
|
|
36960
|
+
};
|
|
36961
|
+
return usage;
|
|
36962
|
+
} catch (err) {
|
|
36963
|
+
if (await handleHostPreferencesAuthFailure(err)) return null;
|
|
36964
|
+
hostPreferencesState = {
|
|
36965
|
+
...hostPreferencesState,
|
|
36966
|
+
voiceInputUsageLoading: false,
|
|
36967
|
+
voiceInputUsageLoaded: false,
|
|
36968
|
+
voiceInputUsageError:
|
|
36969
|
+
err.message || "Could not load Voice Input usage.",
|
|
36970
|
+
};
|
|
36971
|
+
return null;
|
|
36972
|
+
} finally {
|
|
36973
|
+
hostVoiceInputUsageLoadPromise = null;
|
|
36974
|
+
renderHostVoiceInputUsageSummary();
|
|
36975
|
+
renderHostVoiceInputUsageDetail();
|
|
36976
|
+
}
|
|
36977
|
+
})();
|
|
36978
|
+
return hostVoiceInputUsageLoadPromise;
|
|
36979
|
+
}
|
|
36980
|
+
|
|
36981
|
+
function openHostVoiceInputUsageDetail() {
|
|
36982
|
+
void navigateToRoute(buildVoiceInputUsageRoute());
|
|
36983
|
+
}
|
|
36984
|
+
|
|
36985
|
+
function retryHostVoiceInputUsage() {
|
|
36986
|
+
void loadHostVoiceInputUsage({ force: true });
|
|
36987
|
+
}
|
|
36988
|
+
|
|
36989
|
+
function renderHostVoiceInputPreferences({ disabled = false } = {}) {
|
|
36990
|
+
const toggle = $("host-voice-input-enabled-toggle");
|
|
36991
|
+
const voiceInputEnabled =
|
|
36992
|
+
hostPreferencesState.voiceInputEnabled === true;
|
|
36993
|
+
const voiceInputModel =
|
|
36994
|
+
typeof hostPreferencesState.voiceInputModel === "string"
|
|
36995
|
+
? hostPreferencesState.voiceInputModel.trim()
|
|
36996
|
+
: "";
|
|
36997
|
+
setText(
|
|
36998
|
+
"host-voice-input-title",
|
|
36999
|
+
voiceInputModel ? `Voice Input (${voiceInputModel})` : "Voice Input"
|
|
37000
|
+
);
|
|
37001
|
+
setHostVoiceInputEnabledControlValue(voiceInputEnabled);
|
|
37002
|
+
const tokenInput = $("host-voice-input-token");
|
|
37003
|
+
if (tokenInput && document.activeElement !== tokenInput) {
|
|
37004
|
+
tokenInput.value = hostPreferencesState.voiceInputTokenDraft || "";
|
|
37005
|
+
}
|
|
37006
|
+
const tokenCandidate =
|
|
37007
|
+
tokenInput?.value?.trim() ||
|
|
37008
|
+
hostPreferencesState.voiceInputTokenDraft ||
|
|
37009
|
+
"";
|
|
37010
|
+
const tokenConfigured =
|
|
37011
|
+
hostPreferencesState.voiceInputTokenConfigured === true;
|
|
37012
|
+
const tokenValidated =
|
|
37013
|
+
hostPreferencesState.voiceInputTokenValidated === true;
|
|
37014
|
+
const pendingReplacement = Boolean(tokenCandidate);
|
|
37015
|
+
if (tokenInput) {
|
|
37016
|
+
tokenInput.placeholder =
|
|
37017
|
+
tokenConfigured && hostPreferencesState.voiceInputTokenMasked
|
|
37018
|
+
? hostPreferencesState.voiceInputTokenMasked
|
|
37019
|
+
: "Enter a new token";
|
|
37020
|
+
tokenInput.setAttribute(
|
|
37021
|
+
"aria-label",
|
|
37022
|
+
tokenConfigured && !pendingReplacement
|
|
37023
|
+
? `Saved OpenAI API token ${hostPreferencesState.voiceInputTokenMasked}. Enter a new token to replace it.`
|
|
37024
|
+
: "OpenAI API token"
|
|
37025
|
+
);
|
|
37026
|
+
}
|
|
37027
|
+
setText(
|
|
37028
|
+
"host-voice-input-token-status",
|
|
37029
|
+
pendingReplacement
|
|
37030
|
+
? tokenConfigured
|
|
37031
|
+
? "New token entered. Test & Save Token to replace the saved token, or discard this draft."
|
|
37032
|
+
: "New token entered. Run Test & Save Token."
|
|
37033
|
+
: tokenConfigured
|
|
37034
|
+
? tokenValidated
|
|
37035
|
+
? "Validated and saved."
|
|
37036
|
+
: "Saved token requires validation."
|
|
37037
|
+
: "No token saved."
|
|
37038
|
+
);
|
|
37039
|
+
setText(
|
|
37040
|
+
"host-voice-input-client-warning",
|
|
37041
|
+
getHostVoiceInputClientWarning()
|
|
37042
|
+
);
|
|
37043
|
+
setText(
|
|
37044
|
+
"host-voice-input-availability",
|
|
37045
|
+
hostPreferencesState.voiceInputAvailable
|
|
37046
|
+
? `Ready with ${hostPreferencesState.voiceInputModel}.`
|
|
37047
|
+
: pendingReplacement
|
|
37048
|
+
? voiceInputEnabled
|
|
37049
|
+
? "The saved token remains active. Test or discard the replacement draft."
|
|
37050
|
+
: "Test or discard the replacement draft before enabling Voice Input."
|
|
37051
|
+
: hostPreferencesState.voiceInputCanEnable
|
|
37052
|
+
? "Token validation passed. Enable Voice Input and save Preferences."
|
|
37053
|
+
: "Test and save a valid OpenAI API token first."
|
|
37054
|
+
);
|
|
37055
|
+
const pill = $("host-voice-input-state-pill");
|
|
37056
|
+
if (pill) {
|
|
37057
|
+
pill.textContent = hostPreferencesState.voiceInputAvailable
|
|
37058
|
+
? "Ready"
|
|
37059
|
+
: hostPreferencesState.voiceInputCanEnable
|
|
37060
|
+
? "Validated"
|
|
37061
|
+
: "Disabled";
|
|
37062
|
+
}
|
|
37063
|
+
setText(
|
|
37064
|
+
"host-voice-input-sample-expected",
|
|
37065
|
+
hostPreferencesState.voiceInputSampleExpected
|
|
37066
|
+
);
|
|
37067
|
+
const samplePlayer = $("host-voice-input-sample-player");
|
|
37068
|
+
if (
|
|
37069
|
+
samplePlayer &&
|
|
37070
|
+
hostVoiceInputSampleObjectUrl &&
|
|
37071
|
+
samplePlayer.src !== hostVoiceInputSampleObjectUrl
|
|
37072
|
+
) {
|
|
37073
|
+
samplePlayer.src = hostVoiceInputSampleObjectUrl;
|
|
37074
|
+
}
|
|
37075
|
+
setText(
|
|
37076
|
+
"host-voice-input-sample-status",
|
|
37077
|
+
hostPreferencesState.voiceInputSampleLoading
|
|
37078
|
+
? "Loading D1.wav..."
|
|
37079
|
+
: hostPreferencesState.voiceInputSampleError
|
|
37080
|
+
? hostPreferencesState.voiceInputSampleError
|
|
37081
|
+
: hostPreferencesState.voiceInputSampleLoaded
|
|
37082
|
+
? "D1.wav"
|
|
37083
|
+
: ""
|
|
37084
|
+
);
|
|
37085
|
+
const testStatus =
|
|
37086
|
+
hostPreferencesState.voiceInputTestError ||
|
|
37087
|
+
hostPreferencesState.voiceInputTestStatus ||
|
|
37088
|
+
"";
|
|
37089
|
+
setText(
|
|
37090
|
+
"host-voice-input-test-status",
|
|
37091
|
+
hostPreferencesState.voiceInputTestLatencyMs !== null
|
|
37092
|
+
? `${testStatus} ${hostPreferencesState.voiceInputTestLatencyMs} ms`
|
|
37093
|
+
: testStatus
|
|
37094
|
+
);
|
|
37095
|
+
setText(
|
|
37096
|
+
"host-voice-input-test-transcript",
|
|
37097
|
+
hostPreferencesState.voiceInputTestTranscript
|
|
37098
|
+
? `Actual transcript: ${hostPreferencesState.voiceInputTestTranscript}`
|
|
37099
|
+
: ""
|
|
37100
|
+
);
|
|
37101
|
+
const testStatusElement = $("host-voice-input-test-status");
|
|
37102
|
+
testStatusElement?.classList.toggle(
|
|
37103
|
+
"voice-input-warning",
|
|
37104
|
+
Boolean(hostPreferencesState.voiceInputTestError)
|
|
37105
|
+
);
|
|
37106
|
+
const canEnable = hostPreferencesState.voiceInputCanEnable === true;
|
|
37107
|
+
toggle?.toggleAttribute(
|
|
37108
|
+
"disabled",
|
|
37109
|
+
disabled ||
|
|
37110
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
37111
|
+
hostPreferencesState.voiceInputTokenClearing ||
|
|
37112
|
+
(!voiceInputEnabled && (!canEnable || pendingReplacement))
|
|
37113
|
+
);
|
|
37114
|
+
toggle?.setAttribute(
|
|
37115
|
+
"aria-disabled",
|
|
37116
|
+
toggle?.disabled ? "true" : "false"
|
|
37117
|
+
);
|
|
37118
|
+
const enableWarning = $("host-voice-input-enable-warning");
|
|
37119
|
+
setText(
|
|
37120
|
+
"host-voice-input-enable-warning",
|
|
37121
|
+
pendingReplacement
|
|
37122
|
+
? "Test or discard the new token before enabling Voice Input."
|
|
37123
|
+
: "Test and save a valid OpenAI API token before enabling Voice Input."
|
|
37124
|
+
);
|
|
37125
|
+
enableWarning?.classList.toggle(
|
|
37126
|
+
"hidden",
|
|
37127
|
+
voiceInputEnabled || (canEnable && !pendingReplacement)
|
|
37128
|
+
);
|
|
37129
|
+
tokenInput?.toggleAttribute(
|
|
37130
|
+
"disabled",
|
|
37131
|
+
disabled ||
|
|
37132
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
37133
|
+
hostPreferencesState.voiceInputTokenClearing
|
|
37134
|
+
);
|
|
37135
|
+
const discardDraftButton = $(
|
|
37136
|
+
"host-voice-input-discard-token-draft-btn"
|
|
37137
|
+
);
|
|
37138
|
+
discardDraftButton?.classList.toggle("hidden", !pendingReplacement);
|
|
37139
|
+
discardDraftButton?.toggleAttribute(
|
|
37140
|
+
"disabled",
|
|
37141
|
+
disabled ||
|
|
37142
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
37143
|
+
hostPreferencesState.voiceInputTokenClearing
|
|
37144
|
+
);
|
|
37145
|
+
const removeSavedButton = $("host-voice-input-remove-saved-token-btn");
|
|
37146
|
+
removeSavedButton?.classList.toggle(
|
|
37147
|
+
"hidden",
|
|
37148
|
+
pendingReplacement || !tokenConfigured
|
|
37149
|
+
);
|
|
37150
|
+
removeSavedButton?.toggleAttribute(
|
|
37151
|
+
"disabled",
|
|
37152
|
+
disabled ||
|
|
37153
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
37154
|
+
hostPreferencesState.voiceInputTokenClearing
|
|
37155
|
+
);
|
|
37156
|
+
const testButton = $("host-voice-input-test-btn");
|
|
37157
|
+
if (testButton) {
|
|
37158
|
+
testButton.disabled =
|
|
37159
|
+
disabled ||
|
|
37160
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
37161
|
+
hostPreferencesState.voiceInputTokenClearing ||
|
|
37162
|
+
(pendingReplacement
|
|
37163
|
+
? !isHostVoiceInputTokenCandidateTestable(tokenCandidate)
|
|
37164
|
+
: !tokenConfigured);
|
|
37165
|
+
testButton.textContent = hostPreferencesState.voiceInputTestRunning
|
|
37166
|
+
? "Testing..."
|
|
37167
|
+
: tokenCandidate
|
|
37168
|
+
? "Test & Save Token"
|
|
37169
|
+
: tokenConfigured
|
|
37170
|
+
? "Retest Saved Token"
|
|
37171
|
+
: "Test & Save Token";
|
|
37172
|
+
}
|
|
37173
|
+
if (
|
|
37174
|
+
getCurrentScreen() === "host-preferences" &&
|
|
37175
|
+
!hostPreferencesState.voiceInputSampleLoaded &&
|
|
37176
|
+
!hostPreferencesState.voiceInputSampleLoading
|
|
37177
|
+
) {
|
|
37178
|
+
void ensureHostVoiceInputSampleAudio();
|
|
37179
|
+
}
|
|
37180
|
+
renderHostVoiceInputUsageSummary();
|
|
37181
|
+
if (
|
|
37182
|
+
voiceInputEnabled &&
|
|
37183
|
+
!hostPreferencesState.voiceInputUsageLoaded &&
|
|
37184
|
+
!hostPreferencesState.voiceInputUsageLoading
|
|
37185
|
+
) {
|
|
37186
|
+
void loadHostVoiceInputUsage();
|
|
37187
|
+
}
|
|
37188
|
+
}
|
|
37189
|
+
|
|
35897
37190
|
function renderHostPreferences() {
|
|
35898
37191
|
const pathInput = $("host-default-browse-path");
|
|
35899
37192
|
if (
|
|
@@ -36024,10 +37317,8 @@ Waiting for Claude login output…</pre
|
|
|
36024
37317
|
basicPreferencesUnavailable;
|
|
36025
37318
|
const providerSectionStatusVisible =
|
|
36026
37319
|
providerCatalogState.loading || Boolean(providerCatalogState.error);
|
|
36027
|
-
const providerSectionInitialPending =
|
|
36028
|
-
|
|
36029
|
-
const providerSectionUnavailable =
|
|
36030
|
-
!providerCatalogState.loaded && Boolean(providerCatalogState.error);
|
|
37320
|
+
const providerSectionInitialPending = isProviderCatalogInitialPending();
|
|
37321
|
+
const providerSectionUnavailable = isProviderCatalogRequestFailed();
|
|
36031
37322
|
const providerControlsDisabled =
|
|
36032
37323
|
disabled ||
|
|
36033
37324
|
providerSectionInitialPending ||
|
|
@@ -36035,12 +37326,12 @@ Waiting for Claude login output…</pre
|
|
|
36035
37326
|
let providerSectionStatusCopy = "";
|
|
36036
37327
|
if (providerCatalogState.loading) {
|
|
36037
37328
|
providerSectionStatusCopy = providerCatalogState.loaded
|
|
36038
|
-
? "Refreshing provider
|
|
36039
|
-
: "Checking provider
|
|
37329
|
+
? "Refreshing provider availability..."
|
|
37330
|
+
: "Checking provider availability...";
|
|
36040
37331
|
} else if (providerCatalogState.error) {
|
|
36041
37332
|
providerSectionStatusCopy = providerCatalogState.loaded
|
|
36042
|
-
? "Could not refresh provider
|
|
36043
|
-
: "Could not load provider
|
|
37333
|
+
? "Could not refresh provider availability. Existing values remain available."
|
|
37334
|
+
: "Could not load provider availability.";
|
|
36044
37335
|
}
|
|
36045
37336
|
setVisible(
|
|
36046
37337
|
"host-provider-section-status-label",
|
|
@@ -36428,15 +37719,11 @@ Waiting for Claude login output…</pre
|
|
|
36428
37719
|
);
|
|
36429
37720
|
setText(
|
|
36430
37721
|
"host-claude-command-status",
|
|
36431
|
-
|
|
36432
|
-
? "Available on this Host."
|
|
36433
|
-
: "Unavailable on this Host. Blank disables Claude explicitly."
|
|
37722
|
+
describeProviderCommandAvailability("claude")
|
|
36434
37723
|
);
|
|
36435
37724
|
setText(
|
|
36436
37725
|
"host-codex-command-status",
|
|
36437
|
-
|
|
36438
|
-
? "Available on this Host."
|
|
36439
|
-
: "Unavailable on this Host. Blank disables Codex explicitly."
|
|
37726
|
+
describeProviderCommandAvailability("codex")
|
|
36440
37727
|
);
|
|
36441
37728
|
setText(
|
|
36442
37729
|
"host-default-provider-warning",
|
|
@@ -36456,6 +37743,7 @@ Waiting for Claude login output…</pre
|
|
|
36456
37743
|
hostPreferencesState.debugHostPreferencesFullDiskAccessBlockEnabled ===
|
|
36457
37744
|
true;
|
|
36458
37745
|
renderHostNotificationPreferences({ disabled });
|
|
37746
|
+
renderHostVoiceInputPreferences({ disabled });
|
|
36459
37747
|
setVisible("host-folder-access-card", folderAccessVisible);
|
|
36460
37748
|
$("host-public-base-url")?.toggleAttribute(
|
|
36461
37749
|
"disabled",
|
|
@@ -36542,6 +37830,7 @@ Waiting for Claude login output…</pre
|
|
|
36542
37830
|
error: "",
|
|
36543
37831
|
};
|
|
36544
37832
|
renderHostPreferences();
|
|
37833
|
+
void loadHostVoiceInputNativeAppVersion();
|
|
36545
37834
|
try {
|
|
36546
37835
|
const data = await apiWithAuthRetry("GET", "/dev/preferences");
|
|
36547
37836
|
applyHostPreferencesData(data);
|
|
@@ -36975,6 +38264,192 @@ Waiting for Claude login output…</pre
|
|
|
36975
38264
|
discardUnsavedHostPreferencesChanges();
|
|
36976
38265
|
}
|
|
36977
38266
|
|
|
38267
|
+
function handleHostVoiceInputTokenInput() {
|
|
38268
|
+
const tokenDraft = $("host-voice-input-token")?.value || "";
|
|
38269
|
+
hostPreferencesState = {
|
|
38270
|
+
...hostPreferencesState,
|
|
38271
|
+
voiceInputTokenDraft: tokenDraft,
|
|
38272
|
+
voiceInputTestStatus: "",
|
|
38273
|
+
voiceInputTestError: "",
|
|
38274
|
+
voiceInputTestTranscript: "",
|
|
38275
|
+
voiceInputTestLatencyMs: null,
|
|
38276
|
+
};
|
|
38277
|
+
renderHostVoiceInputPreferences({
|
|
38278
|
+
disabled: hostPreferencesState.loading || hostPreferencesState.saving,
|
|
38279
|
+
});
|
|
38280
|
+
}
|
|
38281
|
+
|
|
38282
|
+
function toggleHostVoiceInputEnabled() {
|
|
38283
|
+
const toggle = $("host-voice-input-enabled-toggle");
|
|
38284
|
+
if (!toggle || toggle.disabled) return;
|
|
38285
|
+
const enabled = !getHostVoiceInputEnabledControlValue();
|
|
38286
|
+
setHostVoiceInputEnabledControlValue(enabled);
|
|
38287
|
+
hostPreferencesState = {
|
|
38288
|
+
...hostPreferencesState,
|
|
38289
|
+
voiceInputEnabled: enabled,
|
|
38290
|
+
};
|
|
38291
|
+
stageHostPreferencesDraftFromControls();
|
|
38292
|
+
renderHostPreferences();
|
|
38293
|
+
}
|
|
38294
|
+
|
|
38295
|
+
function discardHostVoiceInputTokenDraft() {
|
|
38296
|
+
if (
|
|
38297
|
+
hostPreferencesState.loading ||
|
|
38298
|
+
hostPreferencesState.saving ||
|
|
38299
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
38300
|
+
hostPreferencesState.voiceInputTokenClearing
|
|
38301
|
+
) {
|
|
38302
|
+
return;
|
|
38303
|
+
}
|
|
38304
|
+
const tokenInput = $("host-voice-input-token");
|
|
38305
|
+
if (tokenInput) tokenInput.value = "";
|
|
38306
|
+
hostPreferencesState = {
|
|
38307
|
+
...hostPreferencesState,
|
|
38308
|
+
voiceInputTokenDraft: "",
|
|
38309
|
+
voiceInputTestStatus: "",
|
|
38310
|
+
voiceInputTestError: "",
|
|
38311
|
+
voiceInputTestTranscript: "",
|
|
38312
|
+
voiceInputTestLatencyMs: null,
|
|
38313
|
+
};
|
|
38314
|
+
renderHostPreferences();
|
|
38315
|
+
}
|
|
38316
|
+
|
|
38317
|
+
async function removeHostVoiceInputSavedToken() {
|
|
38318
|
+
if (
|
|
38319
|
+
hostPreferencesState.loading ||
|
|
38320
|
+
hostPreferencesState.saving ||
|
|
38321
|
+
hostPreferencesState.voiceInputTestRunning ||
|
|
38322
|
+
hostPreferencesState.voiceInputTokenClearing
|
|
38323
|
+
) {
|
|
38324
|
+
return;
|
|
38325
|
+
}
|
|
38326
|
+
if (!hostPreferencesState.voiceInputTokenConfigured) {
|
|
38327
|
+
return;
|
|
38328
|
+
}
|
|
38329
|
+
if (
|
|
38330
|
+
!window.confirm(
|
|
38331
|
+
"Remove the saved OpenAI API token and disable Voice Input?"
|
|
38332
|
+
)
|
|
38333
|
+
) {
|
|
38334
|
+
return;
|
|
38335
|
+
}
|
|
38336
|
+
const tokenInput = $("host-voice-input-token");
|
|
38337
|
+
if (tokenInput) tokenInput.value = "";
|
|
38338
|
+
hostPreferencesState = {
|
|
38339
|
+
...hostPreferencesState,
|
|
38340
|
+
voiceInputTokenDraft: "",
|
|
38341
|
+
voiceInputTokenClearing: true,
|
|
38342
|
+
voiceInputTestStatus: "Clearing saved token...",
|
|
38343
|
+
voiceInputTestError: "",
|
|
38344
|
+
voiceInputTestTranscript: "",
|
|
38345
|
+
voiceInputTestLatencyMs: null,
|
|
38346
|
+
};
|
|
38347
|
+
renderHostPreferences();
|
|
38348
|
+
try {
|
|
38349
|
+
const data = await apiWithAuthRetry("PUT", "/dev/preferences", {
|
|
38350
|
+
voice_input: {
|
|
38351
|
+
enabled: false,
|
|
38352
|
+
token_action: "clear",
|
|
38353
|
+
},
|
|
38354
|
+
});
|
|
38355
|
+
applyHostVoiceInputStatusPayload(data.preferences?.voice_input);
|
|
38356
|
+
hostPreferencesState = {
|
|
38357
|
+
...hostPreferencesState,
|
|
38358
|
+
voiceInputTokenClearing: false,
|
|
38359
|
+
voiceInputTokenDraft: "",
|
|
38360
|
+
voiceInputTestStatus: "Saved token cleared.",
|
|
38361
|
+
voiceInputTestError: "",
|
|
38362
|
+
voiceInputTestTranscript: "",
|
|
38363
|
+
voiceInputTestLatencyMs: null,
|
|
38364
|
+
};
|
|
38365
|
+
} catch (err) {
|
|
38366
|
+
if (await handleHostPreferencesAuthFailure(err)) return;
|
|
38367
|
+
hostPreferencesState = {
|
|
38368
|
+
...hostPreferencesState,
|
|
38369
|
+
voiceInputTokenClearing: false,
|
|
38370
|
+
voiceInputTestStatus: "",
|
|
38371
|
+
voiceInputTestError:
|
|
38372
|
+
err.message || "Could not clear the Voice Input token.",
|
|
38373
|
+
};
|
|
38374
|
+
}
|
|
38375
|
+
renderHostPreferences();
|
|
38376
|
+
}
|
|
38377
|
+
|
|
38378
|
+
async function testHostVoiceInput() {
|
|
38379
|
+
const candidateToken =
|
|
38380
|
+
$("host-voice-input-token")?.value?.trim() ||
|
|
38381
|
+
hostPreferencesState.voiceInputTokenDraft.trim();
|
|
38382
|
+
if (hostPreferencesState.voiceInputTestRunning) {
|
|
38383
|
+
return;
|
|
38384
|
+
}
|
|
38385
|
+
if (
|
|
38386
|
+
candidateToken &&
|
|
38387
|
+
!isHostVoiceInputTokenCandidateTestable(candidateToken)
|
|
38388
|
+
) {
|
|
38389
|
+
hostPreferencesState = {
|
|
38390
|
+
...hostPreferencesState,
|
|
38391
|
+
voiceInputTestStatus: "",
|
|
38392
|
+
voiceInputTestError:
|
|
38393
|
+
"Enter a complete OpenAI API token before testing.",
|
|
38394
|
+
};
|
|
38395
|
+
renderHostPreferences();
|
|
38396
|
+
return;
|
|
38397
|
+
}
|
|
38398
|
+
if (
|
|
38399
|
+
!candidateToken &&
|
|
38400
|
+
!hostPreferencesState.voiceInputTokenConfigured
|
|
38401
|
+
) {
|
|
38402
|
+
return;
|
|
38403
|
+
}
|
|
38404
|
+
hostPreferencesState = {
|
|
38405
|
+
...hostPreferencesState,
|
|
38406
|
+
voiceInputTestRunning: true,
|
|
38407
|
+
voiceInputTestStatus: "Testing D1.wav...",
|
|
38408
|
+
voiceInputTestError: "",
|
|
38409
|
+
voiceInputTestTranscript: "",
|
|
38410
|
+
voiceInputTestLatencyMs: null,
|
|
38411
|
+
error: "",
|
|
38412
|
+
};
|
|
38413
|
+
renderHostPreferences();
|
|
38414
|
+
try {
|
|
38415
|
+
const data = await apiWithAuthRetry(
|
|
38416
|
+
"POST",
|
|
38417
|
+
"/dev/preferences/voice-input/test",
|
|
38418
|
+
candidateToken ? { openai_api_token: candidateToken } : {}
|
|
38419
|
+
);
|
|
38420
|
+
applyHostVoiceInputStatusPayload(data.voice_input);
|
|
38421
|
+
const tokenInput = $("host-voice-input-token");
|
|
38422
|
+
if (tokenInput) tokenInput.value = "";
|
|
38423
|
+
hostPreferencesState = {
|
|
38424
|
+
...hostPreferencesState,
|
|
38425
|
+
voiceInputTestRunning: false,
|
|
38426
|
+
voiceInputTokenDraft: "",
|
|
38427
|
+
voiceInputTestStatus:
|
|
38428
|
+
data.sample_exact === true
|
|
38429
|
+
? "Token saved. Exact sample match."
|
|
38430
|
+
: "Token saved. Sample completed; review the actual transcript.",
|
|
38431
|
+
voiceInputTestError: "",
|
|
38432
|
+
voiceInputTestTranscript: data.transcript || "",
|
|
38433
|
+
voiceInputTestLatencyMs: Number.isFinite(Number(data.duration_ms))
|
|
38434
|
+
? Number(data.duration_ms)
|
|
38435
|
+
: null,
|
|
38436
|
+
};
|
|
38437
|
+
} catch (err) {
|
|
38438
|
+
if (await handleHostPreferencesAuthFailure(err)) return;
|
|
38439
|
+
hostPreferencesState = {
|
|
38440
|
+
...hostPreferencesState,
|
|
38441
|
+
voiceInputTestRunning: false,
|
|
38442
|
+
voiceInputTestStatus: "",
|
|
38443
|
+
voiceInputTestError:
|
|
38444
|
+
err.message || "Voice Input token test failed.",
|
|
38445
|
+
voiceInputTestTranscript: "",
|
|
38446
|
+
voiceInputTestLatencyMs: null,
|
|
38447
|
+
};
|
|
38448
|
+
}
|
|
38449
|
+
void loadHostVoiceInputUsage({ force: true });
|
|
38450
|
+
renderHostPreferences();
|
|
38451
|
+
}
|
|
38452
|
+
|
|
36978
38453
|
async function saveHostPreferences() {
|
|
36979
38454
|
if (hostPreferencesState.saving) {
|
|
36980
38455
|
refreshHostPreferencesSaveButton();
|
|
@@ -37010,6 +38485,8 @@ Waiting for Claude login output…</pre
|
|
|
37010
38485
|
$("host-notification-app-sound-toggle")?.checked !== false;
|
|
37011
38486
|
const requestedDailyTelemetryEnabled =
|
|
37012
38487
|
$("host-daily-telemetry-toggle")?.checked === true;
|
|
38488
|
+
const requestedVoiceInputEnabled =
|
|
38489
|
+
getHostVoiceInputEnabledControlValue();
|
|
37013
38490
|
const claudeCommandInput = $("host-claude-command");
|
|
37014
38491
|
const requestedClaudeCommand = claudeCommandInput
|
|
37015
38492
|
? claudeCommandInput.value.trim()
|
|
@@ -37084,6 +38561,7 @@ Waiting for Claude login output…</pre
|
|
|
37084
38561
|
notificationSoundWebEnabled: requestedWebNotificationSound,
|
|
37085
38562
|
notificationSoundAppEnabled: requestedAppNotificationSound,
|
|
37086
38563
|
dailyTelemetryEnabled: requestedDailyTelemetryEnabled,
|
|
38564
|
+
voiceInputEnabled: requestedVoiceInputEnabled,
|
|
37087
38565
|
publicBaseUrl: requestedPublicBaseUrl,
|
|
37088
38566
|
defaultBrowsePath: requestedPath,
|
|
37089
38567
|
defaultProvider: nextDefaultProvider,
|
|
@@ -37113,6 +38591,10 @@ Waiting for Claude login output…</pre
|
|
|
37113
38591
|
notification_sound_web_enabled: requestedWebNotificationSound,
|
|
37114
38592
|
notification_sound_app_enabled: requestedAppNotificationSound,
|
|
37115
38593
|
daily_telemetry_enabled: requestedDailyTelemetryEnabled,
|
|
38594
|
+
voice_input: {
|
|
38595
|
+
enabled: requestedVoiceInputEnabled,
|
|
38596
|
+
token_action: "retain",
|
|
38597
|
+
},
|
|
37116
38598
|
direct_host_url: requestedPublicBaseUrl || null,
|
|
37117
38599
|
public_base_url: requestedPublicBaseUrl || null,
|
|
37118
38600
|
default_browse_path: requestedPath,
|
|
@@ -37739,6 +39221,55 @@ Waiting for Claude login output…</pre
|
|
|
37739
39221
|
syncCreateAllowedPathsShortcutState();
|
|
37740
39222
|
}
|
|
37741
39223
|
|
|
39224
|
+
function isCreateWebsiteEligible() {
|
|
39225
|
+
return createWebsiteAuthorityState.eligible === true;
|
|
39226
|
+
}
|
|
39227
|
+
|
|
39228
|
+
function syncCreateWebsiteAuthorityState() {
|
|
39229
|
+
const eligible = isCreateWebsiteEligible();
|
|
39230
|
+
const enabledInput = $("create-website-enabled");
|
|
39231
|
+
const accessSelect = $("create-website-access");
|
|
39232
|
+
const hint = $("create-website-authority-hint");
|
|
39233
|
+
if (enabledInput) {
|
|
39234
|
+
enabledInput.disabled = !eligible;
|
|
39235
|
+
if (!eligible) enabledInput.checked = false;
|
|
39236
|
+
}
|
|
39237
|
+
if (accessSelect) {
|
|
39238
|
+
accessSelect.disabled = !eligible;
|
|
39239
|
+
if (!eligible) accessSelect.value = "owner_only";
|
|
39240
|
+
}
|
|
39241
|
+
if (!eligible) setCreateWebsitePasswordValue("");
|
|
39242
|
+
if (hint) {
|
|
39243
|
+
hint.textContent =
|
|
39244
|
+
createWebsiteAuthorityState.reason ||
|
|
39245
|
+
"Website is available only for agents in the Browser Root.";
|
|
39246
|
+
hint.classList.toggle("hidden", eligible);
|
|
39247
|
+
}
|
|
39248
|
+
syncCreateWebsitePasswordMode();
|
|
39249
|
+
}
|
|
39250
|
+
|
|
39251
|
+
function setCreateWebsiteAuthorityState({
|
|
39252
|
+
folderPath = "",
|
|
39253
|
+
projectId = "",
|
|
39254
|
+
eligible = false,
|
|
39255
|
+
reason = "",
|
|
39256
|
+
} = {}) {
|
|
39257
|
+
createWebsiteAuthorityState = {
|
|
39258
|
+
folderPath: String(folderPath || "").trim(),
|
|
39259
|
+
projectId: String(projectId || "").trim(),
|
|
39260
|
+
eligible: eligible === true,
|
|
39261
|
+
reason:
|
|
39262
|
+
String(reason || "").trim() ||
|
|
39263
|
+
"Website is available only for agents in the Browser Root.",
|
|
39264
|
+
};
|
|
39265
|
+
if (eligible !== true) {
|
|
39266
|
+
setCreateWebsiteEnabledValue(false);
|
|
39267
|
+
setCreateWebsiteAccessValue("owner_only");
|
|
39268
|
+
setCreateWebsitePasswordValue("");
|
|
39269
|
+
}
|
|
39270
|
+
syncCreateWebsiteAuthorityState();
|
|
39271
|
+
}
|
|
39272
|
+
|
|
37742
39273
|
function setCreateWebsiteAccessValue(value) {
|
|
37743
39274
|
const select = $("create-website-access");
|
|
37744
39275
|
if (!select) return;
|
|
@@ -37774,16 +39305,19 @@ Waiting for Claude login output…</pre
|
|
|
37774
39305
|
const row = $("create-website-password-row");
|
|
37775
39306
|
const input = $("create-website-password");
|
|
37776
39307
|
const status = $("create-website-password-status");
|
|
39308
|
+
const eligible = isCreateWebsiteEligible();
|
|
37777
39309
|
const passwordMode = getCreateWebsiteAccessValue() === "password";
|
|
37778
39310
|
if (row) row.classList.remove("hidden");
|
|
37779
39311
|
if (input) {
|
|
37780
|
-
input.disabled = !passwordMode;
|
|
39312
|
+
input.disabled = !eligible || !passwordMode;
|
|
37781
39313
|
}
|
|
37782
39314
|
if (status) {
|
|
37783
|
-
status.textContent =
|
|
37784
|
-
|
|
37785
|
-
|
|
37786
|
-
|
|
39315
|
+
status.textContent = eligible
|
|
39316
|
+
? formatOwnerWebsitePasswordHint(
|
|
39317
|
+
getCreateWebsiteAccessValue(),
|
|
39318
|
+
input?.value || ""
|
|
39319
|
+
)
|
|
39320
|
+
: "Website settings are unavailable outside the Browser Root.";
|
|
37787
39321
|
}
|
|
37788
39322
|
}
|
|
37789
39323
|
|
|
@@ -37889,6 +39423,10 @@ Waiting for Claude login output…</pre
|
|
|
37889
39423
|
syncSessionSetupInterfaceStyleVisibility();
|
|
37890
39424
|
setCreateWebsiteEnabledValue(HOST_DEFAULT_SESSION_DEFAULTS.web.enabled);
|
|
37891
39425
|
setCreateWebsiteAccessValue(HOST_DEFAULT_SESSION_DEFAULTS.web.access);
|
|
39426
|
+
setCreateWebsiteAuthorityState({
|
|
39427
|
+
folderPath: startFolder,
|
|
39428
|
+
eligible: false,
|
|
39429
|
+
});
|
|
37892
39430
|
setCreateNotificationsEnabledValue(
|
|
37893
39431
|
HOST_DEFAULT_SESSION_DEFAULTS.notifications.enabled
|
|
37894
39432
|
);
|
|
@@ -37981,6 +39519,10 @@ Waiting for Claude login output…</pre
|
|
|
37981
39519
|
syncSessionSetupInterfaceStyleVisibility();
|
|
37982
39520
|
setCreateWebsiteEnabledValue(HOST_DEFAULT_SESSION_DEFAULTS.web.enabled);
|
|
37983
39521
|
setCreateWebsiteAccessValue(HOST_DEFAULT_SESSION_DEFAULTS.web.access);
|
|
39522
|
+
setCreateWebsiteAuthorityState({
|
|
39523
|
+
folderPath: record.agent_folder || "",
|
|
39524
|
+
eligible: false,
|
|
39525
|
+
});
|
|
37984
39526
|
setCreateNotificationsEnabledValue(
|
|
37985
39527
|
HOST_DEFAULT_SESSION_DEFAULTS.notifications.enabled
|
|
37986
39528
|
);
|
|
@@ -38389,14 +39931,15 @@ Waiting for Claude login output…</pre
|
|
|
38389
39931
|
if (liveSession?.website && typeof liveSession.website === "object") {
|
|
38390
39932
|
return liveSession.website;
|
|
38391
39933
|
}
|
|
38392
|
-
|
|
38393
|
-
|
|
38394
|
-
|
|
38395
|
-
|
|
38396
|
-
|
|
38397
|
-
|
|
38398
|
-
|
|
38399
|
-
|
|
39934
|
+
return {
|
|
39935
|
+
enabled: false,
|
|
39936
|
+
available: false,
|
|
39937
|
+
access: "owner_only",
|
|
39938
|
+
browser_root_authorized: false,
|
|
39939
|
+
reason: "session_folder_outside_browser_root",
|
|
39940
|
+
reason_message:
|
|
39941
|
+
"Website is available only for agents in the Browser Root.",
|
|
39942
|
+
};
|
|
38400
39943
|
}
|
|
38401
39944
|
|
|
38402
39945
|
function getOwnerVisibleWebsitePassword(website = {}) {
|
|
@@ -39038,7 +40581,6 @@ Waiting for Claude login output…</pre
|
|
|
39038
40581
|
liveSession = getSelectedLiveSession()
|
|
39039
40582
|
) {
|
|
39040
40583
|
const input = $("agent-profile-rename-input");
|
|
39041
|
-
const updateConfig = $("agent-profile-identity-update-config");
|
|
39042
40584
|
const saveBtn =
|
|
39043
40585
|
$("agent-profile-identity-save-btn") ||
|
|
39044
40586
|
$("agent-profile-rename-save-btn");
|
|
@@ -39046,10 +40588,6 @@ Waiting for Claude login output…</pre
|
|
|
39046
40588
|
if (!liveSession) {
|
|
39047
40589
|
input.value = "";
|
|
39048
40590
|
input.disabled = true;
|
|
39049
|
-
if (updateConfig) {
|
|
39050
|
-
updateConfig.checked = false;
|
|
39051
|
-
updateConfig.disabled = true;
|
|
39052
|
-
}
|
|
39053
40591
|
saveBtn.disabled = true;
|
|
39054
40592
|
saveBtn.textContent = "Save";
|
|
39055
40593
|
showError("agent-profile-rename-error", "");
|
|
@@ -39062,18 +40600,14 @@ Waiting for Claude login output…</pre
|
|
|
39062
40600
|
).trim();
|
|
39063
40601
|
const draftName = String(agentProfileRenameState.draft || "");
|
|
39064
40602
|
const normalizedDraft = draftName.trim();
|
|
39065
|
-
const persistIdentity = updateConfig?.checked === true;
|
|
39066
40603
|
input.value = draftName;
|
|
39067
40604
|
input.disabled = agentProfileRenameState.saving === true;
|
|
39068
|
-
if (updateConfig) {
|
|
39069
|
-
updateConfig.disabled = agentProfileRenameState.saving === true;
|
|
39070
|
-
}
|
|
39071
40605
|
saveBtn.textContent =
|
|
39072
40606
|
agentProfileRenameState.saving === true ? "Saving..." : "Save";
|
|
39073
40607
|
saveBtn.disabled =
|
|
39074
40608
|
agentProfileRenameState.saving === true ||
|
|
39075
40609
|
!normalizedDraft ||
|
|
39076
|
-
|
|
40610
|
+
normalizedDraft === currentName;
|
|
39077
40611
|
showError(
|
|
39078
40612
|
"agent-profile-rename-error",
|
|
39079
40613
|
agentProfileRenameState.error || ""
|
|
@@ -39091,8 +40625,6 @@ Waiting for Claude login output…</pre
|
|
|
39091
40625
|
const currentSessionName = String(
|
|
39092
40626
|
liveSession.sessionName || liveSession.session_name || ""
|
|
39093
40627
|
).trim();
|
|
39094
|
-
const updateConfig =
|
|
39095
|
-
$("agent-profile-identity-update-config")?.checked === true;
|
|
39096
40628
|
if (!nextSessionName) {
|
|
39097
40629
|
agentProfileRenameState = {
|
|
39098
40630
|
...agentProfileRenameState,
|
|
@@ -39101,7 +40633,7 @@ Waiting for Claude login output…</pre
|
|
|
39101
40633
|
renderAgentProfileRenameView(liveSession);
|
|
39102
40634
|
return;
|
|
39103
40635
|
}
|
|
39104
|
-
if (nextSessionName === currentSessionName
|
|
40636
|
+
if (nextSessionName === currentSessionName) {
|
|
39105
40637
|
agentProfileRenameState = {
|
|
39106
40638
|
...agentProfileRenameState,
|
|
39107
40639
|
draft: currentSessionName,
|
|
@@ -39123,7 +40655,6 @@ Waiting for Claude login output…</pre
|
|
|
39123
40655
|
const data = await api("POST", "/session/rename", {
|
|
39124
40656
|
session_id: liveSession.sessionId,
|
|
39125
40657
|
session_name: nextSessionName,
|
|
39126
|
-
update_config: updateConfig,
|
|
39127
40658
|
});
|
|
39128
40659
|
const resolvedSessionName = data.session_name || nextSessionName;
|
|
39129
40660
|
patchLiveSession(liveSession.sessionId, {
|
|
@@ -39138,11 +40669,7 @@ Waiting for Claude login output…</pre
|
|
|
39138
40669
|
resolvedSessionName
|
|
39139
40670
|
);
|
|
39140
40671
|
renderSelectedAgent();
|
|
39141
|
-
showBanner(
|
|
39142
|
-
data.config_mutated === true
|
|
39143
|
-
? `Renamed session to ${resolvedSessionName} and updated .oysterun/config.json.`
|
|
39144
|
-
: `Renamed session to ${resolvedSessionName}.`
|
|
39145
|
-
);
|
|
40672
|
+
showBanner(`Renamed session to ${resolvedSessionName}.`);
|
|
39146
40673
|
} catch (err) {
|
|
39147
40674
|
agentProfileRenameState = {
|
|
39148
40675
|
...agentProfileRenameState,
|
|
@@ -40377,7 +41904,6 @@ Waiting for Claude login output…</pre
|
|
|
40377
41904
|
"approval_policy",
|
|
40378
41905
|
"allow_dangerously_skip_permissions",
|
|
40379
41906
|
"dangerous_mode",
|
|
40380
|
-
"web_access",
|
|
40381
41907
|
"notifications_enabled",
|
|
40382
41908
|
"allowed_paths",
|
|
40383
41909
|
"runtime_capabilities",
|
|
@@ -40529,8 +42055,10 @@ Waiting for Claude login output…</pre
|
|
|
40529
42055
|
payload.interface_type || getCreateDefaultInterfaceType()
|
|
40530
42056
|
);
|
|
40531
42057
|
syncSessionSetupInterfaceStyleVisibility();
|
|
40532
|
-
|
|
40533
|
-
|
|
42058
|
+
setCreateWebsiteAuthorityState({
|
|
42059
|
+
folderPath: draft.agentFolder || "",
|
|
42060
|
+
eligible: false,
|
|
42061
|
+
});
|
|
40534
42062
|
setCreateTelegramSettingsValue({});
|
|
40535
42063
|
$("create-allowed-paths").value = normalizeAllowedPathsForForm(
|
|
40536
42064
|
payload.allowed_paths
|
|
@@ -40603,6 +42131,13 @@ Waiting for Claude login output…</pre
|
|
|
40603
42131
|
syncCreateAllowedPathsShortcutState();
|
|
40604
42132
|
refreshCreateStartButtonEnabled();
|
|
40605
42133
|
refreshUpdateSessionNameButton();
|
|
42134
|
+
if (draft.agentFolder) {
|
|
42135
|
+
void loadFolderConfigIntoCreateForm(draft.agentFolder, {
|
|
42136
|
+
fillAgentIdIfEmpty: false,
|
|
42137
|
+
applyFormValues: false,
|
|
42138
|
+
showError: false,
|
|
42139
|
+
});
|
|
42140
|
+
}
|
|
40606
42141
|
}
|
|
40607
42142
|
|
|
40608
42143
|
function readSessionSetupSchedulerDraftForEditor(
|
|
@@ -48648,14 +50183,6 @@ Waiting for Claude login output…</pre
|
|
|
48648
50183
|
const allowedPaths = isAllowedPathDebugUiVisible()
|
|
48649
50184
|
? parseAllowedPathsInput($("create-allowed-paths").value)
|
|
48650
50185
|
: null;
|
|
48651
|
-
const webAccess = getCreateWebsiteAccessValue();
|
|
48652
|
-
const webPassword =
|
|
48653
|
-
webAccess === "password" ? getCreateWebsitePasswordValue() : "";
|
|
48654
|
-
if (webAccess === "password" && !webPassword) {
|
|
48655
|
-
throw new Error(
|
|
48656
|
-
"Website Password is required when Website Access is Password. Switch Website Access away from Password before clearing it."
|
|
48657
|
-
);
|
|
48658
|
-
}
|
|
48659
50186
|
|
|
48660
50187
|
const payload = {
|
|
48661
50188
|
provider: createRuntime,
|
|
@@ -48672,8 +50199,6 @@ Waiting for Claude login output…</pre
|
|
|
48672
50199
|
createRuntime === "codex" ? codexApproval : undefined,
|
|
48673
50200
|
allow_dangerously_skip_permissions: allowDanger,
|
|
48674
50201
|
dangerous_mode: allowDanger,
|
|
48675
|
-
web_enabled: getCreateWebsiteEnabledValue(),
|
|
48676
|
-
web_access: webAccess,
|
|
48677
50202
|
notifications_enabled: getCreateNotificationsEnabledValue(),
|
|
48678
50203
|
install_oysterun_skills: getCreateInstallOysterunSkillsValue(),
|
|
48679
50204
|
...readTelegramFieldsPayload("create"),
|
|
@@ -48692,9 +50217,6 @@ Waiting for Claude login output…</pre
|
|
|
48692
50217
|
) {
|
|
48693
50218
|
payload.confirm_beta_provider_permission_mode = true;
|
|
48694
50219
|
}
|
|
48695
|
-
if (webPassword) {
|
|
48696
|
-
payload.web_password = webPassword;
|
|
48697
|
-
}
|
|
48698
50220
|
validateTelegramEnabledPayloadOrThrow(
|
|
48699
50221
|
payload,
|
|
48700
50222
|
getCreateTelegramConfiguredState()
|
|
@@ -48702,6 +50224,23 @@ Waiting for Claude login output…</pre
|
|
|
48702
50224
|
return payload;
|
|
48703
50225
|
}
|
|
48704
50226
|
|
|
50227
|
+
function buildCreateWebsitePayload() {
|
|
50228
|
+
if (!isCreateWebsiteEligible()) return null;
|
|
50229
|
+
const webAccess = getCreateWebsiteAccessValue();
|
|
50230
|
+
const webPassword =
|
|
50231
|
+
webAccess === "password" ? getCreateWebsitePasswordValue() : "";
|
|
50232
|
+
if (webAccess === "password" && !webPassword) {
|
|
50233
|
+
throw new Error(
|
|
50234
|
+
"Website Password is required when Website Access is Password. Switch Website Access away from Password before clearing it."
|
|
50235
|
+
);
|
|
50236
|
+
}
|
|
50237
|
+
return {
|
|
50238
|
+
web_enabled: getCreateWebsiteEnabledValue(),
|
|
50239
|
+
web_access: webAccess,
|
|
50240
|
+
...(webPassword ? { web_password: webPassword } : {}),
|
|
50241
|
+
};
|
|
50242
|
+
}
|
|
50243
|
+
|
|
48705
50244
|
function readCreateFormRequest() {
|
|
48706
50245
|
const agent_id = $("create-agent-id").value.trim();
|
|
48707
50246
|
const agent_folder = $("create-agent-folder").value.trim();
|
|
@@ -48724,12 +50263,17 @@ Waiting for Claude login output…</pre
|
|
|
48724
50263
|
configToggleChecked
|
|
48725
50264
|
),
|
|
48726
50265
|
sessionPayload: buildCreateSessionPayload(),
|
|
50266
|
+
websitePayload: buildCreateWebsitePayload(),
|
|
48727
50267
|
};
|
|
48728
50268
|
}
|
|
48729
50269
|
|
|
48730
50270
|
async function submitCreateAgent() {
|
|
48731
50271
|
if (!hasRunnableCreateProvider()) {
|
|
48732
|
-
const message =
|
|
50272
|
+
const message = isProviderCatalogInitialPending()
|
|
50273
|
+
? "Checking providers. Wait for the Host provider check to finish."
|
|
50274
|
+
: isProviderCatalogRequestFailed()
|
|
50275
|
+
? "Could not load provider status. Retry the provider check before starting a session."
|
|
50276
|
+
: createRuntime
|
|
48733
50277
|
? `${getProviderDisplayLabel(
|
|
48734
50278
|
createRuntime
|
|
48735
50279
|
)} is currently unavailable on this Host. Update Host Preferences before starting a session.`
|
|
@@ -48754,6 +50298,7 @@ Waiting for Claude login output…</pre
|
|
|
48754
50298
|
persistConfig,
|
|
48755
50299
|
preventConfigCreate,
|
|
48756
50300
|
sessionPayload,
|
|
50301
|
+
websitePayload,
|
|
48757
50302
|
} = request;
|
|
48758
50303
|
const sessionSetupProof = applyCreateSessionSetupProofAttributes(
|
|
48759
50304
|
buildCreateSessionSetupProviderModelPermissionProof(sessionPayload)
|
|
@@ -48791,28 +50336,37 @@ Waiting for Claude login output…</pre
|
|
|
48791
50336
|
|
|
48792
50337
|
const configPersistenceAction =
|
|
48793
50338
|
getCreateConfigPersistenceAction(configToggleMode);
|
|
48794
|
-
|
|
48795
|
-
|
|
48796
|
-
|
|
48797
|
-
|
|
48798
|
-
|
|
50339
|
+
const shouldPersistWebsite = Boolean(websitePayload);
|
|
50340
|
+
let failureStep =
|
|
50341
|
+
shouldPersistConfig || shouldPersistWebsite
|
|
50342
|
+
? `Could not ${configPersistenceAction.toLowerCase()} .oysterun/config.json`
|
|
50343
|
+
: resumeSessionId
|
|
50344
|
+
? "Could not resume session"
|
|
50345
|
+
: "Could not start session";
|
|
48799
50346
|
try {
|
|
48800
|
-
if (shouldPersistConfig) {
|
|
50347
|
+
if (shouldPersistConfig || shouldPersistWebsite) {
|
|
48801
50348
|
await apiWithAuthRetry(
|
|
48802
50349
|
"PUT",
|
|
48803
50350
|
"/agent/config",
|
|
48804
50351
|
{
|
|
48805
50352
|
agent_id,
|
|
48806
50353
|
agent_folder,
|
|
48807
|
-
...
|
|
48808
|
-
|
|
48809
|
-
|
|
50354
|
+
...(shouldPersistConfig
|
|
50355
|
+
? {
|
|
50356
|
+
...sessionPayload,
|
|
50357
|
+
session_setup_provider_model_permission_proof:
|
|
50358
|
+
sessionSetupProof,
|
|
50359
|
+
}
|
|
50360
|
+
: {}),
|
|
50361
|
+
...(websitePayload || {}),
|
|
48810
50362
|
},
|
|
48811
50363
|
{
|
|
48812
50364
|
onRetry: () => {
|
|
48813
50365
|
if (!isCurrentCreateAttempt(attemptId)) return;
|
|
48814
50366
|
setCreateStatus(
|
|
48815
|
-
|
|
50367
|
+
shouldPersistConfig
|
|
50368
|
+
? `${configPersistenceAction} .oysterun/config.json...`
|
|
50369
|
+
: "Updating Website settings...",
|
|
48816
50370
|
"Retrying config save after a brief auth settle."
|
|
48817
50371
|
);
|
|
48818
50372
|
},
|
|
@@ -50190,6 +51744,7 @@ Waiting for Claude login output…</pre
|
|
|
50190
51744
|
const folderPath = String(path || "").trim();
|
|
50191
51745
|
if (!folderPath) {
|
|
50192
51746
|
hideCreateConfigToggle("");
|
|
51747
|
+
setCreateWebsiteAuthorityState();
|
|
50193
51748
|
refreshCreateStartButtonEnabled();
|
|
50194
51749
|
return;
|
|
50195
51750
|
}
|
|
@@ -50207,20 +51762,38 @@ Waiting for Claude login output…</pre
|
|
|
50207
51762
|
)}${providerQuery}`
|
|
50208
51763
|
);
|
|
50209
51764
|
const resolvedFolderPath = data.agent_folder || folderPath;
|
|
51765
|
+
const currentFolderPath = String(
|
|
51766
|
+
$("create-agent-folder").value || ""
|
|
51767
|
+
).trim();
|
|
51768
|
+
if (
|
|
51769
|
+
requestId !== latestCreateFolderConfigRequestId ||
|
|
51770
|
+
currentFolderPath !== folderPath
|
|
51771
|
+
) {
|
|
51772
|
+
return;
|
|
51773
|
+
}
|
|
51774
|
+
setCreateWebsiteAuthorityState({
|
|
51775
|
+
folderPath: resolvedFolderPath,
|
|
51776
|
+
projectId: data.websiteProjectId || "",
|
|
51777
|
+
eligible:
|
|
51778
|
+
data.websiteEligible === true ||
|
|
51779
|
+
data.website?.browser_root_authorized === true,
|
|
51780
|
+
reason:
|
|
51781
|
+
data.website?.reason_message ||
|
|
51782
|
+
"Website is available only for agents in the Browser Root.",
|
|
51783
|
+
});
|
|
51784
|
+
if (opts.applyFormValues === false && isCreateWebsiteEligible()) {
|
|
51785
|
+
setCreateWebsiteEnabledValue(
|
|
51786
|
+
HOST_DEFAULT_SESSION_DEFAULTS.web.enabled
|
|
51787
|
+
);
|
|
51788
|
+
setCreateWebsiteAccessValue(
|
|
51789
|
+
HOST_DEFAULT_SESSION_DEFAULTS.web.access
|
|
51790
|
+
);
|
|
51791
|
+
}
|
|
50210
51792
|
applyCreateConfigToggleMode(
|
|
50211
51793
|
resolvedFolderPath,
|
|
50212
51794
|
data.hasConfig === true
|
|
50213
51795
|
);
|
|
50214
51796
|
if (opts.applyFormValues !== false) {
|
|
50215
|
-
const currentFolderPath = String(
|
|
50216
|
-
$("create-agent-folder").value || ""
|
|
50217
|
-
).trim();
|
|
50218
|
-
if (
|
|
50219
|
-
requestId !== latestCreateFolderConfigRequestId ||
|
|
50220
|
-
currentFolderPath !== folderPath
|
|
50221
|
-
) {
|
|
50222
|
-
return;
|
|
50223
|
-
}
|
|
50224
51797
|
const preferencesUntouched =
|
|
50225
51798
|
createFormPreferenceVersion === requestPreferenceVersion;
|
|
50226
51799
|
$("create-agent-folder").value = resolvedFolderPath;
|
|
@@ -50307,6 +51880,10 @@ Waiting for Claude login output…</pre
|
|
|
50307
51880
|
refreshCreateStartButtonEnabled();
|
|
50308
51881
|
} catch (err) {
|
|
50309
51882
|
hideCreateConfigToggle(folderPath);
|
|
51883
|
+
setCreateWebsiteAuthorityState({
|
|
51884
|
+
folderPath,
|
|
51885
|
+
eligible: false,
|
|
51886
|
+
});
|
|
50310
51887
|
setCreateProviderSkillStatus(null);
|
|
50311
51888
|
setCreateProviderTrustStatus(null);
|
|
50312
51889
|
refreshCreateStartButtonEnabled();
|
|
@@ -50827,6 +52404,10 @@ Waiting for Claude login output…</pre
|
|
|
50827
52404
|
markCreatePreferencesEdited();
|
|
50828
52405
|
syncCreateAllowedPathsShortcutState();
|
|
50829
52406
|
hideCreateConfigToggle($("create-agent-folder").value);
|
|
52407
|
+
setCreateWebsiteAuthorityState({
|
|
52408
|
+
folderPath: $("create-agent-folder").value,
|
|
52409
|
+
eligible: false,
|
|
52410
|
+
});
|
|
50830
52411
|
refreshUpdateSessionNameButton();
|
|
50831
52412
|
void refreshCreateProviderTrustStatus();
|
|
50832
52413
|
refreshCreateStartButtonEnabled();
|
|
@@ -50834,6 +52415,7 @@ Waiting for Claude login output…</pre
|
|
|
50834
52415
|
$("create-agent-id").addEventListener("input", () => {
|
|
50835
52416
|
markCreatePreferencesEdited();
|
|
50836
52417
|
syncCreateSessionNameDefault();
|
|
52418
|
+
syncCreateWebsiteAuthorityState();
|
|
50837
52419
|
void refreshCreateProviderSkillStatus();
|
|
50838
52420
|
void refreshCreateProviderTrustStatus();
|
|
50839
52421
|
refreshCreateStartButtonEnabled();
|
|
@@ -50898,7 +52480,7 @@ Waiting for Claude login output…</pre
|
|
|
50898
52480
|
);
|
|
50899
52481
|
if (
|
|
50900
52482
|
control instanceof HTMLInputElement &&
|
|
50901
|
-
["text", "url", "search"].includes(control.type)
|
|
52483
|
+
["text", "url", "search", "password"].includes(control.type)
|
|
50902
52484
|
) {
|
|
50903
52485
|
control.addEventListener(
|
|
50904
52486
|
"input",
|
|
@@ -50906,6 +52488,10 @@ Waiting for Claude login output…</pre
|
|
|
50906
52488
|
);
|
|
50907
52489
|
}
|
|
50908
52490
|
}
|
|
52491
|
+
$("host-voice-input-token")?.addEventListener(
|
|
52492
|
+
"input",
|
|
52493
|
+
handleHostVoiceInputTokenInput
|
|
52494
|
+
);
|
|
50909
52495
|
document.addEventListener("change", (event) => {
|
|
50910
52496
|
if (event.target.closest("[data-host-default-runtime-capability]")) {
|
|
50911
52497
|
stageHostPreferencesDraftFromControls();
|
|
@@ -50914,6 +52500,9 @@ Waiting for Claude login output…</pre
|
|
|
50914
52500
|
window.useStartFolderForAllowedPaths = useStartFolderForAllowedPaths;
|
|
50915
52501
|
window.openPermissionsSettings = openPermissionsSettings;
|
|
50916
52502
|
window.saveHostPreferences = saveHostPreferences;
|
|
52503
|
+
window.discardHostVoiceInputTokenDraft = discardHostVoiceInputTokenDraft;
|
|
52504
|
+
window.removeHostVoiceInputSavedToken = removeHostVoiceInputSavedToken;
|
|
52505
|
+
window.testHostVoiceInput = testHostVoiceInput;
|
|
50917
52506
|
window.generateDirectHostLoginQr = generateDirectHostLoginQr;
|
|
50918
52507
|
window.copyHostPreferencesDirectHostUrl =
|
|
50919
52508
|
copyHostPreferencesDirectHostUrl;
|
|
@@ -51088,10 +52677,6 @@ Waiting for Claude login output…</pre
|
|
|
51088
52677
|
refreshAgentProfileWorkspacePolicySaveState();
|
|
51089
52678
|
return;
|
|
51090
52679
|
}
|
|
51091
|
-
if (event.target.closest("#agent-profile-identity-update-config")) {
|
|
51092
|
-
renderAgentProfileRenameView(getSelectedLiveSession());
|
|
51093
|
-
return;
|
|
51094
|
-
}
|
|
51095
52680
|
handleSessionLoopChange(event);
|
|
51096
52681
|
handleHostSchedulerChange(event);
|
|
51097
52682
|
});
|