chore: update version and enhance provider model configurations.

This commit is contained in:
decolua
2026-02-22 11:30:43 +07:00
parent ea67742f2a
commit 930e917092
7 changed files with 46 additions and 53 deletions

View File

@@ -60,13 +60,10 @@ export const PROVIDER_MODELS = {
{ id: "glm-5", name: "GLM 5" }, { id: "glm-5", name: "GLM 5" },
], ],
ag: [ // Antigravity - special case: models call different backends ag: [ // Antigravity - special case: models call different backends
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking" },
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
{ id: "gemini-3-1-pro-high", name: "Gemini 3.1 Pro High" },
{ id: "gemini-3-1-pro-low", name: "Gemini 3.1 Pro Low" },
{ id: "gemini-3-pro-high", name: "Gemini 3 Pro High" },
{ id: "gemini-3-pro-low", name: "Gemini 3 Pro Low" },
{ id: "gemini-3-flash", name: "Gemini 3 Flash" }, { id: "gemini-3-flash", name: "Gemini 3 Flash" },
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking" },
{ id: "gpt-oss-120b-medium", name: "GPT OSS 120B Medium" },
], ],
gh: [ // GitHub Copilot - OpenAI models gh: [ // GitHub Copilot - OpenAI models
{ id: "gpt-3.5-turbo", name: "GPT-3.5 Turbo" }, { id: "gpt-3.5-turbo", name: "GPT-3.5 Turbo" },

View File

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

View File

@@ -1,13 +1,11 @@
"use client"; "use client";
import { useMemo, useState, useCallback, useRef, useEffect } from "react"; import { useMemo, useState, useCallback, useRef } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
ReactFlow, ReactFlow,
Handle, Handle,
Position, Position,
useNodesState,
useEdgesState,
} from "@xyflow/react"; } from "@xyflow/react";
import "@xyflow/react/dist/style.css"; import "@xyflow/react/dist/style.css";
import { AI_PROVIDERS } from "@/shared/constants/providers"; import { AI_PROVIDERS } from "@/shared/constants/providers";
@@ -193,46 +191,30 @@ function buildLayout(providers, activeSet, lastSet, errorSet) {
} }
export default function ProviderTopology({ providers = [], activeRequests = [], lastProvider = "", errorProvider = "" }) { export default function ProviderTopology({ providers = [], activeRequests = [], lastProvider = "", errorProvider = "" }) {
const activeSet = useMemo( // Serialize to stable string keys so useMemo only re-runs when values actually change
() => new Set(activeRequests.map((r) => r.provider?.toLowerCase()).filter(Boolean)), const activeKey = useMemo(
() => activeRequests.map((r) => r.provider?.toLowerCase()).filter(Boolean).sort().join(","),
[activeRequests] [activeRequests]
); );
const lastKey = lastProvider?.toLowerCase() || "";
const errorKey = errorProvider?.toLowerCase() || "";
const lastSet = useMemo( const activeSet = useMemo(() => new Set(activeKey ? activeKey.split(",") : []), [activeKey]);
() => new Set(lastProvider ? [lastProvider.toLowerCase()] : []), const lastSet = useMemo(() => new Set(lastKey ? [lastKey] : []), [lastKey]);
[lastProvider] const errorSet = useMemo(() => new Set(errorKey ? [errorKey] : []), [errorKey]);
const { nodes, edges } = useMemo(
() => buildLayout(providers, activeSet, lastSet, errorSet),
[providers, activeKey, lastKey, errorKey]
); );
const errorSet = useMemo( // Stable key — only remount when provider list changes
() => new Set(errorProvider ? [errorProvider.toLowerCase()] : []),
[errorProvider]
);
// Stable key for providers list — only changes when provider set changes
const providersKey = useMemo( const providersKey = useMemo(
() => providers.map((p) => p.provider).sort().join(","), () => providers.map((p) => p.provider).sort().join(","),
[providers] [providers]
); );
const { nodes: layoutNodes, edges: layoutEdges } = useMemo(
() => buildLayout(providers, activeSet, lastSet, errorSet),
[providers, activeSet, lastSet, errorSet]
);
const [nodes, setNodes, onNodesChange] = useNodesState(layoutNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(layoutEdges);
const rfInstance = useRef(null); const rfInstance = useRef(null);
// Sync nodes/edges when data changes
useEffect(() => {
setNodes(layoutNodes);
setEdges(layoutEdges);
// Re-fit view after update
if (rfInstance.current) {
setTimeout(() => rfInstance.current.fitView({ padding: 0.3 }), 50);
}
}, [layoutNodes, layoutEdges, setNodes, setEdges]);
const onInit = useCallback((instance) => { const onInit = useCallback((instance) => {
rfInstance.current = instance; rfInstance.current = instance;
setTimeout(() => instance.fitView({ padding: 0.3 }), 50); setTimeout(() => instance.fitView({ padding: 0.3 }), 50);
@@ -249,8 +231,6 @@ export default function ProviderTopology({ providers = [], activeRequests = [],
key={providersKey} key={providersKey}
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
fitView fitView
fitViewOptions={{ padding: 0.3 }} fitViewOptions={{ padding: 0.3 }}

View File

@@ -186,6 +186,7 @@ const server = https.createServer(sslOptions, async (req, res) => {
} }
const model = extractModel(bodyBuffer); const model = extractModel(bodyBuffer);
console.log(`📡 ${model} (passthrough)`);
const mappedModel = getMappedModel(model); const mappedModel = getMappedModel(model);
if (!mappedModel) { if (!mappedModel) {

View File

@@ -128,14 +128,14 @@ export const CLI_TOOLS = {
color: "#4285F4", color: "#4285F4",
description: "Google Antigravity IDE with MITM", description: "Google Antigravity IDE with MITM",
configType: "mitm", configType: "mitm",
modelAliases: ["claude-opus-4-6-thinking", "claude-sonnet-4-6-thinking", "gemini-3-pro-high"], modelAliases: ["claude-opus-4-6-thinking", "claude-sonnet-4-6", "gemini-3-flash", "gpt-oss-120b-medium", "gemini-3-pro-high", "gemini-3-pro-low"],
defaultModels: [ defaultModels: [
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking", alias: "claude-opus-4-6-thinking" },
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", alias: "claude-sonnet-4-6" },
{ id: "gemini-3-1-pro-high", name: "Gemini 3.1 Pro High", alias: "gemini-3-1-pro-high" },
{ id: "gemini-3-1-pro-low", name: "Gemini 3.1 Pro Low", alias: "gemini-3-1-pro-low" },
{ id: "gemini-3-pro-high", name: "Gemini 3 Pro High", alias: "gemini-3-pro-high" }, { id: "gemini-3-pro-high", name: "Gemini 3 Pro High", alias: "gemini-3-pro-high" },
{ id: "gemini-3-pro-low", name: "Gemini 3 Pro Low", alias: "gemini-3-pro-low" },
{ id: "gemini-3-flash", name: "Gemini 3 Flash", alias: "gemini-3-flash" }, { id: "gemini-3-flash", name: "Gemini 3 Flash", alias: "gemini-3-flash" },
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", alias: "claude-sonnet-4-6" },
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking", alias: "claude-opus-4-6-thinking" },
{ id: "gpt-oss-120b-medium", name: "GPT OSS 120B Medium", alias: "gpt-oss-120b-medium" },
], ],
}, },
// HIDDEN: gemini-cli // HIDDEN: gemini-cli

View File

@@ -355,6 +355,13 @@ export const DEFAULT_PRICING = {
cached: 0.50, cached: 0.50,
reasoning: 37.50, reasoning: 37.50,
cache_creation: 5.00 cache_creation: 5.00
},
"gpt-oss-120b-medium": {
input: 0.50,
output: 2.00,
cached: 0.25,
reasoning: 3.00,
cache_creation: 0.50
} }
}, },

View File

@@ -2,6 +2,11 @@ import { cleanupProviderConnections, getSettings } from "@/lib/localDb";
import { enableTunnel } from "@/lib/tunnel/tunnelManager"; import { enableTunnel } from "@/lib/tunnel/tunnelManager";
import { killCloudflared, isCloudflaredRunning, ensureCloudflared } from "@/lib/tunnel/cloudflared"; import { killCloudflared, isCloudflaredRunning, ensureCloudflared } from "@/lib/tunnel/cloudflared";
// Multiple modules register SIGINT/SIGTERM handlers legitimately
process.setMaxListeners(20);
let signalHandlersRegistered = false;
/** /**
* Initialize app on startup * Initialize app on startup
* - Cleanup stale data * - Cleanup stale data
@@ -24,13 +29,16 @@ export async function initializeApp() {
} }
} }
// Kill cloudflared on process exit // Kill cloudflared on process exit (register once only)
const cleanup = () => { if (!signalHandlersRegistered) {
killCloudflared(); const cleanup = () => {
process.exit(); killCloudflared();
}; process.exit();
process.on("SIGINT", cleanup); };
process.on("SIGTERM", cleanup); process.on("SIGINT", cleanup);
process.on("SIGTERM", cleanup);
signalHandlersRegistered = true;
}
// Pre-download cloudflared binary in background // Pre-download cloudflared binary in background
ensureCloudflared().catch(() => {}); ensureCloudflared().catch(() => {});