feat: AI Router per session; Settings at the sidebar's foot; shipped tool icons
AI Router is a session's choice, not a workspace's: - an AI Router select beside the model picker in the workspace home and a pane's run form (RouterPicker.tsx; hidden off Claude/Codex or with only Native; last pick remembered in agenthub.session.router) - `router` on POST /api/lanes/:id/start and POST /api/run; Claude gets --settings=<data dir>/router-settings/<name>.json (0600, outranks project and user settings, key never in argv), Codex -p <name> + key via tmux -e - dashboard_runs.router; a resume naming none goes back to it - profile PATCH rewrites the session files, DELETE removes them - gone: POST /api/lanes/:id/router/apply, LaneRouterRow, the Add-workspace router radio, the claude-/codex-home `routers` answers; clearLaneRouters takes the old keys out of each workspace's settings.local.json at start Sidebar: Settings pinned to the foot, the collapse toggle beside it (stacked on the rail) instead of in the brand's corner. Icons: shipped SVG marks for claude, codex, openclaw and hermes (a black/white pair swapped by theme) in client/public/ai-tools/, used by AiToolIcon before the server's favicon.
This commit is contained in:
@@ -25,7 +25,6 @@ const APP_VERSION = (() => {
|
||||
const { getSettingsPath, getClaudeHome, setClaudeHome } = require("../lib/claude-home");
|
||||
const { getCodexHome, setCodexHome } = require("../lib/codex-home");
|
||||
const { envOwned } = require("../lib/settings-env");
|
||||
const { reapplyCodexLayers, lanesWithMissingRouter } = require("../lib/router-apply");
|
||||
const pricingSync = require("../lib/pricing-sync");
|
||||
|
||||
function getDbSize() {
|
||||
@@ -285,7 +284,7 @@ router.get("/export", (_req, res) => {
|
||||
// overridden again at the next start), PUT validates, applies and persists
|
||||
// (server/lib/settings-env.js). EBADHOME = too broad, INVALID_PATH = any other
|
||||
// bad path, 500 ESAVE = the settings file could not be written.
|
||||
function homeRoutes(route, key, field, get, set, after = () => ({})) {
|
||||
function homeRoutes(route, key, field, get, set) {
|
||||
router.get(route, (_req, res) => {
|
||||
res.json({ [field]: get(), env_owned: envOwned.has(key) });
|
||||
});
|
||||
@@ -308,20 +307,15 @@ function homeRoutes(route, key, field, get, set, after = () => ({})) {
|
||||
error: { code: bad ? err.code : "ESAVE", message: err.message },
|
||||
});
|
||||
}
|
||||
res.json({ ok: true, [field]: resolved, env_owned: envOwned.has(key), ...after() });
|
||||
res.json({ ok: true, [field]: resolved, env_owned: envOwned.has(key) });
|
||||
});
|
||||
}
|
||||
|
||||
// GET/PUT /api/settings/claude-home — a PUT names the lanes whose AI Router
|
||||
// profile the new home's store does not have (they would start on native).
|
||||
homeRoutes("/claude-home", "CLAUDE_HOME", "claude_home", getClaudeHome, setClaudeHome, () => ({
|
||||
routers: { missing: lanesWithMissingRouter() },
|
||||
}));
|
||||
// GET/PUT /api/settings/codex-home — a PUT re-writes every codex lane's AI
|
||||
// Router layer into the new home, or `codex -p <name>` fails at the next start.
|
||||
homeRoutes("/codex-home", "CODEX_HOME", "codex_home", getCodexHome, setCodexHome, () => ({
|
||||
routers: reapplyCodexLayers(),
|
||||
}));
|
||||
// GET/PUT /api/settings/claude-home
|
||||
homeRoutes("/claude-home", "CLAUDE_HOME", "claude_home", getClaudeHome, setClaudeHome);
|
||||
// GET/PUT /api/settings/codex-home — a session's AI Router layer is written
|
||||
// into the current home at its spawn, so a move needs no repair here.
|
||||
homeRoutes("/codex-home", "CODEX_HOME", "codex_home", getCodexHome, setCodexHome);
|
||||
|
||||
// POST /api/settings/cleanup — abandon stale sessions, purge old data
|
||||
router.post("/cleanup", (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user