oysterun 1.5.6 → 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 +1528 -102
- package/dev/client/web-chat/dist/assets/{ReactPrism-isi6q-rt.js → ReactPrism-DNQ9nZSp.js} +1 -1
- package/dev/client/web-chat/dist/assets/{ReactPrism-isi6q-rt.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-CS0AuJg_.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-Chh0JkSx.js → index-Dt0tJQEo.js} +2 -2
- package/dev/client/web-chat/dist/assets/{index-Chh0JkSx.js.map → index-Dt0tJQEo.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-CLXxZ4tL.js → index-kph-A9_0.js} +1 -1
- package/dev/client/web-chat/dist/assets/{index-CLXxZ4tL.js.map → index-kph-A9_0.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{pdf-BHndlpDv.js → pdf-Dz-8X_5I.js} +3 -3
- package/dev/client/web-chat/dist/assets/{pdf-BHndlpDv.js.map → pdf-Dz-8X_5I.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DL4-fcjv.js → web-8cohp67o.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DL4-fcjv.js.map → web-8cohp67o.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DD_lXOHn.js → web-z_YJW2TC.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DD_lXOHn.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/host-service/assets/voice-input/D1.wav +0 -0
- package/host-service/browser-root-project-index.mjs +0 -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 +482 -122
- 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-CS0AuJg_.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
|
|
@@ -9116,6 +9237,168 @@
|
|
|
9116
9237
|
</div>
|
|
9117
9238
|
</div>
|
|
9118
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>
|
|
9119
9402
|
<section class="table-panel">
|
|
9120
9403
|
<div class="table-title">
|
|
9121
9404
|
<div class="table-title-main">
|
|
@@ -9792,6 +10075,55 @@
|
|
|
9792
10075
|
`;
|
|
9793
10076
|
}
|
|
9794
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
|
+
|
|
9795
10127
|
function ChangePasswordView() {
|
|
9796
10128
|
return html`
|
|
9797
10129
|
<section id="change-password-view" class="view view-page-scroll">
|
|
@@ -10580,19 +10912,6 @@ Terminal output will appear here.</pre
|
|
|
10580
10912
|
class="session-profile-action-stack"
|
|
10581
10913
|
data-session-profile-action-block="session_identity"
|
|
10582
10914
|
>
|
|
10583
|
-
<label
|
|
10584
|
-
class="toggle-row"
|
|
10585
|
-
data-session-profile-identity-update-config-row="session_identity"
|
|
10586
|
-
>
|
|
10587
|
-
<span>
|
|
10588
|
-
<strong>Update .oysterun/config.json</strong>
|
|
10589
|
-
</span>
|
|
10590
|
-
<input
|
|
10591
|
-
id="agent-profile-identity-update-config"
|
|
10592
|
-
type="checkbox"
|
|
10593
|
-
data-session-profile-update-config="session_identity"
|
|
10594
|
-
/>
|
|
10595
|
-
</label>
|
|
10596
10915
|
<button
|
|
10597
10916
|
class="btn-secondary session-profile-save-row"
|
|
10598
10917
|
id="agent-profile-identity-save-btn"
|
|
@@ -11406,6 +11725,7 @@ Waiting for Claude login output…</pre
|
|
|
11406
11725
|
<${SessionLoopView} />
|
|
11407
11726
|
<${SessionSetupView} />
|
|
11408
11727
|
<${HostPreferencesView} />
|
|
11728
|
+
<${VoiceInputUsageView} />
|
|
11409
11729
|
<${ChangePasswordView} />
|
|
11410
11730
|
<${TerminalView} />
|
|
11411
11731
|
<${FolderPickerView} />
|
|
@@ -13334,7 +13654,7 @@ Waiting for Claude login output…</pre
|
|
|
13334
13654
|
let latestCreateFolderConfigRequestId = 0;
|
|
13335
13655
|
let createWebsiteAuthorityState = {
|
|
13336
13656
|
folderPath: "",
|
|
13337
|
-
|
|
13657
|
+
projectId: "",
|
|
13338
13658
|
eligible: false,
|
|
13339
13659
|
reason: "Website is available only for agents in the Browser Root.",
|
|
13340
13660
|
};
|
|
@@ -13388,8 +13708,37 @@ Waiting for Claude login output…</pre
|
|
|
13388
13708
|
preview: null,
|
|
13389
13709
|
roots: {},
|
|
13390
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
|
+
|
|
13391
13739
|
function createProviderCatalogState() {
|
|
13392
13740
|
return {
|
|
13741
|
+
status: PROVIDER_CATALOG_STATUS_UNKNOWN,
|
|
13393
13742
|
loaded: false,
|
|
13394
13743
|
loading: false,
|
|
13395
13744
|
error: "",
|
|
@@ -13459,6 +13808,7 @@ Waiting for Claude login output…</pre
|
|
|
13459
13808
|
notificationSoundWebEnabled = true,
|
|
13460
13809
|
notificationSoundAppEnabled = true,
|
|
13461
13810
|
dailyTelemetryEnabled = false,
|
|
13811
|
+
voiceInputEnabled = false,
|
|
13462
13812
|
defaultWebsiteAccess = HOST_DEFAULT_SESSION_DEFAULTS.web.access,
|
|
13463
13813
|
defaultNotificationsEnabled = HOST_DEFAULT_SESSION_DEFAULTS
|
|
13464
13814
|
.notifications.enabled,
|
|
@@ -13485,6 +13835,7 @@ Waiting for Claude login output…</pre
|
|
|
13485
13835
|
notificationSoundWebEnabled,
|
|
13486
13836
|
notificationSoundAppEnabled,
|
|
13487
13837
|
dailyTelemetryEnabled,
|
|
13838
|
+
voiceInputEnabled,
|
|
13488
13839
|
defaultWebsiteAccess,
|
|
13489
13840
|
defaultNotificationsEnabled,
|
|
13490
13841
|
defaultRuntimeCapabilities: normalizeRuntimeCapabilityState(
|
|
@@ -13516,6 +13867,34 @@ Waiting for Claude login output…</pre
|
|
|
13516
13867
|
dailyTelemetryEnabled: false,
|
|
13517
13868
|
dailyTelemetryConsentRecordedAt: "",
|
|
13518
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: "",
|
|
13519
13898
|
defaultWebsiteAccess: HOST_DEFAULT_SESSION_DEFAULTS.web.access,
|
|
13520
13899
|
defaultNotificationsEnabled:
|
|
13521
13900
|
HOST_DEFAULT_SESSION_DEFAULTS.notifications.enabled,
|
|
@@ -13589,6 +13968,7 @@ Waiting for Claude login output…</pre
|
|
|
13589
13968
|
};
|
|
13590
13969
|
}
|
|
13591
13970
|
let providerCatalogState = createProviderCatalogState();
|
|
13971
|
+
let providerCatalogLoadPromise = null;
|
|
13592
13972
|
let providerModelRefreshState = {
|
|
13593
13973
|
provider: "",
|
|
13594
13974
|
refreshing: false,
|
|
@@ -13614,6 +13994,10 @@ Waiting for Claude login output…</pre
|
|
|
13614
13994
|
let browserSurfaceState = createBrowserSurfaceState();
|
|
13615
13995
|
let browserSurfaceLaunchRequestId = 0;
|
|
13616
13996
|
let hostPreferencesState = createHostPreferencesState();
|
|
13997
|
+
let hostVoiceInputSampleObjectUrl = "";
|
|
13998
|
+
let hostVoiceInputSampleLoadPromise = null;
|
|
13999
|
+
let hostVoiceInputNativeAppVersionLoadPromise = null;
|
|
14000
|
+
let hostVoiceInputUsageLoadPromise = null;
|
|
13617
14001
|
let hostRestartHandoffTimer = null;
|
|
13618
14002
|
let hostRestartLoginGatePollTimer = null;
|
|
13619
14003
|
let hostRestartLoginGatePollGeneration = 0;
|
|
@@ -14039,6 +14423,7 @@ Waiting for Claude login output…</pre
|
|
|
14039
14423
|
$("host-notification-app-sound-toggle")?.checked !== false,
|
|
14040
14424
|
dailyTelemetryEnabled:
|
|
14041
14425
|
$("host-daily-telemetry-toggle")?.checked === true,
|
|
14426
|
+
voiceInputEnabled: getHostVoiceInputEnabledControlValue(),
|
|
14042
14427
|
defaultWebsiteAccess: hostPreferencesState.defaultWebsiteAccess,
|
|
14043
14428
|
defaultNotificationsEnabled:
|
|
14044
14429
|
$("host-default-notifications-enabled")?.checked !== false,
|
|
@@ -14093,6 +14478,7 @@ Waiting for Claude login output…</pre
|
|
|
14093
14478
|
notificationSoundWebEnabled: draft.notificationSoundWebEnabled,
|
|
14094
14479
|
notificationSoundAppEnabled: draft.notificationSoundAppEnabled,
|
|
14095
14480
|
dailyTelemetryEnabled: draft.dailyTelemetryEnabled,
|
|
14481
|
+
voiceInputEnabled: draft.voiceInputEnabled,
|
|
14096
14482
|
defaultWebsiteAccess: draft.defaultWebsiteAccess,
|
|
14097
14483
|
defaultNotificationsEnabled: draft.defaultNotificationsEnabled,
|
|
14098
14484
|
defaultRuntimeCapabilities: normalizeRuntimeCapabilityState(
|
|
@@ -14125,6 +14511,7 @@ Waiting for Claude login output…</pre
|
|
|
14125
14511
|
a.notificationSoundWebEnabled === b.notificationSoundWebEnabled &&
|
|
14126
14512
|
a.notificationSoundAppEnabled === b.notificationSoundAppEnabled &&
|
|
14127
14513
|
a.dailyTelemetryEnabled === b.dailyTelemetryEnabled &&
|
|
14514
|
+
a.voiceInputEnabled === b.voiceInputEnabled &&
|
|
14128
14515
|
a.defaultWebsiteAccess === b.defaultWebsiteAccess &&
|
|
14129
14516
|
a.defaultNotificationsEnabled === b.defaultNotificationsEnabled &&
|
|
14130
14517
|
JSON.stringify(a.defaultRuntimeCapabilities) ===
|
|
@@ -14184,6 +14571,7 @@ Waiting for Claude login output…</pre
|
|
|
14184
14571
|
const normalized = normalizeClientRoute(route);
|
|
14185
14572
|
return (
|
|
14186
14573
|
normalized.screen === "host-preferences" ||
|
|
14574
|
+
normalized.screen === "voice-input-usage" ||
|
|
14187
14575
|
(normalized.screen === "folder-picker" &&
|
|
14188
14576
|
normalized.targetInputId === HOST_PREFERENCES_FOLDER_PICKER_TARGET)
|
|
14189
14577
|
);
|
|
@@ -14199,6 +14587,8 @@ Waiting for Claude login output…</pre
|
|
|
14199
14587
|
defaultBrowsePath: savedDraft.defaultBrowsePath,
|
|
14200
14588
|
notificationSoundWebEnabled: savedDraft.notificationSoundWebEnabled,
|
|
14201
14589
|
notificationSoundAppEnabled: savedDraft.notificationSoundAppEnabled,
|
|
14590
|
+
dailyTelemetryEnabled: savedDraft.dailyTelemetryEnabled,
|
|
14591
|
+
voiceInputEnabled: savedDraft.voiceInputEnabled,
|
|
14202
14592
|
defaultWebsiteAccess: savedDraft.defaultWebsiteAccess,
|
|
14203
14593
|
defaultNotificationsEnabled: savedDraft.defaultNotificationsEnabled,
|
|
14204
14594
|
defaultRuntimeCapabilities: normalizeRuntimeCapabilityState(
|
|
@@ -14234,6 +14624,7 @@ Waiting for Claude login output…</pre
|
|
|
14234
14624
|
const normalized = normalizeClientRoute(route);
|
|
14235
14625
|
return (
|
|
14236
14626
|
normalized.screen === "host-preferences" ||
|
|
14627
|
+
normalized.screen === "voice-input-usage" ||
|
|
14237
14628
|
normalized.screen === "agent-profile"
|
|
14238
14629
|
);
|
|
14239
14630
|
}
|
|
@@ -14242,6 +14633,14 @@ Waiting for Claude login output…</pre
|
|
|
14242
14633
|
const current = normalizeClientRoute(currentRoute);
|
|
14243
14634
|
const next = normalizeClientRoute(nextRoute);
|
|
14244
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
|
+
}
|
|
14245
14644
|
if (
|
|
14246
14645
|
current.screen === "host-preferences" &&
|
|
14247
14646
|
next.screen === "folder-picker" &&
|
|
@@ -14353,11 +14752,8 @@ Waiting for Claude login output…</pre
|
|
|
14353
14752
|
liveSession.sessionName || liveSession.session_name || ""
|
|
14354
14753
|
).trim();
|
|
14355
14754
|
const draftName = String(agentProfileRenameState.draft || "").trim();
|
|
14356
|
-
const updateConfig =
|
|
14357
|
-
$("agent-profile-identity-update-config")?.checked === true;
|
|
14358
14755
|
return (
|
|
14359
14756
|
agentProfileRenameState.dirty === true ||
|
|
14360
|
-
updateConfig === true ||
|
|
14361
14757
|
(Boolean(draftName) && draftName !== currentName)
|
|
14362
14758
|
);
|
|
14363
14759
|
}
|
|
@@ -14397,7 +14793,10 @@ Waiting for Claude login output…</pre
|
|
|
14397
14793
|
|
|
14398
14794
|
function getP75DirtyFormState() {
|
|
14399
14795
|
const current = normalizeClientRoute(getCurrentRoute());
|
|
14400
|
-
if (
|
|
14796
|
+
if (
|
|
14797
|
+
current.screen === "host-preferences" ||
|
|
14798
|
+
current.screen === "voice-input-usage"
|
|
14799
|
+
) {
|
|
14401
14800
|
return hasUnsavedHostPreferencesChanges()
|
|
14402
14801
|
? {
|
|
14403
14802
|
screen: "host-preferences",
|
|
@@ -15137,6 +15536,9 @@ Waiting for Claude login output…</pre
|
|
|
15137
15536
|
// topbar/back handlers execute a declared route map instead of browser history.
|
|
15138
15537
|
function getFallbackRoute(route = currentRoute) {
|
|
15139
15538
|
const normalized = normalizeClientRoute(route);
|
|
15539
|
+
if (normalized.screen === "voice-input-usage") {
|
|
15540
|
+
return buildSettingsRoute();
|
|
15541
|
+
}
|
|
15140
15542
|
if (normalized.screen === "file-preview") {
|
|
15141
15543
|
// Source-aware File Preview routes return to their validated source first.
|
|
15142
15544
|
// Direct or invalid routes still fall back to the containing Explorer.
|
|
@@ -15197,6 +15599,7 @@ Waiting for Claude login output…</pre
|
|
|
15197
15599
|
const normalized = normalizeClientRoute(route);
|
|
15198
15600
|
return (
|
|
15199
15601
|
normalized.screen === "chat" ||
|
|
15602
|
+
normalized.screen === "voice-input-usage" ||
|
|
15200
15603
|
normalized.screen === "file-preview" ||
|
|
15201
15604
|
(normalized.screen === "mail" && Boolean(normalized.mailId)) ||
|
|
15202
15605
|
(normalized.screen === "folder-picker" &&
|
|
@@ -19226,12 +19629,13 @@ Waiting for Claude login output…</pre
|
|
|
19226
19629
|
entry,
|
|
19227
19630
|
providerId,
|
|
19228
19631
|
commandAvailable,
|
|
19632
|
+
authSupported,
|
|
19229
19633
|
canStartLogin
|
|
19230
19634
|
) {
|
|
19231
19635
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
19232
19636
|
return {
|
|
19233
19637
|
provider: providerId,
|
|
19234
|
-
supported:
|
|
19638
|
+
supported: authSupported,
|
|
19235
19639
|
canStartLogin,
|
|
19236
19640
|
state: "unknown",
|
|
19237
19641
|
message: "",
|
|
@@ -19329,6 +19733,7 @@ Waiting for Claude login output…</pre
|
|
|
19329
19733
|
entry.auth_status,
|
|
19330
19734
|
providerId,
|
|
19331
19735
|
entry.command_available === true,
|
|
19736
|
+
entry.auth_supported === true,
|
|
19332
19737
|
entry.auth_start_supported === true
|
|
19333
19738
|
),
|
|
19334
19739
|
modelCatalogStatus:
|
|
@@ -19439,6 +19844,20 @@ Waiting for Claude login output…</pre
|
|
|
19439
19844
|
return getProviderCatalogEntry(providerId)?.commandAvailable === true;
|
|
19440
19845
|
}
|
|
19441
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
|
+
|
|
19442
19861
|
function getProviderAuthStatus(providerId) {
|
|
19443
19862
|
return getProviderCatalogEntry(providerId)?.authStatus || null;
|
|
19444
19863
|
}
|
|
@@ -19454,6 +19873,7 @@ Waiting for Claude login output…</pre
|
|
|
19454
19873
|
nextStatus,
|
|
19455
19874
|
providerId,
|
|
19456
19875
|
entry.commandAvailable === true,
|
|
19876
|
+
entry.authSupported === true,
|
|
19457
19877
|
entry.authStartSupported === true
|
|
19458
19878
|
),
|
|
19459
19879
|
}
|
|
@@ -19491,7 +19911,12 @@ Waiting for Claude login output…</pre
|
|
|
19491
19911
|
function buildDefaultProviderWarning(
|
|
19492
19912
|
savedProvider = hostPreferencesState.defaultProvider
|
|
19493
19913
|
) {
|
|
19494
|
-
if (
|
|
19914
|
+
if (
|
|
19915
|
+
!savedProvider ||
|
|
19916
|
+
isProviderCatalogInitialPending() ||
|
|
19917
|
+
isProviderCatalogRequestFailed() ||
|
|
19918
|
+
isProviderAvailable(savedProvider)
|
|
19919
|
+
) {
|
|
19495
19920
|
return "";
|
|
19496
19921
|
}
|
|
19497
19922
|
const effectiveProvider =
|
|
@@ -21173,6 +21598,10 @@ Waiting for Claude login output…</pre
|
|
|
21173
21598
|
return normalizeClientRoute({ screen: "host-preferences" });
|
|
21174
21599
|
}
|
|
21175
21600
|
|
|
21601
|
+
function buildVoiceInputUsageRoute() {
|
|
21602
|
+
return normalizeClientRoute({ screen: "voice-input-usage" });
|
|
21603
|
+
}
|
|
21604
|
+
|
|
21176
21605
|
function buildChangePasswordRoute() {
|
|
21177
21606
|
return normalizeClientRoute({ screen: "change-password" });
|
|
21178
21607
|
}
|
|
@@ -21437,6 +21866,9 @@ Waiting for Claude login output…</pre
|
|
|
21437
21866
|
if (screen === "host-preferences") {
|
|
21438
21867
|
return { screen: "host-preferences", warning };
|
|
21439
21868
|
}
|
|
21869
|
+
if (screen === "voice-input-usage") {
|
|
21870
|
+
return { screen: "voice-input-usage", warning };
|
|
21871
|
+
}
|
|
21440
21872
|
if (screen === "change-password") {
|
|
21441
21873
|
return { screen: "change-password", warning };
|
|
21442
21874
|
}
|
|
@@ -21668,6 +22100,9 @@ Waiting for Claude login output…</pre
|
|
|
21668
22100
|
if (pathname === "/app/settings") {
|
|
21669
22101
|
return buildSettingsRoute();
|
|
21670
22102
|
}
|
|
22103
|
+
if (pathname === "/app/host-preferences/voice-input-usage") {
|
|
22104
|
+
return buildVoiceInputUsageRoute();
|
|
22105
|
+
}
|
|
21671
22106
|
if (pathname === "/app/change-password") {
|
|
21672
22107
|
return buildChangePasswordRoute();
|
|
21673
22108
|
}
|
|
@@ -21795,6 +22230,8 @@ Waiting for Claude login output…</pre
|
|
|
21795
22230
|
}
|
|
21796
22231
|
} else if (normalized.screen === "host-preferences") {
|
|
21797
22232
|
url.pathname = "/app/settings";
|
|
22233
|
+
} else if (normalized.screen === "voice-input-usage") {
|
|
22234
|
+
url.pathname = "/app/host-preferences/voice-input-usage";
|
|
21798
22235
|
} else if (normalized.screen === "change-password") {
|
|
21799
22236
|
url.pathname = "/app/change-password";
|
|
21800
22237
|
} else if (normalized.screen === "terminal") {
|
|
@@ -22026,6 +22463,12 @@ Waiting for Claude login output…</pre
|
|
|
22026
22463
|
}
|
|
22027
22464
|
} else if (normalized.screen === "host-preferences") {
|
|
22028
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();
|
|
22029
22472
|
} else if (normalized.screen === "change-password") {
|
|
22030
22473
|
renderChangePasswordView();
|
|
22031
22474
|
} else if (normalized.screen === "terminal") {
|
|
@@ -24987,6 +25430,7 @@ Waiting for Claude login output…</pre
|
|
|
24987
25430
|
explorer: "file_explorer",
|
|
24988
25431
|
"session-setup": "session_setup",
|
|
24989
25432
|
"host-preferences": "host_preferences",
|
|
25433
|
+
"voice-input-usage": "host_preferences",
|
|
24990
25434
|
terminal: "terminal",
|
|
24991
25435
|
"folder-picker": "file_explorer",
|
|
24992
25436
|
"file-preview": "file_preview",
|
|
@@ -29609,6 +30053,12 @@ Waiting for Claude login output…</pre
|
|
|
29609
30053
|
subtitle: "",
|
|
29610
30054
|
};
|
|
29611
30055
|
}
|
|
30056
|
+
if (screen === "voice-input-usage") {
|
|
30057
|
+
return {
|
|
30058
|
+
title: "Voice Input Usage",
|
|
30059
|
+
subtitle: "",
|
|
30060
|
+
};
|
|
30061
|
+
}
|
|
29612
30062
|
if (screen === "change-password") {
|
|
29613
30063
|
return {
|
|
29614
30064
|
title: "Change Password",
|
|
@@ -29969,6 +30419,10 @@ Waiting for Claude login output…</pre
|
|
|
29969
30419
|
"active",
|
|
29970
30420
|
screen === "host-preferences"
|
|
29971
30421
|
);
|
|
30422
|
+
$("voice-input-usage-view").classList.toggle(
|
|
30423
|
+
"active",
|
|
30424
|
+
screen === "voice-input-usage"
|
|
30425
|
+
);
|
|
29972
30426
|
$("change-password-view").classList.toggle(
|
|
29973
30427
|
"active",
|
|
29974
30428
|
screen === "change-password"
|
|
@@ -30022,6 +30476,14 @@ Waiting for Claude login output…</pre
|
|
|
30022
30476
|
}
|
|
30023
30477
|
if (screen === "host-preferences") {
|
|
30024
30478
|
renderHostPreferences();
|
|
30479
|
+
} else if (
|
|
30480
|
+
hostPreferencesState.voiceInputSampleLoaded ||
|
|
30481
|
+
hostVoiceInputSampleObjectUrl
|
|
30482
|
+
) {
|
|
30483
|
+
releaseHostVoiceInputSampleAudio();
|
|
30484
|
+
}
|
|
30485
|
+
if (screen === "voice-input-usage") {
|
|
30486
|
+
renderHostVoiceInputUsageDetail();
|
|
30025
30487
|
}
|
|
30026
30488
|
if (screen === "change-password") {
|
|
30027
30489
|
renderChangePasswordView();
|
|
@@ -30051,6 +30513,10 @@ Waiting for Claude login output…</pre
|
|
|
30051
30513
|
void navigateToRoute(buildSettingsRoute());
|
|
30052
30514
|
return;
|
|
30053
30515
|
}
|
|
30516
|
+
if (entry.screen === "voice-input-usage") {
|
|
30517
|
+
void navigateToRoute(buildVoiceInputUsageRoute());
|
|
30518
|
+
return;
|
|
30519
|
+
}
|
|
30054
30520
|
if (entry.screen === "change-password") {
|
|
30055
30521
|
void navigateToRoute(buildChangePasswordRoute());
|
|
30056
30522
|
return;
|
|
@@ -34317,6 +34783,11 @@ Waiting for Claude login output…</pre
|
|
|
34317
34783
|
const notificationSoundAppEnabled =
|
|
34318
34784
|
data.notification_sound_app_enabled !== false;
|
|
34319
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;
|
|
34320
34791
|
const debugShowCapabilityUi = data.debug_show_capability_ui === true;
|
|
34321
34792
|
const showInterfaceStyleInSessionSetupProfile =
|
|
34322
34793
|
data.show_interface_style_in_session_setup_profile === true;
|
|
@@ -34353,6 +34824,7 @@ Waiting for Claude login output…</pre
|
|
|
34353
34824
|
notificationSoundWebEnabled,
|
|
34354
34825
|
notificationSoundAppEnabled,
|
|
34355
34826
|
dailyTelemetryEnabled,
|
|
34827
|
+
voiceInputEnabled,
|
|
34356
34828
|
defaultWebsiteAccess: normalizeAgentWebAccess(webDefaults.access),
|
|
34357
34829
|
defaultNotificationsEnabled: notificationDefaults.enabled !== false,
|
|
34358
34830
|
defaultRuntimeCapabilities: runtimeCapabilityDefaults,
|
|
@@ -34409,6 +34881,42 @@ Waiting for Claude login output…</pre
|
|
|
34409
34881
|
: "",
|
|
34410
34882
|
dailyTelemetryHostIdPresent:
|
|
34411
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,
|
|
34412
34920
|
defaultWebsiteAccess: normalizeAgentWebAccess(webDefaults.access),
|
|
34413
34921
|
defaultNotificationsEnabled: notificationDefaults.enabled !== false,
|
|
34414
34922
|
defaultRuntimeCapabilities: runtimeCapabilityDefaults,
|
|
@@ -34498,17 +35006,6 @@ Waiting for Claude login output…</pre
|
|
|
34498
35006
|
});
|
|
34499
35007
|
syncSessionSetupInterfaceStyleVisibility();
|
|
34500
35008
|
renderCreateTelegramFeatureVisibility();
|
|
34501
|
-
if (!providerCatalogState.loaded) {
|
|
34502
|
-
providerCatalogState = {
|
|
34503
|
-
...providerCatalogState,
|
|
34504
|
-
providers: KNOWN_PROVIDER_ORDER.map((providerId) => ({
|
|
34505
|
-
id: providerId,
|
|
34506
|
-
label: getProviderDisplayLabel(providerId),
|
|
34507
|
-
commandAvailable: false,
|
|
34508
|
-
runtimeSupported: true,
|
|
34509
|
-
})),
|
|
34510
|
-
};
|
|
34511
|
-
}
|
|
34512
35009
|
renderHostPreferences();
|
|
34513
35010
|
setCreateRuntime(getEffectiveCreateRuntime(createRuntime), {
|
|
34514
35011
|
preserveSelection: true,
|
|
@@ -34520,11 +35017,18 @@ Waiting for Claude login output…</pre
|
|
|
34520
35017
|
const normalizedProviders = Array.isArray(data?.providers)
|
|
34521
35018
|
? data.providers.map(normalizeProviderCatalogEntry).filter(Boolean)
|
|
34522
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
|
+
});
|
|
34523
35026
|
providerCatalogState = {
|
|
35027
|
+
status: getProviderCatalogStatusForProviders(providers),
|
|
34524
35028
|
loaded: true,
|
|
34525
35029
|
loading: false,
|
|
34526
35030
|
error: "",
|
|
34527
|
-
providers
|
|
35031
|
+
providers,
|
|
34528
35032
|
};
|
|
34529
35033
|
hostPreferencesState = {
|
|
34530
35034
|
...hostPreferencesState,
|
|
@@ -34545,36 +35049,50 @@ Waiting for Claude login output…</pre
|
|
|
34545
35049
|
});
|
|
34546
35050
|
}
|
|
34547
35051
|
|
|
34548
|
-
|
|
34549
|
-
if (
|
|
35052
|
+
function loadProviderCatalog(opts = {}) {
|
|
35053
|
+
if (providerCatalogLoadPromise) return providerCatalogLoadPromise;
|
|
34550
35054
|
providerCatalogState = {
|
|
34551
35055
|
...providerCatalogState,
|
|
35056
|
+
status: providerCatalogState.loaded
|
|
35057
|
+
? providerCatalogState.status
|
|
35058
|
+
: PROVIDER_CATALOG_STATUS_PENDING,
|
|
34552
35059
|
loading: true,
|
|
34553
35060
|
error: "",
|
|
34554
35061
|
};
|
|
34555
35062
|
renderHostPreferences();
|
|
34556
|
-
|
|
34557
|
-
|
|
34558
|
-
|
|
34559
|
-
|
|
34560
|
-
|
|
34561
|
-
|
|
34562
|
-
|
|
34563
|
-
|
|
34564
|
-
|
|
34565
|
-
|
|
34566
|
-
|
|
34567
|
-
|
|
34568
|
-
|
|
34569
|
-
|
|
34570
|
-
|
|
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;
|
|
34571
35089
|
}
|
|
34572
|
-
}
|
|
35090
|
+
})();
|
|
35091
|
+
return providerCatalogLoadPromise;
|
|
34573
35092
|
}
|
|
34574
35093
|
|
|
34575
35094
|
function retryHostPreferencesProviderSection() {
|
|
34576
|
-
|
|
34577
|
-
void loadProviderCatalog({ force: true, quiet: true });
|
|
35095
|
+
return loadProviderCatalog({ force: true, quiet: true });
|
|
34578
35096
|
}
|
|
34579
35097
|
|
|
34580
35098
|
function clearProviderAuthJobPollTimer() {
|
|
@@ -34746,7 +35264,6 @@ Waiting for Claude login output…</pre
|
|
|
34746
35264
|
? response.provider.trim()
|
|
34747
35265
|
: "claude";
|
|
34748
35266
|
if (response.provider_auth) {
|
|
34749
|
-
invalidateDashboardDataCaches({ providers: true });
|
|
34750
35267
|
setProviderCatalogAuthStatus(providerId, response.provider_auth);
|
|
34751
35268
|
}
|
|
34752
35269
|
providerAuthModalState = {
|
|
@@ -34758,6 +35275,7 @@ Waiting for Claude login output…</pre
|
|
|
34758
35275
|
response.provider_auth,
|
|
34759
35276
|
providerId,
|
|
34760
35277
|
getProviderCatalogEntry(providerId)?.commandAvailable === true,
|
|
35278
|
+
getProviderCatalogEntry(providerId)?.authSupported === true,
|
|
34761
35279
|
getProviderCatalogEntry(providerId)?.authStartSupported === true
|
|
34762
35280
|
)
|
|
34763
35281
|
: getProviderAuthStatus(providerId),
|
|
@@ -34829,13 +35347,13 @@ Waiting for Claude login output…</pre
|
|
|
34829
35347
|
"GET",
|
|
34830
35348
|
`/provider-auth/status?provider=${encodeURIComponent(providerId)}`
|
|
34831
35349
|
);
|
|
34832
|
-
invalidateDashboardDataCaches({ providers: true });
|
|
34833
35350
|
setProviderCatalogAuthStatus(providerId, data.provider_auth || null);
|
|
34834
35351
|
if (providerAuthModalState.provider === providerId) {
|
|
34835
35352
|
const normalizedStatus = normalizeProviderAuthStatus(
|
|
34836
35353
|
data.provider_auth,
|
|
34837
35354
|
providerId,
|
|
34838
35355
|
getProviderCatalogEntry(providerId)?.commandAvailable === true,
|
|
35356
|
+
getProviderCatalogEntry(providerId)?.authSupported === true,
|
|
34839
35357
|
getProviderCatalogEntry(providerId)?.authStartSupported === true
|
|
34840
35358
|
);
|
|
34841
35359
|
providerAuthModalState = {
|
|
@@ -35004,6 +35522,7 @@ Waiting for Claude login output…</pre
|
|
|
35004
35522
|
data.provider_auth,
|
|
35005
35523
|
providerId,
|
|
35006
35524
|
getProviderCatalogEntry(providerId)?.commandAvailable === true,
|
|
35525
|
+
getProviderCatalogEntry(providerId)?.authSupported === true,
|
|
35007
35526
|
getProviderCatalogEntry(providerId)?.authStartSupported === true
|
|
35008
35527
|
),
|
|
35009
35528
|
job,
|
|
@@ -35689,7 +36208,11 @@ Waiting for Claude login output…</pre
|
|
|
35689
36208
|
if (!availableProviderIds.length) {
|
|
35690
36209
|
const option = document.createElement("option");
|
|
35691
36210
|
option.value = "";
|
|
35692
|
-
option.textContent =
|
|
36211
|
+
option.textContent = isProviderCatalogInitialPending()
|
|
36212
|
+
? "Checking providers..."
|
|
36213
|
+
: isProviderCatalogRequestFailed()
|
|
36214
|
+
? "Provider status unavailable"
|
|
36215
|
+
: "No available providers";
|
|
35693
36216
|
option.disabled = true;
|
|
35694
36217
|
option.selected = true;
|
|
35695
36218
|
select.appendChild(option);
|
|
@@ -35738,6 +36261,8 @@ Waiting for Claude login output…</pre
|
|
|
35738
36261
|
);
|
|
35739
36262
|
const runtimeLocked =
|
|
35740
36263
|
isResumeMode() && Boolean(pendingResumeSourceRuntime);
|
|
36264
|
+
const providerCatalogPending = isProviderCatalogInitialPending();
|
|
36265
|
+
const providerCatalogFailed = isProviderCatalogRequestFailed();
|
|
35741
36266
|
setVisible("runtime-claude", claudeVisible);
|
|
35742
36267
|
setVisible("runtime-codex", codexVisible);
|
|
35743
36268
|
setVisible("runtime-debug-fixture", debugFixtureVisible);
|
|
@@ -35783,6 +36308,26 @@ Waiting for Claude login output…</pre
|
|
|
35783
36308
|
}
|
|
35784
36309
|
refreshCreateStartButtonEnabled();
|
|
35785
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
|
+
}
|
|
35786
36331
|
if (!visibleProviderIds.length) {
|
|
35787
36332
|
if (modelSelect) {
|
|
35788
36333
|
modelSelect.innerHTML = "";
|
|
@@ -35937,6 +36482,711 @@ Waiting for Claude login output…</pre
|
|
|
35937
36482
|
};
|
|
35938
36483
|
}
|
|
35939
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
|
+
|
|
35940
37190
|
function renderHostPreferences() {
|
|
35941
37191
|
const pathInput = $("host-default-browse-path");
|
|
35942
37192
|
if (
|
|
@@ -36067,10 +37317,8 @@ Waiting for Claude login output…</pre
|
|
|
36067
37317
|
basicPreferencesUnavailable;
|
|
36068
37318
|
const providerSectionStatusVisible =
|
|
36069
37319
|
providerCatalogState.loading || Boolean(providerCatalogState.error);
|
|
36070
|
-
const providerSectionInitialPending =
|
|
36071
|
-
|
|
36072
|
-
const providerSectionUnavailable =
|
|
36073
|
-
!providerCatalogState.loaded && Boolean(providerCatalogState.error);
|
|
37320
|
+
const providerSectionInitialPending = isProviderCatalogInitialPending();
|
|
37321
|
+
const providerSectionUnavailable = isProviderCatalogRequestFailed();
|
|
36074
37322
|
const providerControlsDisabled =
|
|
36075
37323
|
disabled ||
|
|
36076
37324
|
providerSectionInitialPending ||
|
|
@@ -36078,12 +37326,12 @@ Waiting for Claude login output…</pre
|
|
|
36078
37326
|
let providerSectionStatusCopy = "";
|
|
36079
37327
|
if (providerCatalogState.loading) {
|
|
36080
37328
|
providerSectionStatusCopy = providerCatalogState.loaded
|
|
36081
|
-
? "Refreshing provider
|
|
36082
|
-
: "Checking provider
|
|
37329
|
+
? "Refreshing provider availability..."
|
|
37330
|
+
: "Checking provider availability...";
|
|
36083
37331
|
} else if (providerCatalogState.error) {
|
|
36084
37332
|
providerSectionStatusCopy = providerCatalogState.loaded
|
|
36085
|
-
? "Could not refresh provider
|
|
36086
|
-
: "Could not load provider
|
|
37333
|
+
? "Could not refresh provider availability. Existing values remain available."
|
|
37334
|
+
: "Could not load provider availability.";
|
|
36087
37335
|
}
|
|
36088
37336
|
setVisible(
|
|
36089
37337
|
"host-provider-section-status-label",
|
|
@@ -36471,15 +37719,11 @@ Waiting for Claude login output…</pre
|
|
|
36471
37719
|
);
|
|
36472
37720
|
setText(
|
|
36473
37721
|
"host-claude-command-status",
|
|
36474
|
-
|
|
36475
|
-
? "Available on this Host."
|
|
36476
|
-
: "Unavailable on this Host. Blank disables Claude explicitly."
|
|
37722
|
+
describeProviderCommandAvailability("claude")
|
|
36477
37723
|
);
|
|
36478
37724
|
setText(
|
|
36479
37725
|
"host-codex-command-status",
|
|
36480
|
-
|
|
36481
|
-
? "Available on this Host."
|
|
36482
|
-
: "Unavailable on this Host. Blank disables Codex explicitly."
|
|
37726
|
+
describeProviderCommandAvailability("codex")
|
|
36483
37727
|
);
|
|
36484
37728
|
setText(
|
|
36485
37729
|
"host-default-provider-warning",
|
|
@@ -36499,6 +37743,7 @@ Waiting for Claude login output…</pre
|
|
|
36499
37743
|
hostPreferencesState.debugHostPreferencesFullDiskAccessBlockEnabled ===
|
|
36500
37744
|
true;
|
|
36501
37745
|
renderHostNotificationPreferences({ disabled });
|
|
37746
|
+
renderHostVoiceInputPreferences({ disabled });
|
|
36502
37747
|
setVisible("host-folder-access-card", folderAccessVisible);
|
|
36503
37748
|
$("host-public-base-url")?.toggleAttribute(
|
|
36504
37749
|
"disabled",
|
|
@@ -36585,6 +37830,7 @@ Waiting for Claude login output…</pre
|
|
|
36585
37830
|
error: "",
|
|
36586
37831
|
};
|
|
36587
37832
|
renderHostPreferences();
|
|
37833
|
+
void loadHostVoiceInputNativeAppVersion();
|
|
36588
37834
|
try {
|
|
36589
37835
|
const data = await apiWithAuthRetry("GET", "/dev/preferences");
|
|
36590
37836
|
applyHostPreferencesData(data);
|
|
@@ -37018,6 +38264,192 @@ Waiting for Claude login output…</pre
|
|
|
37018
38264
|
discardUnsavedHostPreferencesChanges();
|
|
37019
38265
|
}
|
|
37020
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
|
+
|
|
37021
38453
|
async function saveHostPreferences() {
|
|
37022
38454
|
if (hostPreferencesState.saving) {
|
|
37023
38455
|
refreshHostPreferencesSaveButton();
|
|
@@ -37053,6 +38485,8 @@ Waiting for Claude login output…</pre
|
|
|
37053
38485
|
$("host-notification-app-sound-toggle")?.checked !== false;
|
|
37054
38486
|
const requestedDailyTelemetryEnabled =
|
|
37055
38487
|
$("host-daily-telemetry-toggle")?.checked === true;
|
|
38488
|
+
const requestedVoiceInputEnabled =
|
|
38489
|
+
getHostVoiceInputEnabledControlValue();
|
|
37056
38490
|
const claudeCommandInput = $("host-claude-command");
|
|
37057
38491
|
const requestedClaudeCommand = claudeCommandInput
|
|
37058
38492
|
? claudeCommandInput.value.trim()
|
|
@@ -37127,6 +38561,7 @@ Waiting for Claude login output…</pre
|
|
|
37127
38561
|
notificationSoundWebEnabled: requestedWebNotificationSound,
|
|
37128
38562
|
notificationSoundAppEnabled: requestedAppNotificationSound,
|
|
37129
38563
|
dailyTelemetryEnabled: requestedDailyTelemetryEnabled,
|
|
38564
|
+
voiceInputEnabled: requestedVoiceInputEnabled,
|
|
37130
38565
|
publicBaseUrl: requestedPublicBaseUrl,
|
|
37131
38566
|
defaultBrowsePath: requestedPath,
|
|
37132
38567
|
defaultProvider: nextDefaultProvider,
|
|
@@ -37156,6 +38591,10 @@ Waiting for Claude login output…</pre
|
|
|
37156
38591
|
notification_sound_web_enabled: requestedWebNotificationSound,
|
|
37157
38592
|
notification_sound_app_enabled: requestedAppNotificationSound,
|
|
37158
38593
|
daily_telemetry_enabled: requestedDailyTelemetryEnabled,
|
|
38594
|
+
voice_input: {
|
|
38595
|
+
enabled: requestedVoiceInputEnabled,
|
|
38596
|
+
token_action: "retain",
|
|
38597
|
+
},
|
|
37159
38598
|
direct_host_url: requestedPublicBaseUrl || null,
|
|
37160
38599
|
public_base_url: requestedPublicBaseUrl || null,
|
|
37161
38600
|
default_browse_path: requestedPath,
|
|
@@ -37783,11 +39222,7 @@ Waiting for Claude login output…</pre
|
|
|
37783
39222
|
}
|
|
37784
39223
|
|
|
37785
39224
|
function isCreateWebsiteEligible() {
|
|
37786
|
-
return
|
|
37787
|
-
createWebsiteAuthorityState.eligible === true &&
|
|
37788
|
-
createWebsiteAuthorityState.projectAgentId ===
|
|
37789
|
-
String($("create-agent-id")?.value || "").trim()
|
|
37790
|
-
);
|
|
39225
|
+
return createWebsiteAuthorityState.eligible === true;
|
|
37791
39226
|
}
|
|
37792
39227
|
|
|
37793
39228
|
function syncCreateWebsiteAuthorityState() {
|
|
@@ -37815,13 +39250,13 @@ Waiting for Claude login output…</pre
|
|
|
37815
39250
|
|
|
37816
39251
|
function setCreateWebsiteAuthorityState({
|
|
37817
39252
|
folderPath = "",
|
|
37818
|
-
|
|
39253
|
+
projectId = "",
|
|
37819
39254
|
eligible = false,
|
|
37820
39255
|
reason = "",
|
|
37821
39256
|
} = {}) {
|
|
37822
39257
|
createWebsiteAuthorityState = {
|
|
37823
39258
|
folderPath: String(folderPath || "").trim(),
|
|
37824
|
-
|
|
39259
|
+
projectId: String(projectId || "").trim(),
|
|
37825
39260
|
eligible: eligible === true,
|
|
37826
39261
|
reason:
|
|
37827
39262
|
String(reason || "").trim() ||
|
|
@@ -39146,7 +40581,6 @@ Waiting for Claude login output…</pre
|
|
|
39146
40581
|
liveSession = getSelectedLiveSession()
|
|
39147
40582
|
) {
|
|
39148
40583
|
const input = $("agent-profile-rename-input");
|
|
39149
|
-
const updateConfig = $("agent-profile-identity-update-config");
|
|
39150
40584
|
const saveBtn =
|
|
39151
40585
|
$("agent-profile-identity-save-btn") ||
|
|
39152
40586
|
$("agent-profile-rename-save-btn");
|
|
@@ -39154,10 +40588,6 @@ Waiting for Claude login output…</pre
|
|
|
39154
40588
|
if (!liveSession) {
|
|
39155
40589
|
input.value = "";
|
|
39156
40590
|
input.disabled = true;
|
|
39157
|
-
if (updateConfig) {
|
|
39158
|
-
updateConfig.checked = false;
|
|
39159
|
-
updateConfig.disabled = true;
|
|
39160
|
-
}
|
|
39161
40591
|
saveBtn.disabled = true;
|
|
39162
40592
|
saveBtn.textContent = "Save";
|
|
39163
40593
|
showError("agent-profile-rename-error", "");
|
|
@@ -39170,18 +40600,14 @@ Waiting for Claude login output…</pre
|
|
|
39170
40600
|
).trim();
|
|
39171
40601
|
const draftName = String(agentProfileRenameState.draft || "");
|
|
39172
40602
|
const normalizedDraft = draftName.trim();
|
|
39173
|
-
const persistIdentity = updateConfig?.checked === true;
|
|
39174
40603
|
input.value = draftName;
|
|
39175
40604
|
input.disabled = agentProfileRenameState.saving === true;
|
|
39176
|
-
if (updateConfig) {
|
|
39177
|
-
updateConfig.disabled = agentProfileRenameState.saving === true;
|
|
39178
|
-
}
|
|
39179
40605
|
saveBtn.textContent =
|
|
39180
40606
|
agentProfileRenameState.saving === true ? "Saving..." : "Save";
|
|
39181
40607
|
saveBtn.disabled =
|
|
39182
40608
|
agentProfileRenameState.saving === true ||
|
|
39183
40609
|
!normalizedDraft ||
|
|
39184
|
-
|
|
40610
|
+
normalizedDraft === currentName;
|
|
39185
40611
|
showError(
|
|
39186
40612
|
"agent-profile-rename-error",
|
|
39187
40613
|
agentProfileRenameState.error || ""
|
|
@@ -39199,8 +40625,6 @@ Waiting for Claude login output…</pre
|
|
|
39199
40625
|
const currentSessionName = String(
|
|
39200
40626
|
liveSession.sessionName || liveSession.session_name || ""
|
|
39201
40627
|
).trim();
|
|
39202
|
-
const updateConfig =
|
|
39203
|
-
$("agent-profile-identity-update-config")?.checked === true;
|
|
39204
40628
|
if (!nextSessionName) {
|
|
39205
40629
|
agentProfileRenameState = {
|
|
39206
40630
|
...agentProfileRenameState,
|
|
@@ -39209,7 +40633,7 @@ Waiting for Claude login output…</pre
|
|
|
39209
40633
|
renderAgentProfileRenameView(liveSession);
|
|
39210
40634
|
return;
|
|
39211
40635
|
}
|
|
39212
|
-
if (nextSessionName === currentSessionName
|
|
40636
|
+
if (nextSessionName === currentSessionName) {
|
|
39213
40637
|
agentProfileRenameState = {
|
|
39214
40638
|
...agentProfileRenameState,
|
|
39215
40639
|
draft: currentSessionName,
|
|
@@ -39231,7 +40655,6 @@ Waiting for Claude login output…</pre
|
|
|
39231
40655
|
const data = await api("POST", "/session/rename", {
|
|
39232
40656
|
session_id: liveSession.sessionId,
|
|
39233
40657
|
session_name: nextSessionName,
|
|
39234
|
-
update_config: updateConfig,
|
|
39235
40658
|
});
|
|
39236
40659
|
const resolvedSessionName = data.session_name || nextSessionName;
|
|
39237
40660
|
patchLiveSession(liveSession.sessionId, {
|
|
@@ -39246,11 +40669,7 @@ Waiting for Claude login output…</pre
|
|
|
39246
40669
|
resolvedSessionName
|
|
39247
40670
|
);
|
|
39248
40671
|
renderSelectedAgent();
|
|
39249
|
-
showBanner(
|
|
39250
|
-
data.config_mutated === true
|
|
39251
|
-
? `Renamed session to ${resolvedSessionName} and updated .oysterun/config.json.`
|
|
39252
|
-
: `Renamed session to ${resolvedSessionName}.`
|
|
39253
|
-
);
|
|
40672
|
+
showBanner(`Renamed session to ${resolvedSessionName}.`);
|
|
39254
40673
|
} catch (err) {
|
|
39255
40674
|
agentProfileRenameState = {
|
|
39256
40675
|
...agentProfileRenameState,
|
|
@@ -48850,7 +50269,11 @@ Waiting for Claude login output…</pre
|
|
|
48850
50269
|
|
|
48851
50270
|
async function submitCreateAgent() {
|
|
48852
50271
|
if (!hasRunnableCreateProvider()) {
|
|
48853
|
-
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
|
|
48854
50277
|
? `${getProviderDisplayLabel(
|
|
48855
50278
|
createRuntime
|
|
48856
50279
|
)} is currently unavailable on this Host. Update Host Preferences before starting a session.`
|
|
@@ -50350,7 +51773,7 @@ Waiting for Claude login output…</pre
|
|
|
50350
51773
|
}
|
|
50351
51774
|
setCreateWebsiteAuthorityState({
|
|
50352
51775
|
folderPath: resolvedFolderPath,
|
|
50353
|
-
|
|
51776
|
+
projectId: data.websiteProjectId || "",
|
|
50354
51777
|
eligible:
|
|
50355
51778
|
data.websiteEligible === true ||
|
|
50356
51779
|
data.website?.browser_root_authorized === true,
|
|
@@ -51057,7 +52480,7 @@ Waiting for Claude login output…</pre
|
|
|
51057
52480
|
);
|
|
51058
52481
|
if (
|
|
51059
52482
|
control instanceof HTMLInputElement &&
|
|
51060
|
-
["text", "url", "search"].includes(control.type)
|
|
52483
|
+
["text", "url", "search", "password"].includes(control.type)
|
|
51061
52484
|
) {
|
|
51062
52485
|
control.addEventListener(
|
|
51063
52486
|
"input",
|
|
@@ -51065,6 +52488,10 @@ Waiting for Claude login output…</pre
|
|
|
51065
52488
|
);
|
|
51066
52489
|
}
|
|
51067
52490
|
}
|
|
52491
|
+
$("host-voice-input-token")?.addEventListener(
|
|
52492
|
+
"input",
|
|
52493
|
+
handleHostVoiceInputTokenInput
|
|
52494
|
+
);
|
|
51068
52495
|
document.addEventListener("change", (event) => {
|
|
51069
52496
|
if (event.target.closest("[data-host-default-runtime-capability]")) {
|
|
51070
52497
|
stageHostPreferencesDraftFromControls();
|
|
@@ -51073,6 +52500,9 @@ Waiting for Claude login output…</pre
|
|
|
51073
52500
|
window.useStartFolderForAllowedPaths = useStartFolderForAllowedPaths;
|
|
51074
52501
|
window.openPermissionsSettings = openPermissionsSettings;
|
|
51075
52502
|
window.saveHostPreferences = saveHostPreferences;
|
|
52503
|
+
window.discardHostVoiceInputTokenDraft = discardHostVoiceInputTokenDraft;
|
|
52504
|
+
window.removeHostVoiceInputSavedToken = removeHostVoiceInputSavedToken;
|
|
52505
|
+
window.testHostVoiceInput = testHostVoiceInput;
|
|
51076
52506
|
window.generateDirectHostLoginQr = generateDirectHostLoginQr;
|
|
51077
52507
|
window.copyHostPreferencesDirectHostUrl =
|
|
51078
52508
|
copyHostPreferencesDirectHostUrl;
|
|
@@ -51247,10 +52677,6 @@ Waiting for Claude login output…</pre
|
|
|
51247
52677
|
refreshAgentProfileWorkspacePolicySaveState();
|
|
51248
52678
|
return;
|
|
51249
52679
|
}
|
|
51250
|
-
if (event.target.closest("#agent-profile-identity-update-config")) {
|
|
51251
|
-
renderAgentProfileRenameView(getSelectedLiveSession());
|
|
51252
|
-
return;
|
|
51253
|
-
}
|
|
51254
52680
|
handleSessionLoopChange(event);
|
|
51255
52681
|
handleHostSchedulerChange(event);
|
|
51256
52682
|
});
|