v0.2.3 Core tier 10/5/5 split + dynamic health version

This commit is contained in:
local
2026-05-11 21:53:50 -05:00
parent 07fe14010c
commit 6797aae404
8 changed files with 138 additions and 15 deletions
+18 -3
View File
@@ -14,7 +14,20 @@ const inputSpec = InputSpec.of({
core_lifetime: Value.number({
name: 'Core — Lifetime Credits',
description:
'Total credits a Core (unlicensed) install can ever spend. Default 5.',
'Total credits a Core (unlicensed) install can ever spend across its lifetime. Default 10 (5 served via Gemini + 5 via operator hardware).',
required: true,
default: 10,
min: 0,
max: 1_000_000,
integer: true,
step: 1,
units: 'credits',
placeholder: null,
}),
core_gemini_cap: Value.number({
name: 'Core — Gemini Cap (lifetime)',
description:
'Within the Core lifetime allowance, how many credits may be served via Gemini (the rest spill to the operator-hardware fallback). Default 5.',
required: true,
default: 5,
min: 0,
@@ -91,7 +104,8 @@ export const adjustTierQuotas = sdk.Action.withInput(
parsed = {}
}
return {
core_lifetime: parsed?.core?.lifetime ?? 5,
core_lifetime: parsed?.core?.lifetime ?? 10,
core_gemini_cap: parsed?.core?.geminiCapLifetime ?? 5,
pro_monthly: parsed?.pro?.monthly ?? 50,
pro_gemini_cap: parsed?.pro?.geminiCapMonthly ?? 25,
max_gemini_cap: parsed?.max?.geminiCapMonthly ?? 50,
@@ -101,7 +115,8 @@ export const adjustTierQuotas = sdk.Action.withInput(
async ({ effects, input }) => {
const quotas = {
core: {
lifetime: input.core_lifetime ?? 5,
lifetime: input.core_lifetime ?? 10,
geminiCapLifetime: input.core_gemini_cap ?? 5,
monthly: null,
geminiCapMonthly: null,
},
+10 -1
View File
@@ -62,7 +62,16 @@ export const configFile = FileHelper.json(
// "Adjust Tier Quotas" action without a code change or restart.
relay_tier_quotas_json: z.string().default(
JSON.stringify({
core: { lifetime: 5, monthly: null, geminiCapMonthly: null },
// Core: 10 lifetime credits total — first 5 served via Gemini
// (operator's cloud spend), final 5 fall through to operator
// hardware so the user can keep going on free tier without
// costing the operator more cloud $.
core: {
lifetime: 10,
geminiCapLifetime: 5,
monthly: null,
geminiCapMonthly: null,
},
pro: { lifetime: null, monthly: 50, geminiCapMonthly: 25 },
max: { lifetime: null, monthly: null, geminiCapMonthly: 50 },
}),
+3 -2
View File
@@ -3,8 +3,9 @@ import { v_0_1_0 } from './v0.1.0'
import { v_0_2_0 } from './v0.2.0'
import { v_0_2_1 } from './v0.2.1'
import { v_0_2_2 } from './v0.2.2'
import { v_0_2_3 } from './v0.2.3'
export const versionGraph = VersionGraph.of({
current: v_0_2_2,
other: [v_0_2_1, v_0_2_0, v_0_1_0],
current: v_0_2_3,
other: [v_0_2_2, v_0_2_1, v_0_2_0, v_0_1_0],
})
+43
View File
@@ -0,0 +1,43 @@
import { VersionInfo } from '@start9labs/start-sdk'
import { configFile } from '../file-models/config.json'
export const v_0_2_3 = VersionInfo.of({
version: '0.2.3:0',
releaseNotes: {
en_US:
'Core tier reworked: 10 lifetime credits (was 5), with the first 5 served via Gemini and the next 5 via operator hardware. /relay/health now reports the actual package version. Existing installs migrate their saved tier-quota blob automatically on upgrade.',
},
migrations: {
// Update the saved tier-quota JSON for installs that came up under
// v0.2.0v0.2.2 (Core: 5 lifetime, all Gemini). Idempotent — if
// the operator has already moved away from the old defaults via
// Adjust Tier Quotas, we leave their values alone.
up: async ({ effects }) => {
const current = await configFile.read().once()
if (!current?.relay_tier_quotas_json) return
let parsed: any = {}
try {
parsed = JSON.parse(current.relay_tier_quotas_json)
} catch {
return
}
// Migrate only the legacy default shape — operator-edited blobs
// are left alone. The legacy shape was exactly: core.lifetime=5
// AND no geminiCapLifetime field present.
const isLegacyCore =
parsed?.core?.lifetime === 5 &&
parsed?.core?.geminiCapLifetime === undefined
if (!isLegacyCore) return
parsed.core = {
lifetime: 10,
geminiCapLifetime: 5,
monthly: null,
geminiCapMonthly: null,
}
await configFile.merge(effects, {
relay_tier_quotas_json: JSON.stringify(parsed),
})
},
down: async ({ effects }) => {},
},
})