hosted-consolidation-advanced.mjs
sha256:8d46372e39d2d5a54fd93a8b1c27922fe0d9b22a72197345f1d2c71701cc4ce2
feat(auth): persistent login system + C7 session introspection
Human
minor
⚠ breaking
16 days ago
| 1 | /** |
| 2 | * Hosted consolidation "advanced" knobs — same ranges as self-hosted Hub POST |
| 3 | * (hub/server.mjs /api/v1/settings/consolidation). Used by gateway, bridge, and scheduler. |
| 4 | */ |
| 5 | |
| 6 | export const HOSTED_CONSOL_LOOKBACK_MIN = 1; |
| 7 | export const HOSTED_CONSOL_LOOKBACK_MAX = 8760; |
| 8 | export const HOSTED_CONSOL_MAX_EVENTS_MIN = 1; |
| 9 | export const HOSTED_CONSOL_MAX_EVENTS_MAX = 10000; |
| 10 | export const HOSTED_CONSOL_MAX_TOPICS_MIN = 1; |
| 11 | export const HOSTED_CONSOL_MAX_TOPICS_MAX = 500; |
| 12 | export const HOSTED_CONSOL_LLM_TOKENS_MIN = 64; |
| 13 | export const HOSTED_CONSOL_LLM_TOKENS_MAX = 8192; |
| 14 | |
| 15 | export const HOSTED_CONSOL_DEFAULT_LOOKBACK_HOURS = 24; |
| 16 | export const HOSTED_CONSOL_DEFAULT_MAX_EVENTS = 200; |
| 17 | export const HOSTED_CONSOL_DEFAULT_MAX_TOPICS = 10; |
| 18 | export const HOSTED_CONSOL_DEFAULT_LLM_MAX_TOKENS = 1024; |
| 19 | |
| 20 | /** |
| 21 | * Clamp integer n to [lo, hi]; invalid → fallback. |
| 22 | * @param {unknown} n |
| 23 | * @param {number} lo |
| 24 | * @param {number} hi |
| 25 | * @param {number} fallback |
| 26 | */ |
| 27 | export function clampConsolidationInt(n, lo, hi, fallback) { |
| 28 | const x = Math.floor(Number(n)); |
| 29 | if (!Number.isFinite(x)) return fallback; |
| 30 | return Math.min(hi, Math.max(lo, x)); |
| 31 | } |
| 32 | |
| 33 | /** |
| 34 | * Read advanced defaults from a normalized billing user record. |
| 35 | * @param {object|null|undefined} u |
| 36 | * @returns {{ lookback_hours: number, max_events_per_pass: number, max_topics_per_pass: number, llm_max_tokens: number }} |
| 37 | */ |
| 38 | export function hostedAdvancedFromBillingUser(u) { |
| 39 | if (!u || typeof u !== 'object') { |
| 40 | return { |
| 41 | lookback_hours: HOSTED_CONSOL_DEFAULT_LOOKBACK_HOURS, |
| 42 | max_events_per_pass: HOSTED_CONSOL_DEFAULT_MAX_EVENTS, |
| 43 | max_topics_per_pass: HOSTED_CONSOL_DEFAULT_MAX_TOPICS, |
| 44 | llm_max_tokens: HOSTED_CONSOL_DEFAULT_LLM_MAX_TOKENS, |
| 45 | }; |
| 46 | } |
| 47 | return { |
| 48 | lookback_hours: clampConsolidationInt( |
| 49 | u.consolidation_lookback_hours, |
| 50 | HOSTED_CONSOL_LOOKBACK_MIN, |
| 51 | HOSTED_CONSOL_LOOKBACK_MAX, |
| 52 | HOSTED_CONSOL_DEFAULT_LOOKBACK_HOURS, |
| 53 | ), |
| 54 | max_events_per_pass: clampConsolidationInt( |
| 55 | u.consolidation_max_events_per_pass, |
| 56 | HOSTED_CONSOL_MAX_EVENTS_MIN, |
| 57 | HOSTED_CONSOL_MAX_EVENTS_MAX, |
| 58 | HOSTED_CONSOL_DEFAULT_MAX_EVENTS, |
| 59 | ), |
| 60 | max_topics_per_pass: clampConsolidationInt( |
| 61 | u.consolidation_max_topics_per_pass, |
| 62 | HOSTED_CONSOL_MAX_TOPICS_MIN, |
| 63 | HOSTED_CONSOL_MAX_TOPICS_MAX, |
| 64 | HOSTED_CONSOL_DEFAULT_MAX_TOPICS, |
| 65 | ), |
| 66 | llm_max_tokens: clampConsolidationInt( |
| 67 | u.consolidation_llm_max_tokens, |
| 68 | HOSTED_CONSOL_LLM_TOKENS_MIN, |
| 69 | HOSTED_CONSOL_LLM_TOKENS_MAX, |
| 70 | HOSTED_CONSOL_DEFAULT_LLM_MAX_TOKENS, |
| 71 | ), |
| 72 | }; |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Merge JSON body for POST /memory/consolidate: explicit body fields win; missing keys use billing user. |
| 77 | * @param {object} body - request body (may be partial) |
| 78 | * @param {object} billingUser - normalizeBillingUser() output |
| 79 | * @returns {object} shallow copy with lookback_hours, max_events_per_pass, max_topics_per_pass, llm.max_tokens filled |
| 80 | */ |
| 81 | export function mergeConsolidateRequestBodyWithBillingDefaults(body, billingUser) { |
| 82 | const src = body && typeof body === 'object' ? body : {}; |
| 83 | const out = { ...src }; |
| 84 | const d = hostedAdvancedFromBillingUser(billingUser); |
| 85 | |
| 86 | if (out.lookback_hours == null) out.lookback_hours = d.lookback_hours; |
| 87 | if (out.max_events_per_pass == null) out.max_events_per_pass = d.max_events_per_pass; |
| 88 | if (out.max_topics_per_pass == null) out.max_topics_per_pass = d.max_topics_per_pass; |
| 89 | |
| 90 | const prevLlm = out.llm && typeof out.llm === 'object' ? out.llm : {}; |
| 91 | if (prevLlm.max_tokens == null) { |
| 92 | out.llm = { ...prevLlm, max_tokens: d.llm_max_tokens }; |
| 93 | } else { |
| 94 | out.llm = { ...prevLlm }; |
| 95 | } |
| 96 | |
| 97 | return out; |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * Validate optional advanced fields on POST /api/v1/settings/consolidation (hosted gateway). |
| 102 | * Only checks keys that are present on body. |
| 103 | * @param {object} body |
| 104 | * @returns {{ ok: true } | { ok: false, error: string, code: string }} |
| 105 | */ |
| 106 | export function validateHostedSettingsConsolidationAdvanced(body) { |
| 107 | if (!body || typeof body !== 'object') return { ok: true }; |
| 108 | if (body.lookback_hours !== undefined) { |
| 109 | const lb = Math.floor(Number(body.lookback_hours)); |
| 110 | if (!Number.isFinite(lb) || lb < HOSTED_CONSOL_LOOKBACK_MIN || lb > HOSTED_CONSOL_LOOKBACK_MAX) { |
| 111 | return { ok: false, error: 'lookback_hours must be 1–8760', code: 'VALIDATION_ERROR' }; |
| 112 | } |
| 113 | } |
| 114 | if (body.max_events_per_pass !== undefined) { |
| 115 | const me = Math.floor(Number(body.max_events_per_pass)); |
| 116 | if (!Number.isFinite(me) || me < HOSTED_CONSOL_MAX_EVENTS_MIN || me > HOSTED_CONSOL_MAX_EVENTS_MAX) { |
| 117 | return { ok: false, error: 'max_events_per_pass must be 1–10000', code: 'VALIDATION_ERROR' }; |
| 118 | } |
| 119 | } |
| 120 | if (body.max_topics_per_pass !== undefined) { |
| 121 | const mt = Math.floor(Number(body.max_topics_per_pass)); |
| 122 | if (!Number.isFinite(mt) || mt < HOSTED_CONSOL_MAX_TOPICS_MIN || mt > HOSTED_CONSOL_MAX_TOPICS_MAX) { |
| 123 | return { ok: false, error: 'max_topics_per_pass must be 1–500', code: 'VALIDATION_ERROR' }; |
| 124 | } |
| 125 | } |
| 126 | if (body.llm !== undefined && typeof body.llm === 'object' && body.llm.max_tokens !== undefined) { |
| 127 | const mxt = Math.floor(Number(body.llm.max_tokens)); |
| 128 | if (!Number.isFinite(mxt) || mxt < HOSTED_CONSOL_LLM_TOKENS_MIN || mxt > HOSTED_CONSOL_LLM_TOKENS_MAX) { |
| 129 | return { ok: false, error: 'llm.max_tokens must be 64–8192', code: 'VALIDATION_ERROR' }; |
| 130 | } |
| 131 | } |
| 132 | return { ok: true }; |
| 133 | } |
File History
2 commits
sha256:8d46372e39d2d5a54fd93a8b1c27922fe0d9b22a72197345f1d2c71701cc4ce2
feat(auth): persistent login system + C7 session introspection
Human
minor
⚠
16 days ago
sha256:6a102aafafdfe7e70a24f4e59740200f0ee713ce7915f1b53e9d4ba5ee8b4410
Initial Muse snapshot
Human
48 days ago