# v0.5.3 (2026-06-18)

## Fixes
- **Kiro**: honor thinking effort budgets
- **AG/Kiro/Xiaomi**: provider fixes
- **Combo/Fusion**: flatten tool history in panel calls to prevent 503
- **LLM selector**: show custom vision models in selector and model list
- **Image**: prevent compatible nodes from shadowing provider aliases
This commit is contained in:
decolua
2026-06-18 17:36:08 +07:00
parent 2ff11246ae
commit 7354c5e5f4
8 changed files with 38 additions and 17 deletions

View File

@@ -1,3 +1,12 @@
# v0.5.3 (2026-06-18)
## Fixes
- **Kiro**: honor thinking effort budgets
- **AG/Kiro/Xiaomi**: provider fixes
- **Combo/Fusion**: flatten tool history in panel calls to prevent 503
- **LLM selector**: show custom vision models in selector and model list
- **Image**: prevent compatible nodes from shadowing provider aliases
# v0.5.2 (2026-06-17)
## Features

View File

@@ -1,6 +1,6 @@
{
"name": "9router",
"version": "0.5.2",
"version": "0.5.3",
"description": "9Router CLI - Start and manage 9Router server",
"bin": {
"9router": "./cli.js"

View File

@@ -17,7 +17,6 @@ const EXCLUDE_PATTERNS = [
"@img", // Sharp image processing (not needed with unoptimized images)
"sharp", // Sharp core lib (not needed with unoptimized images)
"detect-libc", // Sharp dependency
"logs", // Runtime logs
".env", // Environment files
".env.local",
".env.*.local",

View File

@@ -25,18 +25,18 @@ export default {
},
},
models: [
{ id: "auto", name: "Qoder Auto" },
{ id: "ultimate", name: "Qoder Ultimate" },
{ id: "performance", name: "Qoder Performance" },
{ id: "efficient", name: "Qoder Efficient" },
{ id: "lite", name: "Qoder Lite" },
{ id: "qmodel", name: "Qwen 3.6 Plus (Qoder)" },
// { id: "auto", name: "Qoder Auto" },
// { id: "ultimate", name: "Qoder Ultimate" },
// { id: "performance", name: "Qoder Performance" },
// { id: "efficient", name: "Qoder Efficient" },
// { id: "lite", name: "Qoder Lite" },
// { id: "qmodel", name: "Qwen 3.6 Plus (Qoder)" },
{ id: "qmodel_latest", name: "Qoder Qwen 3.7 Max" },
{ id: "dmodel", name: "DeepSeek V4 Pro (Qoder)" },
{ id: "dfmodel", name: "DeepSeek V4 Flash (Qoder)" },
{ id: "gm51model", name: "GLM 5.1 (Qoder)" },
{ id: "kmodel", name: "Kimi K2.6 (Qoder)" },
{ id: "mmodel", name: "MiniMax M2.7 (Qoder)" },
// { id: "dmodel", name: "DeepSeek V4 Pro (Qoder)" },
// { id: "dfmodel", name: "DeepSeek V4 Flash (Qoder)" },
// { id: "gm51model", name: "GLM 5.1 (Qoder)" },
// { id: "kmodel", name: "Kimi K2.6 (Qoder)" },
// { id: "mmodel", name: "MiniMax M2.7 (Qoder)" },
],
oauth: {
openApiBaseUrl: "https://openapi.qoder.sh",

View File

@@ -85,7 +85,7 @@ export function clearSessionStore() {
// Conversation-stable session store: Key = hash(scope+assistant text), Value = { sessionId, lastUsed }
const assistantSessionStore = new Map();
const ASSISTANT_MIN_LEN = 50;
const ASSISTANT_CAP_LEN = 200;
const ASSISTANT_CAP_LEN = 50;
const MAX_ASSISTANT_SESSIONS = 5000;
// Client headers/body fields that carry an upstream session id (priority order)

View File

@@ -1,6 +1,6 @@
{
"name": "9router-app",
"version": "0.5.2",
"version": "0.5.3",
"description": "9Router web dashboard",
"private": true,
"scripts": {

View File

@@ -44,7 +44,7 @@ export default function RootLayout({ children }) {
{children}
</RuntimeI18nProvider>
</ThemeProvider>
{gaId && <GoogleAnalytics gaId={"G-LC959F603F"} />}
<GoogleAnalytics gaId={"G-LC959F603F"} />
</body>
</html>
);

View File

@@ -2,9 +2,10 @@
import { describe, it, expect, beforeEach } from "vitest";
import { resolveSessionId, deriveSessionId, clearSessionStore } from "../../open-sse/utils/sessionManager.js";
// Assistant text must exceed ASSISTANT_MIN_LEN (50) to trigger sticky hash path.
// Assistant text must reach ASSISTANT_MIN_LEN (80) to use assistant anchor; else first user message.
const longAssistant = "x".repeat(80);
const bodyWithAssistant = { messages: [{ role: "assistant", content: longAssistant }] };
const bodyWithUserOnly = { messages: [{ role: "user", content: "hello from first user message anchor" }] };
beforeEach(() => clearSessionStore());
@@ -26,6 +27,18 @@ describe("resolveSessionId", () => {
expect(a).not.toBe(b);
});
it("first user message anchor when assistant text below cap", () => {
const opts = { body: bodyWithUserOnly, connectionId: "conn1", scope: "codex" };
expect(resolveSessionId(opts)).toBe(resolveSessionId(opts));
});
it("assistant anchor wins once assistant text reaches cap", () => {
const shortAssistant = { messages: [{ role: "user", content: "same user" }, { role: "assistant", content: "y".repeat(80) }] };
const a = resolveSessionId({ body: shortAssistant, connectionId: "conn1", scope: "codex" });
const b = resolveSessionId({ body: shortAssistant, connectionId: "conn1", scope: "codex" });
expect(a).toBe(b);
});
it("fallback: empty body+no header+no workspaceId -> deriveSessionId(connectionId)", () => {
const got = resolveSessionId({ body: {}, connectionId: "connFallback" });
expect(got).toBe(deriveSessionId("connFallback"));