Compare commits

...
2 Commits
Author SHA1 Message Date
dwrz 7833cf2b00 Fix missing compose settings template 2026-07-05 18:15:00 +00:00
dwrz 0345dab110 Add copy error messages with request id 2026-07-05 18:14:40 +00:00
4 changed files with 55 additions and 6 deletions
+3 -1
View File
@@ -211,7 +211,6 @@ func (svc *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
slog.String("path", r.URL.Path),
))
)
// Log completion time.
defer func() {
log.InfoContext(
@@ -249,6 +248,9 @@ func (svc *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.InfoContext(ctx, "handling")
// Always set request ID header.
w.Header().Set("X-Request-ID", id)
// Pass the request on to the multiplexer.
svc.mux.ServeHTTP(w, r)
}
+9 -2
View File
@@ -657,14 +657,21 @@ class Odidere {
body: JSON.stringify(payload),
signal: this.currentController.signal,
});
const requestId = res.headers.get('X-Request-ID') || '';
if (!res.ok) {
const err = await res.text();
throw new Error(`server error ${res.status}: ${err}`);
this.renderer.renderError(
`server error ${res.status}: ${err}`,
requestId,
);
return;
}
for await (const { eventType, event } of this._parseSSEStream(res)) {
if (event.error) {
throw new Error(event.error);
this.renderer.renderError(event.error, requestId);
return;
}
if (
+9 -3
View File
@@ -403,11 +403,17 @@ export class Renderer {
* renderError renders an error message in the chat.
* @param {string} message
*/
renderError(message) {
renderError(message, requestId = '') {
const $msg =
this.$tplErrorMessage.content.cloneNode(true).firstElementChild;
$msg.querySelector('.message__content').textContent = message;
$msg.dataset.copyText = message;
const $content = $msg.querySelector('.message__content');
if (requestId) {
$content.textContent = `Request: ${requestId}\n${message}`;
$msg.dataset.copyText = `Request: ${requestId}\n${message}`;
} else {
$content.textContent = message;
$msg.dataset.copyText = message;
}
this.$chat.insertBefore($msg, this.$chatLoading);
this.scrollToBottom();
}
@@ -0,0 +1,34 @@
{{ define "modal/compose-settings" }}
<div class="settings-overlay" id="compose-settings-overlay">
<div class="settings-panel" role="dialog" aria-modal="true"
aria-labelledby="compose-settings-title">
<div class="settings-panel__header">
<h2 class="settings-panel__title" id="compose-settings-title">Message Options</h2>
<button
type="button"
class="footer__toolbar-btn"
id="compose-settings-close"
aria-label="Close message options"
>
<svg class="icon"><use href="/static/icons.svg#close"></use></svg>
</button>
</div>
<div class="settings-field">
<label class="settings-label" for="max-turns-input">
Max Iterations
<span class="settings-label__sub">0 = unlimited</span>
</label>
<input
type="number"
class="settings-select"
id="max-turns-input"
min="0"
max="99"
value="0"
aria-label="Max iterations"
/>
</div>
</div>
</div>
{{ end }}