@mostok/codexes 0.2.0 → 0.3.2
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.
- package/README.md +9 -3
- package/dist/cli.js +2072 -1385
- package/dist/cli.js.map +4 -4
- package/dist/commands/account-list/run-account-list-command.js +36 -18
- package/dist/commands/account-list/run-account-list-command.js.map +1 -1
- package/dist/commands/root/run-root-command.js +54 -6
- package/dist/commands/root/run-root-command.js.map +1 -1
- package/dist/config/wrapper-config.d.ts +2 -1
- package/dist/config/wrapper-config.js +66 -17
- package/dist/config/wrapper-config.js.map +1 -1
- package/dist/core/context.d.ts +3 -0
- package/dist/core/context.js +3 -0
- package/dist/core/context.js.map +1 -1
- package/dist/selection/format-selection-summary.d.ts +12 -0
- package/dist/selection/format-selection-summary.js +182 -0
- package/dist/selection/format-selection-summary.js.map +1 -0
- package/dist/selection/select-account.js +7 -163
- package/dist/selection/select-account.js.map +1 -1
- package/dist/selection/selection-summary.d.ts +38 -0
- package/dist/selection/selection-summary.js +405 -0
- package/dist/selection/selection-summary.js.map +1 -0
- package/dist/selection/usage-cache.js +23 -0
- package/dist/selection/usage-cache.js.map +1 -1
- package/dist/selection/usage-normalize.js +182 -19
- package/dist/selection/usage-normalize.js.map +1 -1
- package/dist/selection/usage-probe-coordinator.js +13 -0
- package/dist/selection/usage-probe-coordinator.js.map +1 -1
- package/dist/selection/usage-types.d.ts +18 -2
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-selection-summary.js","sourceRoot":"","sources":["../../src/selection/format-selection-summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,168 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveSelectionSummary } from "./selection-summary.js";
|
|
2
2
|
export async function selectAccountForExecution(input) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
accountCount: accounts.length,
|
|
3
|
+
const summary = await resolveSelectionSummary({
|
|
4
|
+
...input,
|
|
5
|
+
mode: "execution",
|
|
7
6
|
});
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
throw new Error("No accounts configured. Add one with `codexes account add <label>`.");
|
|
7
|
+
if (!summary.selectedAccount) {
|
|
8
|
+
throw new Error(summary.executionBlockedReason ?? "Execution selection did not resolve an account.");
|
|
11
9
|
}
|
|
12
|
-
|
|
13
|
-
case "manual-default":
|
|
14
|
-
return selectManualDefaultAccount(input.registry, input.logger, accounts);
|
|
15
|
-
case "single-account":
|
|
16
|
-
return selectSingleAccountOnly(input.registry, input.logger, accounts);
|
|
17
|
-
case "remaining-limit-experimental":
|
|
18
|
-
return selectExperimentalRemainingLimitAccount({
|
|
19
|
-
accounts,
|
|
20
|
-
experimentalSelection: input.experimentalSelection,
|
|
21
|
-
fetchImpl: input.fetchImpl,
|
|
22
|
-
logger: input.logger,
|
|
23
|
-
registry: input.registry,
|
|
24
|
-
selectionCacheFilePath: input.selectionCacheFilePath,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
async function selectManualDefaultAccount(registry, logger, accounts) {
|
|
29
|
-
const defaultAccount = await registry.getDefaultAccount();
|
|
30
|
-
if (defaultAccount) {
|
|
31
|
-
logger.info("selection.manual_default", {
|
|
32
|
-
accountId: defaultAccount.id,
|
|
33
|
-
label: defaultAccount.label,
|
|
34
|
-
});
|
|
35
|
-
return defaultAccount;
|
|
36
|
-
}
|
|
37
|
-
if (accounts.length === 1) {
|
|
38
|
-
const [singleAccount] = accounts;
|
|
39
|
-
if (!singleAccount) {
|
|
40
|
-
throw new Error("No accounts configured.");
|
|
41
|
-
}
|
|
42
|
-
logger.info("selection.manual_default_fallback_single", {
|
|
43
|
-
accountId: singleAccount.id,
|
|
44
|
-
label: singleAccount.label,
|
|
45
|
-
});
|
|
46
|
-
return registry.selectAccount(singleAccount.id);
|
|
47
|
-
}
|
|
48
|
-
logger.warn("selection.manual_default_missing", {
|
|
49
|
-
accountCount: accounts.length,
|
|
50
|
-
});
|
|
51
|
-
throw new Error("Multiple accounts are configured but no default account is selected. Use `codexes account use <account-id-or-label>` first.");
|
|
52
|
-
}
|
|
53
|
-
async function selectSingleAccountOnly(registry, logger, accounts) {
|
|
54
|
-
if (accounts.length !== 1) {
|
|
55
|
-
logger.warn("selection.single_account_invalid", {
|
|
56
|
-
accountCount: accounts.length,
|
|
57
|
-
});
|
|
58
|
-
throw new Error("The single-account strategy requires exactly one configured account.");
|
|
59
|
-
}
|
|
60
|
-
const [singleAccount] = accounts;
|
|
61
|
-
if (!singleAccount) {
|
|
62
|
-
throw new Error("No accounts configured.");
|
|
63
|
-
}
|
|
64
|
-
logger.info("selection.single_account", {
|
|
65
|
-
accountId: singleAccount.id,
|
|
66
|
-
label: singleAccount.label,
|
|
67
|
-
});
|
|
68
|
-
const defaultAccount = await registry.getDefaultAccount();
|
|
69
|
-
if (defaultAccount?.id === singleAccount.id) {
|
|
70
|
-
return singleAccount;
|
|
71
|
-
}
|
|
72
|
-
return registry.selectAccount(singleAccount.id);
|
|
73
|
-
}
|
|
74
|
-
async function selectExperimentalRemainingLimitAccount(input) {
|
|
75
|
-
if (!input.experimentalSelection?.enabled || !input.selectionCacheFilePath) {
|
|
76
|
-
input.logger.warn("selection.experimental_config_missing", {
|
|
77
|
-
enabled: input.experimentalSelection?.enabled ?? false,
|
|
78
|
-
hasSelectionCacheFilePath: Boolean(input.selectionCacheFilePath),
|
|
79
|
-
});
|
|
80
|
-
return selectManualDefaultAccount(input.registry, input.logger, input.accounts);
|
|
81
|
-
}
|
|
82
|
-
const defaultAccount = await input.registry.getDefaultAccount();
|
|
83
|
-
const probeResults = await resolveAccountUsageSnapshots({
|
|
84
|
-
accounts: input.accounts,
|
|
85
|
-
cacheFilePath: input.selectionCacheFilePath,
|
|
86
|
-
fetchImpl: input.fetchImpl,
|
|
87
|
-
logger: input.logger,
|
|
88
|
-
probeConfig: input.experimentalSelection,
|
|
89
|
-
});
|
|
90
|
-
const failedProbes = probeResults.filter((entry) => !entry.ok);
|
|
91
|
-
if (failedProbes.length > 0) {
|
|
92
|
-
const eventName = failedProbes.length === probeResults.length
|
|
93
|
-
? "selection.experimental_fallback_all_probes_failed"
|
|
94
|
-
: "selection.experimental_fallback_mixed_probe_outcomes";
|
|
95
|
-
input.logger.warn(eventName, {
|
|
96
|
-
failedAccountIds: failedProbes.map((entry) => entry.account.id),
|
|
97
|
-
failureCategories: failedProbes.map((entry) => entry.category),
|
|
98
|
-
successfulAccountIds: probeResults
|
|
99
|
-
.filter((entry) => entry.ok)
|
|
100
|
-
.map((entry) => entry.account.id),
|
|
101
|
-
});
|
|
102
|
-
return selectManualDefaultAccount(input.registry, input.logger, input.accounts);
|
|
103
|
-
}
|
|
104
|
-
const successfulProbes = probeResults.filter((entry) => entry.ok);
|
|
105
|
-
const candidates = successfulProbes
|
|
106
|
-
.filter((entry) => entry.snapshot.status === "usable")
|
|
107
|
-
.sort((left, right) => compareExperimentalCandidates({
|
|
108
|
-
defaultAccountId: defaultAccount?.id ?? null,
|
|
109
|
-
left,
|
|
110
|
-
right,
|
|
111
|
-
registryOrder: input.accounts,
|
|
112
|
-
}));
|
|
113
|
-
input.logger.info("selection.experimental_ranked", {
|
|
114
|
-
candidateOrder: candidates.map((entry) => ({
|
|
115
|
-
accountId: entry.account.id,
|
|
116
|
-
label: entry.account.label,
|
|
117
|
-
dailyRemaining: entry.snapshot.dailyRemaining,
|
|
118
|
-
weeklyRemaining: entry.snapshot.weeklyRemaining,
|
|
119
|
-
source: entry.source,
|
|
120
|
-
})),
|
|
121
|
-
defaultAccountId: defaultAccount?.id ?? null,
|
|
122
|
-
});
|
|
123
|
-
const selected = candidates[0];
|
|
124
|
-
if (!selected) {
|
|
125
|
-
const allExhausted = successfulProbes.every((entry) => entry.snapshot.limitReached || entry.snapshot.status === "limit-reached");
|
|
126
|
-
input.logger.warn(allExhausted
|
|
127
|
-
? "selection.experimental_fallback_all_accounts_exhausted"
|
|
128
|
-
: "selection.experimental_fallback_ambiguous_usage", {
|
|
129
|
-
usableProbeCount: candidates.length,
|
|
130
|
-
probeStatuses: successfulProbes.map((entry) => ({
|
|
131
|
-
accountId: entry.account.id,
|
|
132
|
-
snapshotStatus: entry.snapshot.status,
|
|
133
|
-
limitReached: entry.snapshot.limitReached,
|
|
134
|
-
dailyRemaining: entry.snapshot.dailyRemaining,
|
|
135
|
-
weeklyRemaining: entry.snapshot.weeklyRemaining,
|
|
136
|
-
})),
|
|
137
|
-
});
|
|
138
|
-
return selectManualDefaultAccount(input.registry, input.logger, input.accounts);
|
|
139
|
-
}
|
|
140
|
-
input.logger.info("selection.experimental_selected", {
|
|
141
|
-
accountId: selected.account.id,
|
|
142
|
-
label: selected.account.label,
|
|
143
|
-
dailyRemaining: selected.snapshot.dailyRemaining,
|
|
144
|
-
weeklyRemaining: selected.snapshot.weeklyRemaining,
|
|
145
|
-
source: selected.source,
|
|
146
|
-
});
|
|
147
|
-
return selected.account;
|
|
148
|
-
}
|
|
149
|
-
function compareExperimentalCandidates(input) {
|
|
150
|
-
const dailyDelta = (input.right.snapshot.dailyRemaining ?? Number.NEGATIVE_INFINITY) -
|
|
151
|
-
(input.left.snapshot.dailyRemaining ?? Number.NEGATIVE_INFINITY);
|
|
152
|
-
if (dailyDelta !== 0) {
|
|
153
|
-
return dailyDelta;
|
|
154
|
-
}
|
|
155
|
-
const weeklyDelta = (input.right.snapshot.weeklyRemaining ?? Number.NEGATIVE_INFINITY) -
|
|
156
|
-
(input.left.snapshot.weeklyRemaining ?? Number.NEGATIVE_INFINITY);
|
|
157
|
-
if (weeklyDelta !== 0) {
|
|
158
|
-
return weeklyDelta;
|
|
159
|
-
}
|
|
160
|
-
const leftIsDefault = input.left.account.id === input.defaultAccountId;
|
|
161
|
-
const rightIsDefault = input.right.account.id === input.defaultAccountId;
|
|
162
|
-
if (leftIsDefault !== rightIsDefault) {
|
|
163
|
-
return leftIsDefault ? -1 : 1;
|
|
164
|
-
}
|
|
165
|
-
return (input.registryOrder.findIndex((account) => account.id === input.left.account.id) -
|
|
166
|
-
input.registryOrder.findIndex((account) => account.id === input.right.account.id));
|
|
10
|
+
return summary.selectedAccount;
|
|
167
11
|
}
|
|
168
12
|
//# sourceMappingURL=select-account.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-account.js","sourceRoot":"","sources":["../../src/selection/select-account.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"select-account.js","sourceRoot":"","sources":["../../src/selection/select-account.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAO/C;IACC,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC;QAC5C,GAAG,KAAK;QACR,IAAI,EAAE,WAAW;KAClB,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,OAAO,CAAC,sBAAsB,IAAI,iDAAiD,CACpF,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,eAAe,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AccountRecord, AccountRegistry } from "../accounts/account-registry.js";
|
|
2
|
+
import type { AccountSelectionStrategy, ExperimentalSelectionConfig } from "../config/wrapper-config.js";
|
|
3
|
+
import type { Logger } from "../logging/logger.js";
|
|
4
|
+
import type { UsageProbeFailureCategory } from "./usage-client.js";
|
|
5
|
+
import type { NormalizedUsageSnapshot } from "./usage-types.js";
|
|
6
|
+
export type SelectionEntrySource = "cache" | "fresh" | "unavailable";
|
|
7
|
+
export type SelectionFallbackReason = "experimental-config-missing" | "all-probes-failed" | "mixed-probe-outcomes" | "all-accounts-exhausted" | "ambiguous-usage" | null;
|
|
8
|
+
export type SelectionDecisionMode = "manual-default" | "manual-default-fallback-single" | "single-account" | "experimental-ranked";
|
|
9
|
+
export type SelectionSummaryMode = "display-only" | "execution";
|
|
10
|
+
export interface SelectionSummaryEntry {
|
|
11
|
+
account: AccountRecord;
|
|
12
|
+
failureCategory: UsageProbeFailureCategory | null;
|
|
13
|
+
failureMessage: string | null;
|
|
14
|
+
isDefault: boolean;
|
|
15
|
+
isEligibleForRanking: boolean;
|
|
16
|
+
isSelected: boolean;
|
|
17
|
+
rankingPosition: number | null;
|
|
18
|
+
snapshot: NormalizedUsageSnapshot | null;
|
|
19
|
+
source: SelectionEntrySource;
|
|
20
|
+
}
|
|
21
|
+
export interface SelectionSummary {
|
|
22
|
+
entries: SelectionSummaryEntry[];
|
|
23
|
+
executionBlockedReason: string | null;
|
|
24
|
+
fallbackReason: SelectionFallbackReason;
|
|
25
|
+
mode: SelectionSummaryMode;
|
|
26
|
+
selectedAccount: AccountRecord | null;
|
|
27
|
+
selectedBy: SelectionDecisionMode | null;
|
|
28
|
+
strategy: AccountSelectionStrategy;
|
|
29
|
+
}
|
|
30
|
+
export declare function resolveSelectionSummary(input: {
|
|
31
|
+
experimentalSelection?: ExperimentalSelectionConfig;
|
|
32
|
+
fetchImpl?: typeof fetch;
|
|
33
|
+
logger: Logger;
|
|
34
|
+
mode?: SelectionSummaryMode;
|
|
35
|
+
registry: AccountRegistry;
|
|
36
|
+
selectionCacheFilePath?: string;
|
|
37
|
+
strategy: AccountSelectionStrategy;
|
|
38
|
+
}): Promise<SelectionSummary>;
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { resolveAccountUsageSnapshots } from "./usage-probe-coordinator.js";
|
|
2
|
+
export async function resolveSelectionSummary(input) {
|
|
3
|
+
const mode = input.mode ?? "execution";
|
|
4
|
+
const accounts = await input.registry.listAccounts();
|
|
5
|
+
input.logger.info("selection.summary.start", {
|
|
6
|
+
mode,
|
|
7
|
+
strategy: input.strategy,
|
|
8
|
+
accountCount: accounts.length,
|
|
9
|
+
});
|
|
10
|
+
if (accounts.length === 0) {
|
|
11
|
+
input.logger.warn("selection.none", {
|
|
12
|
+
mode,
|
|
13
|
+
strategy: input.strategy,
|
|
14
|
+
});
|
|
15
|
+
throw new Error("No accounts configured. Add one with `codexes account add <label>`.");
|
|
16
|
+
}
|
|
17
|
+
const defaultAccount = await input.registry.getDefaultAccount();
|
|
18
|
+
const summary = await resolveStrategySummary({
|
|
19
|
+
accounts,
|
|
20
|
+
defaultAccount,
|
|
21
|
+
experimentalSelection: input.experimentalSelection,
|
|
22
|
+
fetchImpl: input.fetchImpl,
|
|
23
|
+
logger: input.logger,
|
|
24
|
+
mode,
|
|
25
|
+
registry: input.registry,
|
|
26
|
+
selectionCacheFilePath: input.selectionCacheFilePath,
|
|
27
|
+
strategy: input.strategy,
|
|
28
|
+
});
|
|
29
|
+
input.logger.info("selection.summary.complete", {
|
|
30
|
+
mode: summary.mode,
|
|
31
|
+
strategy: summary.strategy,
|
|
32
|
+
selectedAccountId: summary.selectedAccount?.id ?? null,
|
|
33
|
+
selectedBy: summary.selectedBy,
|
|
34
|
+
fallbackReason: summary.fallbackReason,
|
|
35
|
+
executionBlockedReason: summary.executionBlockedReason,
|
|
36
|
+
entryCount: summary.entries.length,
|
|
37
|
+
});
|
|
38
|
+
return summary;
|
|
39
|
+
}
|
|
40
|
+
async function resolveStrategySummary(input) {
|
|
41
|
+
switch (input.strategy) {
|
|
42
|
+
case "manual-default":
|
|
43
|
+
return buildManualDefaultSummary(input.registry, input.logger, input.accounts, input.defaultAccount, input.mode);
|
|
44
|
+
case "single-account":
|
|
45
|
+
return buildSingleAccountSummary(input.registry, input.logger, input.accounts, input.defaultAccount, input.mode);
|
|
46
|
+
case "remaining-limit":
|
|
47
|
+
case "remaining-limit-experimental":
|
|
48
|
+
return buildExperimentalSummary(input);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function buildManualDefaultSummary(registry, logger, accounts, defaultAccount, mode) {
|
|
52
|
+
const selection = await resolveManualDefaultSelection({
|
|
53
|
+
accounts,
|
|
54
|
+
logger,
|
|
55
|
+
mode,
|
|
56
|
+
registry,
|
|
57
|
+
strategy: "manual-default",
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
entries: createUnavailableEntries(accounts, defaultAccount, selection.selectedAccount),
|
|
61
|
+
executionBlockedReason: selection.executionBlockedReason,
|
|
62
|
+
fallbackReason: null,
|
|
63
|
+
mode,
|
|
64
|
+
selectedAccount: selection.selectedAccount,
|
|
65
|
+
selectedBy: selection.selectedBy,
|
|
66
|
+
strategy: "manual-default",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function buildSingleAccountSummary(registry, logger, accounts, defaultAccount, mode) {
|
|
70
|
+
const selectedAccount = await selectSingleAccountOnly(registry, logger, accounts, mode);
|
|
71
|
+
return {
|
|
72
|
+
entries: createUnavailableEntries(accounts, defaultAccount, selectedAccount),
|
|
73
|
+
executionBlockedReason: null,
|
|
74
|
+
fallbackReason: null,
|
|
75
|
+
mode,
|
|
76
|
+
selectedAccount,
|
|
77
|
+
selectedBy: "single-account",
|
|
78
|
+
strategy: "single-account",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function buildExperimentalSummary(input) {
|
|
82
|
+
if (!input.experimentalSelection?.enabled || !input.selectionCacheFilePath) {
|
|
83
|
+
input.logger.warn("selection.experimental_config_missing", {
|
|
84
|
+
enabled: input.experimentalSelection?.enabled ?? false,
|
|
85
|
+
hasSelectionCacheFilePath: Boolean(input.selectionCacheFilePath),
|
|
86
|
+
mode: input.mode,
|
|
87
|
+
});
|
|
88
|
+
const fallbackSelection = await resolveManualDefaultSelection({
|
|
89
|
+
accounts: input.accounts,
|
|
90
|
+
fallbackReason: "experimental-config-missing",
|
|
91
|
+
logger: input.logger,
|
|
92
|
+
mode: input.mode,
|
|
93
|
+
registry: input.registry,
|
|
94
|
+
strategy: input.strategy,
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
entries: createUnavailableEntries(input.accounts, input.defaultAccount, fallbackSelection.selectedAccount),
|
|
98
|
+
executionBlockedReason: fallbackSelection.executionBlockedReason,
|
|
99
|
+
fallbackReason: "experimental-config-missing",
|
|
100
|
+
mode: input.mode,
|
|
101
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
102
|
+
selectedBy: fallbackSelection.selectedBy,
|
|
103
|
+
strategy: input.strategy,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const probeResults = await resolveAccountUsageSnapshots({
|
|
107
|
+
accounts: input.accounts,
|
|
108
|
+
cacheFilePath: input.selectionCacheFilePath,
|
|
109
|
+
fetchImpl: input.fetchImpl,
|
|
110
|
+
logger: input.logger,
|
|
111
|
+
probeConfig: input.experimentalSelection,
|
|
112
|
+
});
|
|
113
|
+
const failedProbes = probeResults.filter((entry) => !entry.ok);
|
|
114
|
+
if (failedProbes.length > 0) {
|
|
115
|
+
const fallbackReason = failedProbes.length === probeResults.length ? "all-probes-failed" : "mixed-probe-outcomes";
|
|
116
|
+
input.logger.warn(fallbackReason === "all-probes-failed"
|
|
117
|
+
? "selection.experimental_fallback_all_probes_failed"
|
|
118
|
+
: "selection.experimental_fallback_mixed_probe_outcomes", {
|
|
119
|
+
failedAccountIds: failedProbes.map((entry) => entry.account.id),
|
|
120
|
+
failureCategories: failedProbes.map((entry) => entry.category),
|
|
121
|
+
mode: input.mode,
|
|
122
|
+
successfulAccountIds: probeResults
|
|
123
|
+
.filter((entry) => entry.ok)
|
|
124
|
+
.map((entry) => entry.account.id),
|
|
125
|
+
});
|
|
126
|
+
const fallbackSelection = await resolveManualDefaultSelection({
|
|
127
|
+
accounts: input.accounts,
|
|
128
|
+
fallbackReason,
|
|
129
|
+
logger: input.logger,
|
|
130
|
+
mode: input.mode,
|
|
131
|
+
registry: input.registry,
|
|
132
|
+
strategy: input.strategy,
|
|
133
|
+
});
|
|
134
|
+
logExperimentalFallbackSelection(input.logger, {
|
|
135
|
+
fallbackReason,
|
|
136
|
+
mode: input.mode,
|
|
137
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
138
|
+
selectedBy: fallbackSelection.selectedBy,
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
entries: createExperimentalEntries({
|
|
142
|
+
defaultAccount: input.defaultAccount,
|
|
143
|
+
probeResults,
|
|
144
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
145
|
+
selectedCandidateIds: [],
|
|
146
|
+
}),
|
|
147
|
+
executionBlockedReason: fallbackSelection.executionBlockedReason,
|
|
148
|
+
fallbackReason,
|
|
149
|
+
mode: input.mode,
|
|
150
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
151
|
+
selectedBy: fallbackSelection.selectedBy,
|
|
152
|
+
strategy: input.strategy,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const successfulProbes = probeResults.filter((entry) => entry.ok);
|
|
156
|
+
const candidates = successfulProbes
|
|
157
|
+
.filter((entry) => entry.snapshot.status === "usable")
|
|
158
|
+
.sort((left, right) => compareExperimentalCandidates({
|
|
159
|
+
defaultAccountId: input.defaultAccount?.id ?? null,
|
|
160
|
+
left,
|
|
161
|
+
registryOrder: input.accounts,
|
|
162
|
+
right,
|
|
163
|
+
}));
|
|
164
|
+
input.logger.info("selection.experimental_ranked", {
|
|
165
|
+
candidateOrder: candidates.map((entry) => ({
|
|
166
|
+
accountId: entry.account.id,
|
|
167
|
+
label: entry.account.label,
|
|
168
|
+
primaryRemainingPercent: entry.snapshot.dailyRemaining,
|
|
169
|
+
secondaryRemainingPercent: entry.snapshot.weeklyRemaining,
|
|
170
|
+
source: entry.source,
|
|
171
|
+
})),
|
|
172
|
+
defaultAccountId: input.defaultAccount?.id ?? null,
|
|
173
|
+
mode: input.mode,
|
|
174
|
+
rankingSignal: "remaining-percent",
|
|
175
|
+
tieBreakOrder: [
|
|
176
|
+
"primary_remaining_percent_desc",
|
|
177
|
+
"secondary_remaining_percent_desc",
|
|
178
|
+
"default_account",
|
|
179
|
+
"registry_order",
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
const selected = candidates[0];
|
|
183
|
+
if (!selected) {
|
|
184
|
+
const allExhausted = successfulProbes.every((entry) => entry.snapshot.limitReached || entry.snapshot.status === "limit-reached");
|
|
185
|
+
const fallbackReason = allExhausted ? "all-accounts-exhausted" : "ambiguous-usage";
|
|
186
|
+
input.logger.warn(allExhausted
|
|
187
|
+
? "selection.experimental_fallback_all_accounts_exhausted"
|
|
188
|
+
: "selection.experimental_fallback_ambiguous_usage", {
|
|
189
|
+
mode: input.mode,
|
|
190
|
+
usableProbeCount: candidates.length,
|
|
191
|
+
probeStatuses: successfulProbes.map((entry) => ({
|
|
192
|
+
accountId: entry.account.id,
|
|
193
|
+
snapshotStatus: entry.snapshot.status,
|
|
194
|
+
limitReached: entry.snapshot.limitReached,
|
|
195
|
+
dailyRemaining: entry.snapshot.dailyRemaining,
|
|
196
|
+
weeklyRemaining: entry.snapshot.weeklyRemaining,
|
|
197
|
+
})),
|
|
198
|
+
});
|
|
199
|
+
const fallbackSelection = await resolveManualDefaultSelection({
|
|
200
|
+
accounts: input.accounts,
|
|
201
|
+
fallbackReason,
|
|
202
|
+
logger: input.logger,
|
|
203
|
+
mode: input.mode,
|
|
204
|
+
registry: input.registry,
|
|
205
|
+
strategy: input.strategy,
|
|
206
|
+
});
|
|
207
|
+
logExperimentalFallbackSelection(input.logger, {
|
|
208
|
+
fallbackReason,
|
|
209
|
+
mode: input.mode,
|
|
210
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
211
|
+
selectedBy: fallbackSelection.selectedBy,
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
entries: createExperimentalEntries({
|
|
215
|
+
defaultAccount: input.defaultAccount,
|
|
216
|
+
probeResults,
|
|
217
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
218
|
+
selectedCandidateIds: [],
|
|
219
|
+
}),
|
|
220
|
+
executionBlockedReason: fallbackSelection.executionBlockedReason,
|
|
221
|
+
fallbackReason,
|
|
222
|
+
mode: input.mode,
|
|
223
|
+
selectedAccount: fallbackSelection.selectedAccount,
|
|
224
|
+
selectedBy: fallbackSelection.selectedBy,
|
|
225
|
+
strategy: input.strategy,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
input.logger.info("selection.experimental_selected", {
|
|
229
|
+
accountId: selected.account.id,
|
|
230
|
+
label: selected.account.label,
|
|
231
|
+
primaryRemainingPercent: selected.snapshot.dailyRemaining,
|
|
232
|
+
secondaryRemainingPercent: selected.snapshot.weeklyRemaining,
|
|
233
|
+
source: selected.source,
|
|
234
|
+
mode: input.mode,
|
|
235
|
+
selectedBy: "experimental-ranked",
|
|
236
|
+
rankingSignal: "remaining-percent",
|
|
237
|
+
});
|
|
238
|
+
return {
|
|
239
|
+
entries: createExperimentalEntries({
|
|
240
|
+
defaultAccount: input.defaultAccount,
|
|
241
|
+
probeResults,
|
|
242
|
+
selectedAccount: selected.account,
|
|
243
|
+
selectedCandidateIds: candidates.map((entry) => entry.account.id),
|
|
244
|
+
}),
|
|
245
|
+
executionBlockedReason: null,
|
|
246
|
+
fallbackReason: null,
|
|
247
|
+
mode: input.mode,
|
|
248
|
+
selectedAccount: selected.account,
|
|
249
|
+
selectedBy: "experimental-ranked",
|
|
250
|
+
strategy: input.strategy,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async function resolveManualDefaultSelection(input) {
|
|
254
|
+
input.logger.debug("selection.manual_default.requirement", {
|
|
255
|
+
mode: input.mode,
|
|
256
|
+
strategy: input.strategy,
|
|
257
|
+
fallbackReason: input.fallbackReason ?? null,
|
|
258
|
+
accountCount: input.accounts.length,
|
|
259
|
+
});
|
|
260
|
+
const defaultAccount = await input.registry.getDefaultAccount();
|
|
261
|
+
if (defaultAccount) {
|
|
262
|
+
input.logger.info("selection.manual_default", {
|
|
263
|
+
accountId: defaultAccount.id,
|
|
264
|
+
label: defaultAccount.label,
|
|
265
|
+
mode: input.mode,
|
|
266
|
+
strategy: input.strategy,
|
|
267
|
+
});
|
|
268
|
+
return {
|
|
269
|
+
executionBlockedReason: null,
|
|
270
|
+
selectedAccount: defaultAccount,
|
|
271
|
+
selectedBy: "manual-default",
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (input.accounts.length === 1) {
|
|
275
|
+
const [singleAccount] = input.accounts;
|
|
276
|
+
if (!singleAccount) {
|
|
277
|
+
throw new Error("No accounts configured.");
|
|
278
|
+
}
|
|
279
|
+
input.logger.info("selection.manual_default_fallback_single", {
|
|
280
|
+
accountId: singleAccount.id,
|
|
281
|
+
label: singleAccount.label,
|
|
282
|
+
mode: input.mode,
|
|
283
|
+
strategy: input.strategy,
|
|
284
|
+
});
|
|
285
|
+
return {
|
|
286
|
+
executionBlockedReason: null,
|
|
287
|
+
selectedAccount: await input.registry.selectAccount(singleAccount.id),
|
|
288
|
+
selectedBy: "manual-default-fallback-single",
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const executionBlockedReason = "Multiple accounts are configured but no default account is selected. Use `codexes account use <account-id-or-label>` first.";
|
|
292
|
+
input.logger.warn("selection.manual_default_missing", {
|
|
293
|
+
accountCount: input.accounts.length,
|
|
294
|
+
mode: input.mode,
|
|
295
|
+
strategy: input.strategy,
|
|
296
|
+
fallbackReason: input.fallbackReason ?? null,
|
|
297
|
+
});
|
|
298
|
+
if (input.mode === "display-only") {
|
|
299
|
+
input.logger.info("selection.display_only_missing_execution_account", {
|
|
300
|
+
accountCount: input.accounts.length,
|
|
301
|
+
strategy: input.strategy,
|
|
302
|
+
fallbackReason: input.fallbackReason ?? null,
|
|
303
|
+
});
|
|
304
|
+
return {
|
|
305
|
+
executionBlockedReason,
|
|
306
|
+
selectedAccount: null,
|
|
307
|
+
selectedBy: null,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
input.logger.warn("selection.execution_blocked_missing_default", {
|
|
311
|
+
accountCount: input.accounts.length,
|
|
312
|
+
strategy: input.strategy,
|
|
313
|
+
fallbackReason: input.fallbackReason ?? null,
|
|
314
|
+
});
|
|
315
|
+
throw new Error(executionBlockedReason);
|
|
316
|
+
}
|
|
317
|
+
async function selectSingleAccountOnly(registry, logger, accounts, mode) {
|
|
318
|
+
logger.debug("selection.single_account.requirement", {
|
|
319
|
+
mode,
|
|
320
|
+
accountCount: accounts.length,
|
|
321
|
+
});
|
|
322
|
+
if (accounts.length !== 1) {
|
|
323
|
+
logger.warn("selection.single_account_invalid", {
|
|
324
|
+
accountCount: accounts.length,
|
|
325
|
+
mode,
|
|
326
|
+
});
|
|
327
|
+
throw new Error("The single-account strategy requires exactly one configured account.");
|
|
328
|
+
}
|
|
329
|
+
const [singleAccount] = accounts;
|
|
330
|
+
if (!singleAccount) {
|
|
331
|
+
throw new Error("No accounts configured.");
|
|
332
|
+
}
|
|
333
|
+
logger.info("selection.single_account", {
|
|
334
|
+
accountId: singleAccount.id,
|
|
335
|
+
label: singleAccount.label,
|
|
336
|
+
mode,
|
|
337
|
+
});
|
|
338
|
+
const defaultAccount = await registry.getDefaultAccount();
|
|
339
|
+
if (defaultAccount?.id === singleAccount.id) {
|
|
340
|
+
return singleAccount;
|
|
341
|
+
}
|
|
342
|
+
return registry.selectAccount(singleAccount.id);
|
|
343
|
+
}
|
|
344
|
+
function createUnavailableEntries(accounts, defaultAccount, selectedAccount) {
|
|
345
|
+
return accounts.map((account) => ({
|
|
346
|
+
account,
|
|
347
|
+
failureCategory: null,
|
|
348
|
+
failureMessage: null,
|
|
349
|
+
isDefault: account.id === defaultAccount?.id,
|
|
350
|
+
isEligibleForRanking: false,
|
|
351
|
+
isSelected: account.id === selectedAccount?.id,
|
|
352
|
+
rankingPosition: null,
|
|
353
|
+
snapshot: null,
|
|
354
|
+
source: "unavailable",
|
|
355
|
+
}));
|
|
356
|
+
}
|
|
357
|
+
function createExperimentalEntries(input) {
|
|
358
|
+
return input.probeResults.map((entry) => ({
|
|
359
|
+
account: entry.account,
|
|
360
|
+
failureCategory: entry.ok ? null : entry.category,
|
|
361
|
+
failureMessage: entry.ok ? null : entry.message,
|
|
362
|
+
isDefault: entry.account.id === input.defaultAccount?.id,
|
|
363
|
+
isEligibleForRanking: entry.ok && entry.snapshot.status === "usable",
|
|
364
|
+
isSelected: entry.account.id === input.selectedAccount?.id,
|
|
365
|
+
rankingPosition: entry.ok ? resolveRankingPosition(input.selectedCandidateIds, entry.account.id) : null,
|
|
366
|
+
snapshot: entry.ok ? entry.snapshot : null,
|
|
367
|
+
source: entry.ok ? entry.source : "fresh",
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
function resolveRankingPosition(selectedCandidateIds, accountId) {
|
|
371
|
+
const index = selectedCandidateIds.indexOf(accountId);
|
|
372
|
+
if (index < 0) {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
return index + 1;
|
|
376
|
+
}
|
|
377
|
+
function compareExperimentalCandidates(input) {
|
|
378
|
+
const dailyDelta = (input.right.snapshot.dailyRemaining ?? Number.NEGATIVE_INFINITY) -
|
|
379
|
+
(input.left.snapshot.dailyRemaining ?? Number.NEGATIVE_INFINITY);
|
|
380
|
+
if (dailyDelta !== 0) {
|
|
381
|
+
return dailyDelta;
|
|
382
|
+
}
|
|
383
|
+
const weeklyDelta = (input.right.snapshot.weeklyRemaining ?? Number.NEGATIVE_INFINITY) -
|
|
384
|
+
(input.left.snapshot.weeklyRemaining ?? Number.NEGATIVE_INFINITY);
|
|
385
|
+
if (weeklyDelta !== 0) {
|
|
386
|
+
return weeklyDelta;
|
|
387
|
+
}
|
|
388
|
+
const leftIsDefault = input.left.account.id === input.defaultAccountId;
|
|
389
|
+
const rightIsDefault = input.right.account.id === input.defaultAccountId;
|
|
390
|
+
if (leftIsDefault !== rightIsDefault) {
|
|
391
|
+
return leftIsDefault ? -1 : 1;
|
|
392
|
+
}
|
|
393
|
+
return (input.registryOrder.findIndex((account) => account.id === input.left.account.id) -
|
|
394
|
+
input.registryOrder.findIndex((account) => account.id === input.right.account.id));
|
|
395
|
+
}
|
|
396
|
+
function logExperimentalFallbackSelection(logger, input) {
|
|
397
|
+
logger.info("selection.experimental_fallback_selected", {
|
|
398
|
+
fallbackReason: input.fallbackReason,
|
|
399
|
+
mode: input.mode,
|
|
400
|
+
selectedAccountId: input.selectedAccount?.id ?? null,
|
|
401
|
+
selectedBy: input.selectedBy,
|
|
402
|
+
rankingSignal: input.selectedBy === null ? null : "manual-default-fallback",
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=selection-summary.js.map
|