feat(config): opt-in autoModelPath for SDK model-path pinning

The SDK now defaults automatic DeepSeek model-path selection to off, so
surface it as an operator setting: `autoModelPath` in
~/.routstrd/config.json (default false), threaded into routeRequests via
the daemon request handler. Explicit x-routstr-model-path headers are
unaffected.

Requires a daemon restart after changing the value, matching how the other
startup config fields reach the handler. Documented in the README config
section; the config-store scenario covers the default and a round-trip.
This commit is contained in:
redshift
2026-09-29 16:30:12 +08:00
parent c7b8a2ae5b
commit 9ba3e216d8
5 changed files with 16 additions and 0 deletions
+6
View File
@@ -276,6 +276,7 @@ Configuration is stored in `~/.routstrd/config.json`:
"host": "127.0.0.1",
"provider": null,
"cocodPath": null,
"autoModelPath": false,
"autoRefresh": { "enabled": true }
}
```
@@ -287,6 +288,11 @@ every 21 minutes. Set it to `false` (or run
refresh manually with `routstrd clients --manual-refresh`. `autoRefresh.intervalMs`
overrides the 21-minute interval.
`autoModelPath` defaults to `false`. Set it to `true` to let the SDK automatically
choose and pin an advertised model path for `deepseek-v4.1-flash` requests.
Explicit `x-routstr-model-path` request headers work independently of this
setting and take precedence. Restart the daemon after changing `autoModelPath`.
### Environment Variables
- `ROUTSTRD_DIR` - Config directory (default: `~/.routstrd`)
+3
View File
@@ -392,6 +392,8 @@ export function createDaemonRequestHandler(deps: {
mode?: "xcashu" | "apikeys";
/** Default max_tokens/max_output_tokens to inject when the client omits one. */
maxTokens: number;
/** Enable SDK automatic DeepSeek V4.1 Flash model-path selection. */
autoModelPath?: boolean;
/** Nostr hex pubkey for routstr review/audit events (kind 38425). */
routstrPubkey?: string;
/** Nostr hex pubkey for the routstr-21 model list only (kind 38423). Falls back to routstrPubkey. */
@@ -1932,6 +1934,7 @@ export function createDaemonRequestHandler(deps: {
requestBody,
path: url.pathname,
forcedProvider,
autoModelPath: deps.autoModelPath === true,
headers: incomingHeaders,
walletAdapter: deps.walletAdapter,
storageAdapter: deps.storageAdapter,
+1
View File
@@ -214,6 +214,7 @@ export async function runDaemon(argv: string[] = process.argv): Promise<void> {
getModelProviders,
refreshProvidersAndModels,
mode: config.mode || "apikeys",
autoModelPath: config.autoModelPath === true,
maxTokens: config.maxTokens ?? 64000,
routstrPubkey: config.routstrPubkey,
routstrModelsPubkey: config.routstrModelsPubkey,
+3
View File
@@ -48,6 +48,8 @@ export interface RoutstrdConfig {
provider: string | null;
cocodPath: string | null;
mode?: "xcashu" | "apikeys";
/** Opt into SDK automatic model-path selection for DeepSeek V4.1 Flash. Disabled by default; requires daemon restart after changing. */
autoModelPath?: boolean;
/** Raw upstream request/response logging. Disabled by default because logs can contain sensitive prompts, outputs, and auth/payment headers. */
requestResponseLogging?: {
/** Enable raw request/response file logging. */
@@ -87,5 +89,6 @@ export const DEFAULT_CONFIG: RoutstrdConfig = {
provider: null,
cocodPath: null,
mode: "apikeys",
autoModelPath: false,
maxTokens: 64000,
};
+3
View File
@@ -38,8 +38,10 @@ const scenario = process.argv[2];
switch (scenario) {
case "fresh-install": {
assert(loadDaemonConfigSync().autoModelPath === false, "autoModelPath must default to false");
saveDaemonConfig({
...baseConfig,
autoModelPath: true,
nsec: "nsec1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
});
assert(modeOf(CONFIG_DIR) === 0o700, `dir mode ${modeOf(CONFIG_DIR).toString(8)} != 700`);
@@ -54,6 +56,7 @@ switch (scenario) {
"nsec round-trip failed",
);
assert(loaded.port === 8008, "port round-trip failed");
assert(loaded.autoModelPath === true, "autoModelPath round-trip failed");
await ensureDirs();
assert(modeOf(CONFIG_DIR) === 0o700, "ensureDirs dir mode");