dsh-multi-router 0.6.8 → 0.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import {
2
2
  isFreeModel,
3
3
  reasoningModes,
4
4
  writePrivateJson
5
- } from "./chunk-XD52ZGZ5.js";
5
+ } from "./chunk-GEBZMIMA.js";
6
6
 
7
7
  // src/telemetry.mjs
8
8
  import { createHash, randomUUID } from "node:crypto";
@@ -335,48 +335,94 @@ var Router = class {
335
335
  this.active = /* @__PURE__ */ new Map();
336
336
  this.budgets = /* @__PURE__ */ new Map();
337
337
  }
338
+ /**
339
+ * Sort candidates inside each expiring-credit group, never across the boundary.
340
+ *
341
+ * `expiry` identifies the group: candidates that share one expiring date form a group
342
+ * that keeps its place relative to the others. Only the order inside a group changes,
343
+ * which is what keeps a cheaper account from jumping ahead of one with credits that
344
+ * expire sooner. `key` returning undefined means "no opinion" and sorts last inside
345
+ * its own group rather than counting as the cheapest.
346
+ */
347
+ sortWithinGroups(candidates, expiry, key) {
348
+ const groups = /* @__PURE__ */ new Map();
349
+ for (const candidate of candidates) {
350
+ const group = expiry(candidate);
351
+ if (!groups.has(group)) groups.set(group, []);
352
+ groups.get(group).push(candidate);
353
+ }
354
+ const result = [];
355
+ for (const group of groups.values()) {
356
+ const decorated = group.map((candidate, index) => ({ candidate, index, key: key(candidate) }));
357
+ decorated.sort((a, b) => {
358
+ if (a.key === b.key) return a.index - b.index;
359
+ if (a.key === void 0) return 1;
360
+ if (b.key === void 0) return -1;
361
+ return a.key - b.key;
362
+ });
363
+ result.push(...decorated.map((entry) => entry.candidate));
364
+ }
365
+ return result;
366
+ }
338
367
  /**
339
368
  * Move accounts whose observed credit spend exceeded this route's threshold behind
340
- * the ones that still have headroom.
369
+ * the ones that still have headroom, within each expiring-credit group.
341
370
  *
342
371
  * This is a preference, not a filter: the caller keeps every candidate, so a route
343
372
  * whose accounts are all over budget still serves requests instead of failing. The
344
373
  * baseline is per route and per account, so switching accounts resets a newcomer's
345
374
  * counter to zero while the previous account stays demoted for the rest of the round.
346
375
  *
347
- * Once every candidate has spent its allowance the round is over and each baseline
348
- * restarts from the current total. Without that reset the counters only ever grow,
349
- * every account stays demoted forever and the ordering stops changing after one pass.
376
+ * The demotion is scoped to a group so it cannot outrank expiring credits: an account
377
+ * holding credits that expire sooner stays ahead even after it has spent its allowance.
378
+ *
379
+ * Once every candidate in a group has spent its allowance the round is over and those
380
+ * baselines restart from the current total. Without that reset the counters only ever
381
+ * grow, every account stays demoted forever and the ordering stops changing after one pass.
350
382
  *
351
383
  * Spend is inferred from platform balance drops, so one request may overshoot and an
352
384
  * account without a usable balance reading is never demoted on a guess.
353
385
  */
354
- demoteOverBudget(alias, route, candidates) {
386
+ demoteOverBudget(alias, route, candidates, expiry = () => Infinity) {
355
387
  if (!candidates.length) return candidates;
356
388
  const threshold = route.creditBalanceThreshold ?? 1e3;
357
389
  const bases = this.budgets.get(alias) ?? /* @__PURE__ */ new Map();
358
390
  this.budgets.set(alias, bases);
359
391
  const live = new Set(candidates.map((c) => c.account.id));
360
392
  for (const id of bases.keys()) if (!live.has(id)) bases.delete(id);
361
- const fresh = [], spent = [];
393
+ const groups = /* @__PURE__ */ new Map();
362
394
  for (const candidate of candidates) {
363
- const id = candidate.account.id, row = this.telemetry.row("accounts", id);
364
- const observed = row.creditsObserved ?? 0;
365
- if (!bases.has(id)) bases.set(id, observed);
366
- const used = observed - bases.get(id);
367
- if (!Number.isFinite(used) || used < 0) {
368
- bases.set(id, observed);
369
- fresh.push(candidate);
395
+ const group = expiry(candidate);
396
+ if (!groups.has(group)) groups.set(group, []);
397
+ groups.get(group).push(candidate);
398
+ }
399
+ const result = [];
400
+ for (const group of groups.values()) {
401
+ const fresh = [], spent = [];
402
+ for (const candidate of group) {
403
+ const id = candidate.account.id, row = this.telemetry.row("accounts", id);
404
+ const observed = row.creditsObserved ?? 0;
405
+ if (!bases.has(id)) bases.set(id, observed);
406
+ const used = observed - bases.get(id);
407
+ if (!Number.isFinite(used) || used < 0) {
408
+ bases.set(id, observed);
409
+ fresh.push(candidate);
410
+ continue;
411
+ }
412
+ (used >= threshold ? spent : fresh).push(candidate);
413
+ }
414
+ if (!spent.length) {
415
+ result.push(...fresh);
370
416
  continue;
371
417
  }
372
- (used >= threshold ? spent : fresh).push(candidate);
373
- }
374
- if (!spent.length) return fresh;
375
- if (spent.length === candidates.length) {
376
- for (const candidate of candidates) bases.set(candidate.account.id, this.telemetry.row("accounts", candidate.account.id).creditsObserved ?? 0);
377
- return candidates;
418
+ if (spent.length === group.length) {
419
+ for (const candidate of group) bases.set(candidate.account.id, this.telemetry.row("accounts", candidate.account.id).creditsObserved ?? 0);
420
+ result.push(...group);
421
+ continue;
422
+ }
423
+ result.push(...fresh, ...spent);
378
424
  }
379
- return [...fresh, ...spent];
425
+ return result;
380
426
  }
381
427
  updateConfig(config) {
382
428
  for (const old of this.config.accounts) {
@@ -516,8 +562,16 @@ var Router = class {
516
562
  }
517
563
  preferActive ??= await this.syncExpiring(alias, route, expiryCandidates, below);
518
564
  const expiry = (c) => preferActive && !this.telemetry.expiring(alias).completed.includes(c.account.id) ? this.expiringAt(c.account, route) : Infinity;
519
- if (preferActive) candidates.sort((a, b) => expiry(a) - expiry(b));
520
- if (route.balanceCredits && !route.freeOnly && this.telemetry) candidates = this.demoteOverBudget(alias, route, candidates);
565
+ if (preferActive) {
566
+ const ordered = candidates.map((candidate, index) => ({ candidate, index }));
567
+ ordered.sort((a, b) => expiry(a.candidate) - expiry(b.candidate) || a.index - b.index);
568
+ candidates = ordered.map((entry) => entry.candidate);
569
+ }
570
+ if (route.discountOrder && !route.freeOnly) candidates = this.sortWithinGroups(candidates, expiry, (candidate) => {
571
+ const rate = route.creditRates?.[candidate.account.id];
572
+ return rate === void 0 ? void 0 : rate;
573
+ });
574
+ if (route.balanceCredits && !route.freeOnly && this.telemetry) candidates = this.demoteOverBudget(alias, route, candidates, expiry);
521
575
  if (strategy === "weighted") {
522
576
  let eligible = candidates.filter(available);
523
577
  const nearest = Math.min(Infinity, ...eligible.map(expiry));
@@ -613,4 +667,4 @@ export {
613
667
  matchModel,
614
668
  Router
615
669
  };
616
- //# sourceMappingURL=chunk-Q6A57FN3.js.map
670
+ //# sourceMappingURL=chunk-R2Z4WGR6.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/telemetry.mjs", "../src/model-context.mjs", "../src/router.mjs"],
4
+ "sourcesContent": ["import { createHash, randomUUID } from 'node:crypto';\nimport { assistantStreamFirstTokenTime } from '@deepseek-ai/dsh-llm';\nimport { readFile } from 'node:fs/promises';\nimport { writePrivateJson } from './config.mjs';\nconst empty = () => ({ requests: 0, failures: 0, input: 0, output: 0, tokens: 0, unmetered: 0 });\nconst day = at => new Date(at).toLocaleDateString('en-CA', { timeZone: 'Asia/Shanghai' });\nconst safe = n => typeof n === 'number' && Number.isFinite(n) && n >= 0 ? n : 0;\nconst measured = n => typeof n === 'number' && Number.isFinite(n) && n >= 0 ? n : null;\nexport class Telemetry {\n constructor(file, now = Date.now) { this.file = file; this.now = now; this.retentionDays = 30; this.data = { accounts: {}, routes: {}, days: {}, rounds: {}, expiringRounds: {}, events: [] }; this.queue = Promise.resolve(); }\n async load() {\n try { const saved = JSON.parse(await readFile(this.file, 'utf8')); if (saved.version !== 1) throw Error('Unsupported telemetry'); this.data = { ...saved, expiringRounds: saved.expiringRounds ?? {} }; }\n catch (e) { if (e.code !== 'ENOENT') throw e; }\n if (this.prune()) await this.persist();\n }\n configure(retentionDays) { this.retentionDays = retentionDays; }\n prune() {\n const cutoff = this.now() - this.retentionDays * 86400000, before = this.data.events.length;\n this.data.events = this.data.events.filter(e => Number.isFinite(e.at) && e.at >= cutoff);\n return before !== this.data.events.length;\n }\n row(group, key) { if (!Object.hasOwn(this.data[group], key)) Object.defineProperty(this.data[group], key, { value: empty(), enumerable: true, writable: true }); return this.data[group][key]; }\n count(alias, account) { return this.row('routes', JSON.stringify([alias, account])); }\n expiring(alias) {\n if (!Object.hasOwn(this.data.expiringRounds, alias)) Object.defineProperty(this.data.expiringRounds, alias, { value: { accounts: [], completed: [], cooldownUntil: 0, number: 1 }, enumerable: true, writable: true });\n return this.data.expiringRounds[alias];\n }\n restartExpiring(alias) { const row = this.expiring(alias); row.accounts = []; row.completed = []; row.cooldownUntil = 0; row.number++; return this.persist(); }\n round(alias, signature) {\n if (!Object.hasOwn(this.data.rounds, alias) || this.data.rounds[alias].signature !== signature) Object.defineProperty(this.data.rounds, alias, { value: { signature, number: 1, bases: {} }, enumerable: true, writable: true });\n return this.data.rounds[alias];\n }\n advance(alias, candidates, signature) {\n const round = this.round(alias, signature); round.number++;\n for (const c of candidates) Object.defineProperty(round.bases, c.account.id, { value: { tokens: this.count(alias, c.account.id).tokens, credits: this.row('accounts', c.account.id).creditsObserved ?? 0 }, enumerable: true, writable: true, configurable: true });\n return this.persist();\n }\n observe(account, snapshot) {\n const row = this.row('accounts', account);\n if (Number.isFinite(snapshot.remaining) && snapshot.unit === 'credits') {\n const sameCycle = row.balance?.cycle === snapshot.cycle;\n const change = sameCycle && Number.isFinite(row.balance?.remaining) ? Math.max(0, row.balance.remaining - snapshot.remaining) : 0;\n row.creditsObserved = (row.creditsObserved ?? 0) + change;\n }\n row.balance = snapshot;\n return this.persist();\n }\n record(event) {\n const at = this.now();\n const rows = [this.row('accounts', event.account), this.count(event.alias, event.account), this.row('days', day(at))];\n for (const row of rows) {\n row.requests++; if (!event.ok) row.failures++;\n if (event.usage) { const input = safe(event.usage.prompt_tokens), output = safe(event.usage.completion_tokens); row.input += input; row.output += output; row.tokens += safe(event.usage.total_tokens) || input + output; }\n else if (event.status === 200 || event.accepted) row.unmetered++;\n }\n const input = measured(event.usage?.prompt_tokens), output = measured(event.usage?.completion_tokens);\n this.data.events.unshift({ at, account: event.account, provider: event.provider, alias: event.alias, model: event.model ?? null, status: event.status,\n outcome: event.ok ? 'completed' : event.cancelled ? 'cancelled' : 'failed', input, output,\n tokens: measured(event.usage?.total_tokens) ?? (input !== null && output !== null ? input + output : null),\n cachedInput: measured(event.usage?.prompt_tokens_details?.cached_tokens), reasoningOutput: measured(event.usage?.completion_tokens_details?.reasoning_tokens),\n callId: event.callId ?? null, session: event.session ?? null, source: event.source === 'api' ? 'api' : 'dsh',\n timing: event.timing ? Object.fromEntries(['modelMs', 'ttftMs', 'decodeMs', 'decodeTokens'].map(k => [k, measured(event.timing[k])])) : null, timingSource: event.timing ? 'upstream' : null });\n const dates = Object.keys(this.data.days).sort(); for (const key of dates.slice(0, -31)) delete this.data.days[key];\n return this.persist();\n }\n persist() { this.prune(); const saved = structuredClone({ ...this.data, version: 1 }); this.queue = this.queue.catch(() => {}).then(() => writePrivateJson(this.file, saved)); return this.queue; }\n state() { this.prune(); return { ...structuredClone(this.data), retentionDays: this.retentionDays, today: day(this.now()), updatedAt: this.now() }; }\n}\n\n// Pass bytes through unchanged; parse only usage and terminal/error markers, never persist content.\nexport function meterResponse(response, complete, signal, { now = () => performance.now(), startedAt = now() } = {}) {\n if (!response.body) return response;\n const reader = response.body.getReader(), decoder = new TextDecoder();\n let pending = '', usage, ended = false, failed = false, finished = false, firstToken = null, terminalAt = null;\n async function finish(cancelled = false) { if (finished) return; finished = true; const end = terminalAt ?? now(); await complete({ usage, ok: ended && !failed && !cancelled, cancelled, timing: { modelMs: Math.max(0, end - startedAt), ttftMs: firstToken === null ? null : Math.max(0, firstToken - startedAt), decodeMs: firstToken === null ? null : Math.max(0, end - firstToken), decodeTokens: firstToken === null ? null : measured(usage?.completion_tokens) } }); }\n function inspect(bytes) {\n pending += decoder.decode(bytes, { stream: true });\n let split;\n while ((split = /\\r?\\n\\r?\\n/.exec(pending))) {\n const frame = pending.slice(0, split.index); pending = pending.slice(split.index + split[0].length);\n const data = frame.split(/\\r?\\n/).filter(l => l.startsWith('data:')).map(l => l.slice(5).trimStart()).join('\\n');\n if (data === '[DONE]') { ended = true; terminalAt ??= now(); continue; }\n try { const value = JSON.parse(data); if (value.usage && ['prompt_tokens', 'completion_tokens', 'total_tokens'].some(k => Number.isFinite(value.usage[k]) && value.usage[k] >= 0)) usage = value.usage; if (value.error) failed = true; if (firstToken === null && value.choices?.some(c => { const d = c.delta; return [d?.content, d?.reasoning_content, d?.reasoning].some(v => typeof v === 'string' && v.trim()) || d?.tool_calls?.some(t => t.function?.name || t.function?.arguments); })) firstToken = now(); if (value.choices?.some(c => c.finish_reason)) { ended = true; terminalAt ??= now(); } } catch { /* Unknown frame is forwarded. */ }\n }\n if (pending.length > 1024 * 1024) { pending = ''; failed = true; }\n }\n const body = new ReadableStream({\n async pull(controller) {\n try { signal?.throwIfAborted(); const chunk = await reader.read(); if (chunk.done) { await finish(); controller.close(); } else { inspect(chunk.value); controller.enqueue(chunk.value); } }\n catch (e) { await finish(signal?.aborted); controller.error(e); await reader.cancel().catch(() => {}); }\n },\n async cancel(reason) { await reader.cancel(reason).catch(() => {}); await finish(!ended); },\n });\n return new Response(body, { status: response.status, headers: response.headers });\n}\n\n// Link local transport attempts to DSH steps without retaining titles, prompts,\n// tool names/arguments/results, or the original session identity.\nexport class SessionMetrics {\n constructor(telemetry) { this.telemetry = telemetry; this.steps = new Map(); }\n key(id) { return createHash('sha256').update(String(id)).digest('hex').slice(0, 24); }\n beginCall(sessionId, purpose) {\n const callId = randomUUID(), session = sessionId == null ? null : this.key(sessionId);\n const step = session && this.steps.get(session);\n if (step && !purpose) step.callId = callId;\n return { callId, session };\n }\n event(session, event) {\n const key = this.key(session.id), d = event.data;\n if (event.type === 'step/start') { this.steps.set(key, { turn: d.turn, step: d.step, start: event.time, first: null, calls: new Map(), toolMs: 0, toolCount: 0, toolsCompleted: 0 }); return; }\n const step = this.steps.get(key);\n if (!step) return;\n if (d.turn !== undefined && (d.turn !== step.turn || d.step !== undefined && d.step !== step.step)) return;\n if (event.type === 'assistant/attempt') { step.first ??= assistantStreamFirstTokenTime(d.stream) ?? null; return; }\n const row = this.telemetry.data.events.find(e => e.callId === step.callId && e.session === key);\n if (event.type === 'assistant/message') {\n if (!row || d.interrupted) return;\n const first = step.first ?? assistantStreamFirstTokenTime(d.stream) ?? null;\n const output = measured(d.usage?.outputTokens);\n row.timing = { modelMs: Math.max(0, event.time - step.start), ttftMs: first === null ? null : Math.max(0, first - step.start),\n decodeMs: first === null || output === null ? null : Math.max(0, event.time - first), decodeTokens: first === null ? null : output };\n row.timingSource = 'dsh-step';\n } else if (event.type === 'tool/call' && row?.timingSource === 'dsh-step') {\n if (!step.calls.has(d.callId)) { step.calls.set(d.callId, event.time); step.toolCount++; }\n } else if (event.type === 'tool/result' && step.calls.has(d.message?.source?.callId)) {\n const id = d.message.source.callId;\n step.toolMs += Math.max(0, event.time - step.calls.get(id)); step.toolsCompleted++; step.calls.delete(id);\n } else if (event.type === 'step/end' || event.type === 'turn/end') {\n this.steps.delete(key);\n } else return;\n if (row?.timingSource !== 'dsh-step') return;\n Object.assign(row.timing, { toolMs: step.toolMs, toolCount: step.toolCount, toolsCompleted: step.toolsCompleted });\n return this.telemetry.persist();\n }\n dispose(session) { this.steps.delete(this.key(session.id)); }\n}\n", "const positive = n => Number.isSafeInteger(n) && n > 0;\n\n// Preserve native/default tiers separately from the local DSH budget.\nexport function contextInfo(model) {\n const defaultContextWindow = positive(model.defaultContextWindow) ? model.defaultContextWindow\n : positive(model.contextWindow) ? model.contextWindow : 200000;\n const supportedContextWindows = [...new Set([defaultContextWindow, model.contextWindow, model.maxContextWindow,\n ...(Array.isArray(model.supportedContextWindows) ? model.supportedContextWindows : [])].filter(positive))].sort((a, b) => a - b);\n const maxContextWindow = supportedContextWindows.at(-1);\n return { defaultContextWindow, supportedContextWindows, maxContextWindow, contextWindow: maxContextWindow };\n}\n\nexport function resolveContext(models, selected, fallback = 200000) {\n const infos = models.map(contextInfo);\n const maxContextWindow = infos.length ? Math.max(...infos.map(m => m.maxContextWindow)) : fallback;\n const contextWindow = positive(selected) ? Math.min(selected, maxContextWindow) : maxContextWindow;\n return { maxContextWindow, contextWindow, contextKnown: infos.length > 0, configuredContextWindow: positive(selected) ? selected : null,\n supportedContextWindows: [...new Set([contextWindow, ...infos.flatMap(m => m.supportedContextWindows)])].sort((a, b) => a - b) };\n}\n\n// Select the smallest real wire tier that can honour a local budget. Never mutate\n// the shared discovered catalog: concurrent routes may request different tiers.\nexport function qoderContextModel(model, budget) {\n if (!model?.contextOptions) return model;\n const entries = Object.entries(model.contextOptions).filter(([, v]) => positive(v.tokenCount)).sort((a, b) => a[1].tokenCount - b[1].tokenCount);\n if (!entries.length) return model;\n const selected = budget == null ? entries.at(-1) : entries.find(([, v]) => v.tokenCount >= budget);\n if (!selected) throw Object.assign(Error('context_window_unavailable'), { status: 400, code: 'context_window_unavailable' });\n return { ...model, contextWindow: selected[1].tokenCount,\n contextOptions: Object.fromEntries(Object.entries(model.contextOptions).map(([key, value]) => [key, { ...value, isDefault: key === selected[0] }])) };\n}\n", "import { meterResponse } from './telemetry.mjs';\nimport { isFreeModel } from './config.mjs';\nimport { reasoningModes } from './reasoning.mjs';\nimport { contextInfo } from './model-context.mjs';\nexport class RouteError extends Error {\n constructor(status, code, attempts = [], hint) {\n super(`${code}${attempts.length ? ': ' + attempts.map(a => `${a.account} HTTP ${a.status}`).join(', ') : ''}${hint ? `\uFF08${hint}\uFF09` : ''}`);\n this.status = status; this.code = code; this.attempts = attempts; this.hint = hint;\n }\n}\nconst normalize = value => value.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/official$/, '');\nexport function abortable(promise, signal) {\n if (!signal) return promise;\n // Attach handlers even if already aborted, so a late rejection is consumed.\n return new Promise((resolve, reject) => {\n const abort = () => reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n signal.addEventListener('abort', abort, { once: true });\n if (signal.aborted) abort();\n Promise.resolve(promise).then(resolve, reject).finally(() => signal.removeEventListener('abort', abort));\n });\n}\nexport function matchModel(alias, target, catalog, effort, provider = target.provider) {\n const allowed = m => m && (effort === undefined || reasoningModes(m, provider).includes(effort));\n if (target.model) return catalog.find(m => m.id === target.model && allowed(m));\n if (target.models) return target.models.map(id => catalog.find(m => m.id === id)).find(allowed);\n if (alias === 'ds4.1f') return catalog.find(m => allowed(m) && [m.id, m.name ?? ''].some(x => normalize(x) === 'deepseekv41flash'));\n}\n\nexport class Router {\n constructor(config, createClient, onAttempt = () => {}, now = Date.now) {\n this.config = config; this.createClient = createClient; this.onAttempt = onAttempt; this.now = now;\n this.telemetry = null; this.scores = new Map(); this.monitor = null; this.clients = new Map(); this.cooldowns = new Map(); this.active = new Map(); this.budgets = new Map();\n }\n /**\n * Sort candidates inside each expiring-credit group, never across the boundary.\n *\n * `expiry` identifies the group: candidates that share one expiring date form a group\n * that keeps its place relative to the others. Only the order inside a group changes,\n * which is what keeps a cheaper account from jumping ahead of one with credits that\n * expire sooner. `key` returning undefined means \"no opinion\" and sorts last inside\n * its own group rather than counting as the cheapest.\n */\n sortWithinGroups(candidates, expiry, key) {\n const groups = new Map();\n for (const candidate of candidates) {\n const group = expiry(candidate);\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group).push(candidate);\n }\n const result = [];\n for (const group of groups.values()) {\n const decorated = group.map((candidate, index) => ({ candidate, index, key: key(candidate) }));\n decorated.sort((a, b) => {\n if (a.key === b.key) return a.index - b.index;\n if (a.key === undefined) return 1;\n if (b.key === undefined) return -1;\n return a.key - b.key;\n });\n result.push(...decorated.map(entry => entry.candidate));\n }\n return result;\n }\n /**\n * Move accounts whose observed credit spend exceeded this route's threshold behind\n * the ones that still have headroom, within each expiring-credit group.\n *\n * This is a preference, not a filter: the caller keeps every candidate, so a route\n * whose accounts are all over budget still serves requests instead of failing. The\n * baseline is per route and per account, so switching accounts resets a newcomer's\n * counter to zero while the previous account stays demoted for the rest of the round.\n *\n * The demotion is scoped to a group so it cannot outrank expiring credits: an account\n * holding credits that expire sooner stays ahead even after it has spent its allowance.\n *\n * Once every candidate in a group has spent its allowance the round is over and those\n * baselines restart from the current total. Without that reset the counters only ever\n * grow, every account stays demoted forever and the ordering stops changing after one pass.\n *\n * Spend is inferred from platform balance drops, so one request may overshoot and an\n * account without a usable balance reading is never demoted on a guess.\n */\n demoteOverBudget(alias, route, candidates, expiry = () => Infinity) {\n if (!candidates.length) return candidates;\n const threshold = route.creditBalanceThreshold ?? 1000;\n const bases = this.budgets.get(alias) ?? new Map();\n this.budgets.set(alias, bases);\n const live = new Set(candidates.map(c => c.account.id));\n for (const id of bases.keys()) if (!live.has(id)) bases.delete(id);\n const groups = new Map();\n for (const candidate of candidates) {\n const group = expiry(candidate);\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group).push(candidate);\n }\n const result = [];\n for (const group of groups.values()) {\n const fresh = [], spent = [];\n for (const candidate of group) {\n const id = candidate.account.id, row = this.telemetry.row('accounts', id);\n const observed = row.creditsObserved ?? 0;\n if (!bases.has(id)) bases.set(id, observed);\n const used = observed - bases.get(id);\n // A balance rewrite (prepaid top-up, new settlement cycle) must not keep an account\n // demoted on a negative counter.\n if (!Number.isFinite(used) || used < 0) { bases.set(id, observed); fresh.push(candidate); continue; }\n (used >= threshold ? spent : fresh).push(candidate);\n }\n if (!spent.length) { result.push(...fresh); continue; }\n if (spent.length === group.length) {\n // Every account in this group has used its allowance: bank the totals and start a\n // new round for the group.\n for (const candidate of group) bases.set(candidate.account.id, this.telemetry.row('accounts', candidate.account.id).creditsObserved ?? 0);\n result.push(...group);\n continue;\n }\n result.push(...fresh, ...spent);\n }\n return result;\n }\n updateConfig(config) {\n for (const old of this.config.accounts) {\n const next = config.accounts.find(a => a.id === old.id);\n if (!next || next.provider !== old.provider || next.credentialFile !== old.credentialFile || next.identityFile !== old.identityFile) this.clients.delete(old.id);\n }\n this.config = config;\n for (const alias of this.active.keys()) if (!Object.hasOwn(config.routes, alias)) this.active.delete(alias);\n for (const alias of this.budgets.keys()) if (!Object.hasOwn(config.routes, alias)) this.budgets.delete(alias);\n }\n async client(account) {\n if (!this.clients.has(account.id)) this.clients.set(account.id, Promise.resolve().then(() => this.createClient(account)));\n try { return await this.clients.get(account.id); }\n catch (error) { this.clients.delete(account.id); throw error; }\n }\n status() {\n return this.config.accounts.map(a => ({ id: a.id, provider: a.provider, enabled: a.enabled !== false,\n cooldowns: [...this.cooldowns].filter(([key, time]) => key.startsWith(`${a.id}:`) && time > this.now())\n .map(([key, time]) => ({ route: key.slice(a.id.length + 1), remainingMs: time - this.now() })),\n activeFor: [...this.active].filter(([, key]) => key.split(':')[0] === a.id).map(([alias]) => alias) }));\n }\n candidates(alias) {\n const route = this.config.routes[alias];\n if (!Object.hasOwn(this.config.routes, alias)) throw new RouteError(404, 'unknown_model', [], '\u63D2\u4EF6\u8DEF\u7531\u8868\u4E2D\u6CA1\u6709\u8BE5\u8C03\u7528\u540D\u79F0\uFF0C\u8BF7\u5728\u914D\u7F6E\u9875\u65B0\u5EFA\u6216\u6062\u590D\u5BF9\u5E94\u8DEF\u7531');\n const candidates = route.targets.flatMap((target, index) => this.config.accounts\n .filter(a => a.enabled !== false && a.provider === target.provider && (!target.account || a.id === target.account))\n .flatMap(account => route.freeOnly ? (this.freeModels?.(account) ?? []).filter(m => (!target.model || m.id === target.model) && (!target.models || target.models.includes(m.id)))\n .map(model => ({ account, target: { ...target, model: model.id, models: undefined }, key: `${account.id}:${index}:${model.id}` }))\n : [{ account, target, key: `${account.id}:${index}` }]));\n const active = candidates.findIndex(c => c.key === this.active.get(alias));\n return active < 0 ? candidates : [...candidates.slice(active), ...candidates.slice(0, active)];\n }\n expiringAt(account, route) {\n const balance = this.telemetry?.row('accounts', account.id).balance;\n if (!balance || balance.error || balance.unit !== 'credits' || this.now() - balance.fetchedAt > 120000) return Infinity;\n const horizon = this.now() + (route.expiringWithinDays ?? 7) * 86400000;\n return Math.min(Infinity, ...(balance.packages ?? []).filter(p => p.remaining > 0 && !p.unlimited && p.expiresAt > this.now() && p.expiresAt <= horizon).map(p => p.expiresAt));\n }\n async syncExpiring(alias, route, candidates, below = () => true) {\n if (!route.preferExpiringCredits || !this.telemetry) return false;\n const round = this.telemetry.expiring(alias);\n if (round.cooldownUntil > this.now()) return false;\n const before = JSON.stringify(round);\n if (round.cooldownUntil) { round.accounts = []; round.completed = []; round.cooldownUntil = 0; round.number++; }\n for (const id of round.accounts) {\n const matches = candidates.filter(c => c.account.id === id), balance = this.telemetry.row('accounts', id).balance;\n const fresh = balance && !balance.error && balance.unit === 'credits' && this.now() - balance.fetchedAt <= 120000;\n if (!matches.length || matches.every(c => !below(c)) || (fresh && !Number.isFinite(this.expiringAt({ id }, route)))) {\n if (!round.completed.includes(id)) round.completed.push(id);\n }\n }\n for (const c of candidates) if (below(c) && Number.isFinite(this.expiringAt(c.account, route)) && !round.accounts.includes(c.account.id)) round.accounts.push(c.account.id);\n // Cooling applies only to expiring-credit priority; ordinary routing keeps running.\n if (round.accounts.length && round.accounts.every(id => round.completed.includes(id))) round.cooldownUntil = this.now() + 3 * 86400000;\n if (JSON.stringify(round) !== before) await this.telemetry.persist();\n return round.cooldownUntil <= this.now();\n }\n remainingCooldown(candidate, alias, route) {\n const id = candidate.account.id;\n const keys = [`${id}:*`, `${id}:${alias}`];\n if (route.freeOnly) keys.push(`${id}:${alias}:${candidate.target.model}`);\n return Math.max(0, ...keys.map(key => (this.cooldowns.get(key) ?? 0) - this.now()));\n }\n exhaustHint({ alias, route, strategy, candidates, expiryCandidates, attempts }) {\n const kinds = new Set(attempts.map(a => a.kind));\n const modelOnly = attempts.length > 0 && [...kinds].every(k => ['model_unavailable', 'reasoning_effort_unavailable', 'model_no_longer_free', 'context_window_unavailable'].includes(k));\n const cooling = candidates.map(c => this.remainingCooldown(c, alias, route)).filter(ms => ms > 0);\n const soonest = cooling.length ? Math.min(...cooling) : undefined;\n const countdown = soonest === undefined ? undefined : `\u7EA6 ${Math.max(1, Math.ceil(soonest / 1000))} \u79D2\u540E\u53EF\u91CD\u8BD5`;\n if (!expiryCandidates.length) return route.freeOnly\n ? '\u8BE5\u8DEF\u7531\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684\u514D\u8D39\u6A21\u578B\uFF1A\u53EF\u80FD\u5DF2\u6062\u590D\u6536\u8D39\u3001\u9650\u514D\u5230\u671F\u6216\u76EE\u5F55\u83B7\u53D6\u5931\u8D25'\n : '\u8BE5\u8DEF\u7531\u6CA1\u6709\u53EF\u7528\u7684\u8D26\u53F7\u76EE\u6807\uFF1A\u8D26\u53F7\u53EF\u80FD\u5DF2\u5168\u90E8\u7981\u7528\uFF0C\u6216\u4E0E\u76EE\u6807\u6E20\u9053\u4E0D\u5339\u914D';\n if (kinds.has('context_window_unavailable') && modelOnly) return '\u5019\u9009\u6E20\u9053\u4E0D\u652F\u6301\u5F53\u524D\u4E0A\u4E0B\u6587\u9884\u7B97\uFF0C\u8BF7\u5237\u65B0\u76EE\u5F55\u6216\u5728\u6A21\u578B\uFF0F\u8DEF\u7531\u8BBE\u7F6E\u4E2D\u8C03\u4F4E\u9884\u7B97\uFF1B\u4E0D\u4F1A\u622A\u65AD\u4F1A\u8BDD\u6216\u964D\u7EA7\u5230\u5C0F\u5BB9\u91CF\u6E20\u9053';\n if (modelOnly) return `\u5DF2\u5C1D\u8BD5\u7684\u8D26\u53F7\u76EE\u5F55\u4E2D\u90FD\u6CA1\u6709\u8BE5\u6A21\u578B\u3001\u6240\u9009\u63A8\u7406\u6863\u4F4D\u6216\u514D\u8D39\u8D44\u683C\u4E0D\u6EE1\u8DB3${countdown ? `\uFF1B\u5176\u4F59\u8D26\u53F7\u51B7\u5374\u4E2D\uFF0C${countdown}` : ''}`;\n if (soonest !== undefined && cooling.length >= candidates.length) {\n return attempts.length ? `\u6240\u6709\u5019\u9009\u8D26\u53F7\u672C\u6B21\u8C03\u7528\u5747\u5931\u8D25\u5E76\u5DF2\u8FDB\u5165\u51B7\u5374\uFF0C${countdown}` : `\u5168\u90E8\u8D26\u53F7\u90FD\u5728\u5931\u8D25\u51B7\u5374\u4E2D\uFF0C${countdown}`;\n }\n if (soonest !== undefined) return `\u90E8\u5206\u8D26\u53F7\u4ECD\u5728\u5931\u8D25\u51B7\u5374\u4E2D\uFF0C${countdown}`;\n if (!attempts.length && ['tokens', 'credits'].includes(strategy)) return `\u6240\u6709\u8D26\u53F7\u7684\u672C\u8F6E${strategy === 'tokens' ? ' Token' : '\u79EF\u5206'}\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u6216\u56E0\u7F3A\u5C11\u7528\u91CF\u8BA1\u91CF\u800C\u6682\u505C\u53C2\u4E0E\u8F6E\u6362`;\n return undefined;\n }\n async chat(input, signal, metadata = {}) {\n const alias = input.model;\n if (!Array.isArray(input.messages) || !input.messages.length || input.stream !== true) throw new RouteError(400, 'messages_and_stream_true_required');\n const initialRoute = this.config.routes[alias];\n if (initialRoute?.freeOnly) {\n await abortable(this.prepareFree?.(), signal);\n if (!this.config.routes[alias]) throw new RouteError(503, 'free_model_pool_unavailable', [], '\u672C\u8DEF\u7531\u4ECA\u5929\u6CA1\u6709\u53EF\u7528\u7684\u514D\u8D39\u6A21\u578B');\n }\n const effort = Object.hasOwn(input, 'reasoning_effort') ? input.reasoning_effort : this.config.routes[alias]?.reasoningEffort;\n input = { ...input }; delete input.reasoning_effort;\n if (effort !== undefined && effort !== null) input.reasoning_effort = effort;\n let candidates = this.candidates(alias);\n const expiryCandidates = [...candidates];\n const route = this.config.routes[alias], strategy = route.strategy ?? 'failover';\n const available = c => (this.cooldowns.get(`${c.account.id}:*`) ?? 0) <= this.now() && (this.cooldowns.get(`${c.account.id}:${alias}`) ?? 0) <= this.now()\n && (!route.freeOnly || (this.cooldowns.get(`${c.account.id}:${alias}:${c.target.model}`) ?? 0) <= this.now());\n if (route.preferExpiringCredits && this.monitor) {\n await Promise.all([...new Map(candidates.filter(available).map(c => [c.account.id, c.account])).values()].map(a => {\n const snapshot = this.telemetry?.row('accounts', a.id).balance;\n return !snapshot || snapshot.error || this.now() - snapshot.fetchedAt > 60000 ? this.monitor(a) : undefined;\n }));\n signal?.throwIfAborted();\n }\n if (strategy === 'credits') {\n await Promise.all([...new Map(candidates.filter(available).map(c => [c.account.id, c.account])).values()].map(a => this.monitor?.(a)));\n signal?.throwIfAborted();\n candidates = candidates.filter(c => { const balance = this.telemetry?.row('accounts', c.account.id).balance; return balance?.unit === 'credits' && Number.isFinite(balance.remaining) && this.now() - balance.fetchedAt < 120000 && !balance.error; });\n if (!candidates.length) throw new RouteError(503, 'credit_usage_unavailable', [], '\u65E0\u6CD5\u83B7\u53D6\u4EFB\u4F55\u5019\u9009\u8D26\u53F7\u7684\u79EF\u5206\u4F59\u989D\u6570\u636E');\n }\n const signature = JSON.stringify({ strategy, targets: route.targets });\n let below = () => true, preferActive;\n if (this.telemetry && ['tokens', 'credits'].includes(strategy)) {\n const round = this.telemetry.round(alias, signature);\n const counters = c => ({ tokens: this.telemetry.count(alias, c.account.id).tokens, credits: this.telemetry.row('accounts', c.account.id).creditsObserved ?? 0 });\n for (const c of candidates) if (!Object.hasOwn(round.bases, c.account.id)) Object.defineProperty(round.bases, c.account.id, { value: counters(c), enumerable: true, writable: true, configurable: true });\n below = c => !round.bases[c.account.id] || counters(c)[strategy] - round.bases[c.account.id][strategy] < (strategy === 'tokens' ? c.target.tokenBudget : c.target.creditBudget);\n preferActive = await this.syncExpiring(alias, route, expiryCandidates, below);\n // Start another round only when every configured, metered candidate has used its budget.\n if (candidates.length && candidates.every(c => !below(c))) {\n await this.telemetry.advance(alias, candidates, signature);\n this.active.delete(alias);\n const allowed = new Set(candidates.map(c => c.key));\n candidates = this.candidates(alias).filter(c => allowed.has(c.key));\n }\n candidates = candidates.filter(below);\n if (strategy === 'tokens' && candidates.some(c => this.telemetry.count(alias, c.account.id).unmetered > 0)) {\n // A missing upstream usage marker cannot silently count as zero forever.\n candidates = candidates.filter(c => this.telemetry.count(alias, c.account.id).unmetered === 0);\n }\n }\n preferActive ??= await this.syncExpiring(alias, route, expiryCandidates, below);\n const expiry = c => preferActive && !this.telemetry.expiring(alias).completed.includes(c.account.id) ? this.expiringAt(c.account, route) : Infinity;\n // Expiring credits are the first priority and stay there: the rate and allowance rules\n // below only reorder candidates inside the group they are already in. Comparing dates\n // keeps two non-expiring accounts equal, which subtracting two Infinity values would not.\n if (preferActive) {\n const ordered = candidates.map((candidate, index) => ({ candidate, index }));\n ordered.sort((a, b) => expiry(a.candidate) - expiry(b.candidate) || a.index - b.index);\n candidates = ordered.map(entry => entry.candidate);\n }\n // Cheapest known rate first, never across the expiring-credit boundary: a cheaper\n // account without expiring credits must not displace one that has them.\n if (route.discountOrder && !route.freeOnly) candidates = this.sortWithinGroups(candidates, expiry, candidate => {\n const rate = route.creditRates?.[candidate.account.id];\n return rate === undefined ? undefined : rate;\n });\n if (route.balanceCredits && !route.freeOnly && this.telemetry) candidates = this.demoteOverBudget(alias, route, candidates, expiry);\n if (strategy === 'weighted') {\n let eligible = candidates.filter(available);\n const nearest = Math.min(Infinity, ...eligible.map(expiry));\n if (Number.isFinite(nearest)) eligible = eligible.filter(c => expiry(c) === nearest);\n if (eligible.length) {\n let scores = this.scores.get(alias);\n if (scores?.signature !== signature) { scores = { signature, values: new Map() }; this.scores.set(alias, scores); }\n let total = 0, winner;\n for (const c of eligible) { const weight = c.target.weight ?? 1; total += weight; scores.values.set(c.key, (scores.values.get(c.key) ?? 0) + weight); if (!winner || scores.values.get(c.key) > scores.values.get(winner.key)) winner = c; }\n scores.values.set(winner.key, scores.values.get(winner.key) - total);\n candidates = [winner, ...candidates.filter(c => c !== winner)];\n }\n }\n const attempts = [];\n // Each account/model target is attempted once, even when configuration repeats it.\n const tried = new Set();\n for (const candidate of candidates) {\n signal?.throwIfAborted();\n const { account, target, key } = candidate;\n if (!available(candidate)) continue;\n let result, actualModel, startedAt;\n try {\n const client = await abortable(this.client(account), signal);\n const catalog = await abortable(client.models(signal), signal);\n const suitable = route.enforceContext ? catalog.filter(m => contextInfo(m).maxContextWindow >= route.contextWindow) : catalog;\n const model = matchModel(alias, target, suitable, effort ?? undefined);\n if (!model) { attempts.push({ account: account.id, provider: account.provider, status: 404,\n kind: matchModel(alias, target, catalog, effort ?? undefined) ? 'context_window_unavailable'\n : matchModel(alias, target, catalog) ? 'reasoning_effort_unavailable' : 'model_unavailable' }); continue; }\n if (route.freeOnly && !isFreeModel(model, this.now())) { attempts.push({ account: account.id, provider: account.provider, status: 404, kind: 'model_no_longer_free' }); continue; }\n actualModel = model.id;\n const dedupe = `${account.id}:${model.id}`;\n if (tried.has(dedupe)) continue;\n tried.add(dedupe);\n startedAt = performance.now();\n result = await abortable(client.chat({ ...input, model: model.id }, signal, { contextWindow: route.contextWindow }), signal);\n signal?.throwIfAborted();\n if (result.ok) {\n this.active.set(alias, key);\n this.onAttempt({ account: account.id, provider: account.provider, alias, model: model.id, status: 200 });\n const response = this.telemetry ? meterResponse(result.response, async summary => {\n await this.telemetry.record({ ...summary, ...metadata, account: account.id, provider: account.provider, alias, model: model.id, accepted: true, status: summary.ok ? 200 : summary.cancelled ? 499 : 502 });\n await this.syncExpiring(alias, route, expiryCandidates, below);\n if (strategy === 'credits' || route.preferExpiringCredits) void this.monitor?.(account).then(() => this.syncExpiring(alias, route, expiryCandidates, below)).catch(() => {});\n }, signal, { startedAt }) : result.response;\n return { response, account: account.id, provider: account.provider };\n }\n } catch (error) {\n signal?.throwIfAborted();\n const reported = error.status ?? error.failure?.status ?? /\\bhttp\\s+(\\d{3})\\b/i.exec(error.message ?? '')?.[1];\n result = { ok: false, status: Number(reported) || 502, kind: error.code ?? error.failure?.code ?? 'transport' };\n }\n const status = result.status >= 400 && result.status <= 599 ? result.status : 502;\n const attempt = { account: account.id, provider: account.provider, status, kind: result.kind };\n attempts.push(attempt);\n await this.telemetry?.record({ ...attempt, ...metadata, alias, model: actualModel, ok: false, timing: startedAt === undefined ? null : { modelMs: Math.max(0, performance.now() - startedAt) } });\n // Upstream messages can contain credentials or request text: log metadata only.\n this.onAttempt({ ...attempt, alias });\n const retryable = status < 500 || this.config.retryServerErrors;\n if (!retryable) throw new RouteError(status, 'upstream_failed', attempts, '\u4E0A\u6E38\u8FD4\u56DE 5xx \u4E14\u672A\u5F00\u542F\u300C5xx \u548C\u7F51\u7EDC\u9519\u8BEF\u4E5F\u5207\u6362\u8D26\u53F7\u300D\uFF0C\u672C\u6B21\u8BF7\u6C42\u5DF2\u505C\u6B62');\n const scope = [401, 402, 429].includes(status) ? '*' : route.freeOnly && actualModel ? `${alias}:${actualModel}` : alias;\n this.cooldowns.set(`${account.id}:${scope}`, this.now() + this.config.cooldownMs);\n }\n const hint = this.exhaustHint({ alias, route, strategy, candidates, expiryCandidates, attempts });\n throw new RouteError(503, route.freeOnly ? 'free_model_pool_unavailable' : 'account_pool_exhausted', attempts, hint);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["input", "output"]
7
+ }
package/lib/cli.js CHANGED
@@ -1,23 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createAccountClient
4
- } from "./chunk-TKVFF7LN.js";
4
+ } from "./chunk-LXDLKLM6.js";
5
5
  import {
6
6
  importAccount
7
- } from "./chunk-YZIARLWT.js";
7
+ } from "./chunk-2UM45OXY.js";
8
8
  import "./chunk-FLL3DUVP.js";
9
9
  import "./chunk-KWXLQJS5.js";
10
10
  import "./chunk-S5KMFAQM.js";
11
11
  import "./chunk-4V52V5GO.js";
12
12
  import {
13
13
  Router
14
- } from "./chunk-Q6A57FN3.js";
14
+ } from "./chunk-R2Z4WGR6.js";
15
15
  import {
16
16
  DEFAULT_ROUTES,
17
17
  PROVIDERS,
18
18
  validateConfig,
19
19
  writePrivateJson
20
- } from "./chunk-XD52ZGZ5.js";
20
+ } from "./chunk-GEBZMIMA.js";
21
21
 
22
22
  // src/cli.mjs
23
23
  import { parseArgs } from "node:util";
package/lib/client.js CHANGED
@@ -50,7 +50,7 @@ module.exports = __toCommonJS(client_exports);
50
50
  var import_react = require("react");
51
51
 
52
52
  // package.json
53
- var version = "0.6.8";
53
+ var version = "0.6.10";
54
54
 
55
55
  // src/client.jsx
56
56
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -1005,7 +1005,7 @@ function RoutesTable({ data, busy, act, edit }) {
1005
1005
  ] }),
1006
1006
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
1007
1007
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", "aria-label": `\u5C55\u793A\u8DEF\u7531 ${r.name}`, disabled: busy, checked: r.visible !== false, onChange: (e) => {
1008
- const { id, reasoning, supportsImages, expiringStatus, freeStatus, maxContextWindow, supportedContextWindows, configuredContextWindow, contextKnown, eligibleAccountIds, enforceContext, ...route } = r;
1008
+ const { id, reasoning, supportsImages, expiringStatus, freeStatus, creditRates, maxContextWindow, supportedContextWindows, configuredContextWindow, contextKnown, eligibleAccountIds, enforceContext, ...route } = r;
1009
1009
  void act({ action: "route.save", id, previousId: id, route: { ...route, visible: e.target.checked } });
1010
1010
  } }),
1011
1011
  r.visible !== false ? "\u5F00\u542F" : "\u5173\u95ED"
@@ -2297,7 +2297,7 @@ function FreeStatus({ route, busy, act, onUpdate }) {
2297
2297
  function FreeRouteForm({ draft, setDraft, data, act, busy, error, notice }) {
2298
2298
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: async (e) => {
2299
2299
  e.preventDefault();
2300
- const { id, previousId, revision, reasoning, supportsImages, expiringStatus, freeStatus, maxContextWindow, supportedContextWindows, configuredContextWindow, contextKnown, eligibleAccountIds, enforceContext, ...route } = draft;
2300
+ const { id, previousId, revision, reasoning, supportsImages, expiringStatus, freeStatus, creditRates, maxContextWindow, supportedContextWindows, configuredContextWindow, contextKnown, eligibleAccountIds, enforceContext, ...route } = draft;
2301
2301
  route.targets = route.targets.map((t) => ({ provider: t.provider, ...t.account ? { account: t.account } : {}, ...t.model ? { model: t.model } : {}, ...t.models ? { models: t.models } : {} }));
2302
2302
  if (await act({ action: "route.save", id, previousId, revision, route })) setDraft(null);
2303
2303
  }, children: [
@@ -2463,6 +2463,13 @@ function RouteForm({ draft, setDraft, data, act, busy, error, notice }) {
2463
2463
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "number", disabled: busy, min: "1", step: "1", required: true, value: draft.creditBalanceThreshold ?? 1e3, onChange: (e) => set("creditBalanceThreshold", Number(e.target.value)) })
2464
2464
  ] })
2465
2465
  ] }),
2466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "box stack", children: [
2467
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
2468
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", disabled: busy, checked: draft.discountOrder !== false, onChange: (e) => set("discountOrder", e.target.checked) }),
2469
+ "\u6309\u79EF\u5206\u6298\u6263\u6392\u5E8F\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF09"
2470
+ ] }),
2471
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u6BCF\u6B21\u8BF7\u6C42\u6309\u5404\u6E20\u9053\u5F53\u524D\u516C\u5E03\u7684\u79EF\u5206\u500D\u7387\u4ECE\u5C0F\u5230\u5927\u6392\u5217\u5019\u9009\u8D26\u53F7\uFF0C\u500D\u7387\u8D8A\u4F4E\u8D8A\u4FBF\u5B9C\u3001\u8D8A\u5148\u7528\u3002\u500D\u7387\u6765\u81EA\u6A21\u578B\u76EE\u5F55\u5E76\u968F\u76EE\u5F55\u5237\u65B0\uFF0C\u9650\u65F6\u4FC3\u9500\u5230\u671F\u540E\u81EA\u52A8\u6062\u590D\u3002\u4E34\u671F\u79EF\u5206\u4E0E\u79EF\u5206\u5747\u8861\u989D\u5EA6\u4ECD\u7136\u4F18\u5148\uFF0C\u6298\u6263\u53EA\u5728\u540C\u7C7B\u5019\u9009\u4E4B\u95F4\u51B3\u5B9A\u5148\u540E\uFF1B\u6CA1\u6709\u516C\u5E03\u500D\u7387\u7684\u8D26\u53F7\u6392\u5728\u6700\u540E\u3002" })
2472
+ ] }),
2466
2473
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
2467
2474
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u6A21\u578B\u4E0E\u8D26\u53F7\u76EE\u6807" }),
2468
2475
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "notice", children: "\u6309\u4E0B\u65B9\u987A\u5E8F\u5207\u6362" })