make profile startup state-driven
This commit is contained in:
@@ -162,6 +162,12 @@ profile env 默认放在:
|
|||||||
node ./scripts/run-profile.mjs default
|
node ./scripts/run-profile.mjs default
|
||||||
```
|
```
|
||||||
|
|
||||||
|
如果已经由 state 记录了当前活跃 profile,也可以直接不传 profile 参数:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node ./scripts/run-profile.mjs --prefer-state-profile
|
||||||
|
```
|
||||||
|
|
||||||
## 如何恢复
|
## 如何恢复
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
|
|||||||
+10
-2
@@ -55,7 +55,15 @@ function parseEnvFile(content) {
|
|||||||
|
|
||||||
function getProfileName(options) {
|
function getProfileName(options) {
|
||||||
const positional = options._?.[0];
|
const positional = options._?.[0];
|
||||||
return `${options.profile || positional || process.env.CODEX_RETRY_GATEWAY_PROFILE || "default"}`;
|
return `${options.profile || positional || process.env.CODEX_RETRY_GATEWAY_PROFILE || ""}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveDefaultRequestedProfileName(existingState) {
|
||||||
|
const stateProfileName = `${existingState?.profile_name || ""}`.trim();
|
||||||
|
if (stateProfileName) {
|
||||||
|
return stateProfileName;
|
||||||
|
}
|
||||||
|
return process.env.CODEX_RETRY_GATEWAY_DEFAULT_PROFILE || "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePreferredProfileName({ requestedProfileName, existingState, preferStateProfile, profilesDir }) {
|
function resolvePreferredProfileName({ requestedProfileName, existingState, preferStateProfile, profilesDir }) {
|
||||||
@@ -246,7 +254,6 @@ async function ensureCodexPointsToGateway({ paths, codexConfigPath, providerCont
|
|||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const options = parseOptions(process.argv, { booleanFlags: ["no-codex-config-update", "prefer-state-profile"] });
|
const options = parseOptions(process.argv, { booleanFlags: ["no-codex-config-update", "prefer-state-profile"] });
|
||||||
const requestedProfileName = getProfileName(options);
|
|
||||||
const profilesDir = options.profilesDir || DEFAULT_PROFILES_DIR;
|
const profilesDir = options.profilesDir || DEFAULT_PROFILES_DIR;
|
||||||
const stateRoot = options.stateRoot || process.env.CODEX_RETRY_GATEWAY_STATE_ROOT || DEFAULT_STATE_ROOT;
|
const stateRoot = options.stateRoot || process.env.CODEX_RETRY_GATEWAY_STATE_ROOT || DEFAULT_STATE_ROOT;
|
||||||
const codexConfigPath =
|
const codexConfigPath =
|
||||||
@@ -261,6 +268,7 @@ async function main() {
|
|||||||
await ensureDirectory(paths.backupDir);
|
await ensureDirectory(paths.backupDir);
|
||||||
|
|
||||||
const existingState = await readJsonFile(paths.statePath);
|
const existingState = await readJsonFile(paths.statePath);
|
||||||
|
const requestedProfileName = getProfileName(options) || resolveDefaultRequestedProfileName(existingState);
|
||||||
const profileName = resolvePreferredProfileName({
|
const profileName = resolvePreferredProfileName({
|
||||||
requestedProfileName,
|
requestedProfileName,
|
||||||
existingState,
|
existingState,
|
||||||
|
|||||||
+24
-1
@@ -310,6 +310,17 @@ function durationSeconds(value?: number | null) {
|
|||||||
return typeof value === "number" && Number.isFinite(value) ? `${(value / 1000).toFixed(2)} s` : "-";
|
return typeof value === "number" && Number.isFinite(value) ? `${(value / 1000).toFixed(2)} s` : "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function secondsSince(value: string | null | undefined, nowMs: number) {
|
||||||
|
if (!value) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
const atMs = new Date(value).getTime();
|
||||||
|
if (Number.isNaN(atMs)) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
return `${Math.max(0, (nowMs - atMs) / 1000).toFixed(1)} s`;
|
||||||
|
}
|
||||||
|
|
||||||
function bytesFormat(value?: number | null) {
|
function bytesFormat(value?: number | null) {
|
||||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||||
return "-";
|
return "-";
|
||||||
@@ -478,6 +489,7 @@ export default function App() {
|
|||||||
const [latestLogSeq, setLatestLogSeq] = useState(0);
|
const [latestLogSeq, setLatestLogSeq] = useState(0);
|
||||||
const [requestQuery, setRequestQuery] = useState("");
|
const [requestQuery, setRequestQuery] = useState("");
|
||||||
const [requestFilter, setRequestFilter] = useState("all");
|
const [requestFilter, setRequestFilter] = useState("all");
|
||||||
|
const [nowMs, setNowMs] = useState(() => Date.now());
|
||||||
const [ruleForm, setRuleForm] = useState<RuleFormState>(ruleFormFromStatus(null));
|
const [ruleForm, setRuleForm] = useState<RuleFormState>(ruleFormFromStatus(null));
|
||||||
const [profileForm, setProfileForm] = useState<ProfileFormState>(defaultProfileForm);
|
const [profileForm, setProfileForm] = useState<ProfileFormState>(defaultProfileForm);
|
||||||
const [ruleMessage, setRuleMessage] = useState<MessageState>({ text: "", tone: "" });
|
const [ruleMessage, setRuleMessage] = useState<MessageState>({ text: "", tone: "" });
|
||||||
@@ -668,6 +680,7 @@ export default function App() {
|
|||||||
if (page !== "requests") {
|
if (page !== "requests") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setNowMs(Date.now());
|
||||||
const timer = window.setTimeout(() => {
|
const timer = window.setTimeout(() => {
|
||||||
loadRequests().catch((error) => {
|
loadRequests().catch((error) => {
|
||||||
setRuleMessage({ text: error?.message || String(error), tone: "error" });
|
setRuleMessage({ text: error?.message || String(error), tone: "error" });
|
||||||
@@ -676,6 +689,16 @@ export default function App() {
|
|||||||
return () => window.clearTimeout(timer);
|
return () => window.clearTimeout(timer);
|
||||||
}, [page, requestQuery, requestFilter]);
|
}, [page, requestQuery, requestFilter]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (page !== "requests") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const timer = window.setInterval(() => {
|
||||||
|
setNowMs(Date.now());
|
||||||
|
}, 1000);
|
||||||
|
return () => window.clearInterval(timer);
|
||||||
|
}, [page]);
|
||||||
|
|
||||||
async function saveProfile(event: FormEvent) {
|
async function saveProfile(event: FormEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setProfileMessage({ text: "正在保存 profile...", tone: "" });
|
setProfileMessage({ text: "正在保存 profile...", tone: "" });
|
||||||
@@ -1019,7 +1042,7 @@ export default function App() {
|
|||||||
<span className="meta-pill meta-stream">
|
<span className="meta-pill meta-stream">
|
||||||
<span className="meta-key">流</span>
|
<span className="meta-key">流</span>
|
||||||
{entry.response_stream
|
{entry.response_stream
|
||||||
? `${numberFormat(entry.stream_chunk_count)} chunk / ${bytesFormat(entry.response_bytes_received)}`
|
? `${numberFormat(entry.stream_chunk_count)} chunk / ${bytesFormat(entry.response_bytes_received)} / ${secondsSince(entry.last_activity_at || entry.usage_last_updated_at, nowMs)}`
|
||||||
: "-"}
|
: "-"}
|
||||||
</span>
|
</span>
|
||||||
<span className="meta-pill meta-received">
|
<span className="meta-pill meta-received">
|
||||||
|
|||||||
Reference in New Issue
Block a user