diff --git a/CHANGELOG.md b/CHANGELOG.md index 8abc33bb..200e5f2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [1.4.11] — 2026-02-25 + +> ### 🐛 Settings Persistence Fix +> +> Fixes routing strategy and wildcard aliases not saving after page refresh. + +### 🐛 Bug Fixes + +- **Routing Strategy Not Saved After Refresh (#134)** — Added `fallbackStrategy`, `wildcardAliases`, and `stickyRoundRobinLimit` to the Zod validation schema. These fields were silently stripped during validation, preventing them from being persisted to the database + +### 📝 Notes + +- **#135 Closed** — Feature request for proxy configuration (global + per-provider) was already implemented in v1.4.10 + +--- + ## [1.4.10] — 2026-02-25 > ### 🔒 Proxy Visibility + Bug Fixes diff --git a/src/app/(dashboard)/dashboard/translator/components/ChatTesterMode.tsx b/src/app/(dashboard)/dashboard/translator/components/ChatTesterMode.tsx index 61dec44d..7f9e9082 100644 --- a/src/app/(dashboard)/dashboard/translator/components/ChatTesterMode.tsx +++ b/src/app/(dashboard)/dashboard/translator/components/ChatTesterMode.tsx @@ -99,8 +99,8 @@ export default function ChatTesterMode() { steps.push({ id: 1, - name: "Client Request", - description: "The request body as your client would send it", + name: t("clientRequest"), + description: t("clientRequestDescription"), format: clientFormat, content: JSON.stringify(clientRequest, null, 2), status: "done", @@ -117,8 +117,8 @@ export default function ChatTesterMode() { steps.push({ id: 2, - name: "Format Detected", - description: "OmniRoute auto-detects the API format from the request structure", + name: t("formatDetected"), + description: t("formatDetectedDescription"), format: detectedFormat, content: JSON.stringify( { detectedFormat, clientFormat, match: detectedFormat === clientFormat }, @@ -143,8 +143,8 @@ export default function ChatTesterMode() { steps.push({ id: 3, - name: "OpenAI Intermediate", - description: "All formats are first normalized to OpenAI format (the universal bridge)", + name: t("openaiIntermediate"), + description: t("openaiIntermediateDescription"), format: "openai", content: JSON.stringify(toOpenaiData.result || toOpenaiData, null, 2), status: toOpenaiData.success ? "done" : "error", @@ -166,8 +166,8 @@ export default function ChatTesterMode() { steps.push({ id: 4, - name: "Provider Format", - description: `OpenAI format is translated to the provider's native format`, + name: t("providerFormat"), + description: t("providerFormatDescription"), format: targetFmt, content: JSON.stringify(providerTargetData.result || providerTargetData, null, 2), status: providerTargetData.success ? "done" : "error", @@ -181,18 +181,21 @@ export default function ChatTesterMode() { }); if (!sendRes.ok) { - const errData = await sendRes.json().catch(() => ({ error: "Request failed" })); + const errData = await sendRes.json().catch(() => ({ error: t("requestFailed") })); steps.push({ id: 5, - name: "Provider Response", - description: "The raw response from the provider API", + name: t("providerResponse"), + description: t("providerResponseRawDescription"), format: targetFmt, content: JSON.stringify(errData, null, 2), status: "error", }); setChatHistory((prev) => [ ...prev, - { role: "assistant", content: `Error: ${errData.error || "Request failed"}` }, + { + role: "assistant", + content: t("errorMessage", { message: errData.error || t("requestFailed") }), + }, ]); } else { // Read streaming response @@ -208,8 +211,8 @@ export default function ChatTesterMode() { steps.push({ id: 5, - name: "Provider Response", - description: "The raw SSE stream from the provider API", + name: t("providerResponse"), + description: t("providerResponseSseDescription"), format: targetFmt, content: fullResponse.slice(0, 5000) + (fullResponse.length > 5000 ? "\n... (truncated)" : ""), @@ -220,19 +223,22 @@ export default function ChatTesterMode() { const assistantText = extractAssistantText(fullResponse); setChatHistory((prev) => [ ...prev, - { role: "assistant", content: assistantText || "(No text extracted)" }, + { role: "assistant", content: assistantText || t("noTextExtracted") }, ]); } } catch (err) { steps.push({ id: steps.length + 1, - name: "Error", - description: "An unexpected error occurred", + name: t("error"), + description: t("unexpectedError"), format: "error", content: JSON.stringify({ error: err.message }, null, 2), status: "error", }); - setChatHistory((prev) => [...prev, { role: "assistant", content: `Error: ${err.message}` }]); + setChatHistory((prev) => [ + ...prev, + { role: "assistant", content: t("errorMessage", { message: err.message }) }, + ]); } setPipeline(steps); @@ -250,13 +256,10 @@ export default function ChatTesterMode() {

{t("pipelineDebugger")}

+

{t("chatTesterDescription")}

- Send messages as a specific client format and see how each step of the translation - pipeline works. The right panel shows the full flow:{" "} - - Client Request → Format Detection → OpenAI Intermediate → Provider Format → Response - - . Click any step to inspect the data at that stage. + {t("chatTesterFlow")}.{" "} + {t("clickStepToInspect")}

@@ -270,7 +273,7 @@ export default function ChatTesterMode() {
setModel(e.target.value)} list="model-suggestions" - placeholder="Select or type a model name..." + placeholder={t("modelPlaceholder")} className="w-full bg-bg-subtle border border-border rounded-lg px-3 py-2 text-sm text-text-main placeholder:text-text-muted focus:outline-none focus:border-primary transition-colors" /> @@ -322,13 +325,10 @@ export default function ChatTesterMode() { chat -

- Send a message to see the translation pipeline -

+

{t("sendMessageToSeePipeline")}

- Your message will be formatted as a{" "} - {FORMAT_META[clientFormat]?.label} request, translated through - the pipeline, and sent to the selected provider. + {t("chatMessageHintPrefix")} {FORMAT_META[clientFormat]?.label}{" "} + {t("chatMessageHintSuffix")}

)} @@ -346,8 +346,8 @@ export default function ChatTesterMode() { >

{msg.role === "user" - ? `You (${FORMAT_META[clientFormat]?.label})` - : "Assistant"} + ? t("youWithFormat", { format: FORMAT_META[clientFormat]?.label }) + : t("assistant")}

{msg.content}

@@ -364,7 +364,7 @@ export default function ChatTesterMode() { value={message} onChange={(e) => setMessage(e.target.value)} onKeyDown={(e) => e.key === "Enter" && !e.shiftKey && handleSend()} - placeholder="Type a message..." + placeholder={t("typeMessage")} className="flex-1 bg-bg-subtle border border-border rounded-lg px-3 py-2 text-sm text-text-main placeholder:text-text-muted focus:outline-none focus:border-primary transition-colors" disabled={sending} /> @@ -374,7 +374,7 @@ export default function ChatTesterMode() { loading={sending} disabled={!message.trim() || sending} > - Send + {t("send")}
@@ -391,9 +391,7 @@ export default function ChatTesterMode() {

{t("translationPipeline")}

-

- Click on any step to inspect the data at that stage -

+

{t("clickStepToInspect")}

@@ -403,11 +401,8 @@ export default function ChatTesterMode() { account_tree -

Pipeline visualization

-

- Send a message to see how your request flows through detection → translation → - provider call. -

+

{t("pipelineVisualization")}

+

{t("pipelineVisualizationHint")}

) : ( diff --git a/src/app/(dashboard)/dashboard/translator/components/LiveMonitorMode.tsx b/src/app/(dashboard)/dashboard/translator/components/LiveMonitorMode.tsx index cb605ac3..93581602 100644 --- a/src/app/(dashboard)/dashboard/translator/components/LiveMonitorMode.tsx +++ b/src/app/(dashboard)/dashboard/translator/components/LiveMonitorMode.tsx @@ -61,10 +61,10 @@ export default function LiveMonitorMode() {

{t("realtime")}

- {t("liveMonitorDescription")}{" "} + {t("liveMonitorDescriptionPrefix")}{" "} {t("chatTester")},{" "} - {t("testBench")}, {t("or")}{" "} - {t("externalApiCalls").toLowerCase()} {t("toGenerateEvents")} + {t("testBench")} + {t("liveMonitorDescriptionSuffix")}

@@ -124,9 +124,7 @@ export default function LiveMonitorMode() { monitoring

{t("noTranslations")}

-

- {t("eventsAppearHint")} -

+

{t("eventsAppearHint")}

{t("chatTesterTab")}