@code-yeongyu/senpi-ai 2026.10.27-2 → 2026.10.30-1
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/dist/auth/pool/select.d.ts +5 -0
- package/dist/auth/pool/select.js +17 -5
- package/dist/legacy-provider-ids.d.ts +5 -0
- package/dist/legacy-provider-ids.js +7 -0
- package/dist/models.d.ts +5 -0
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/chatgpt-subscription.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/radius.json +1 -1
- package/dist/providers/data/venice.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/utils/provider-diagnostic-sources.d.ts +3 -2
- package/dist/utils/provider-diagnostic-sources.js +15 -4
- package/dist/utils/provider-diagnostic-vocabulary.d.ts +4 -3
- package/dist/utils/provider-diagnostic-vocabulary.js +6 -3
- package/dist/utils/provider-failure-description.js +14 -3
- package/package.json +2 -2
|
@@ -36,6 +36,11 @@ export declare function applyAccountOrder<T extends {
|
|
|
36
36
|
export declare function withoutOrderedAccount<T extends {
|
|
37
37
|
order?: string[];
|
|
38
38
|
}>(credential: T, name: string): T;
|
|
39
|
+
/**
|
|
40
|
+
* Whether selection skips a slot now: an auth block holds until a login rewrites the slot, whatever its deadline;
|
|
41
|
+
* any other block holds until its deadline. Account listings ask this too, so they never call a skipped slot available.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isSlotBlocked(slot: Pick<SelectableSlot, "blockedUntil" | "blockReason">, now: number): boolean;
|
|
39
44
|
/** Elapsed rate/capacity blocks clear; auth blocks persist until a login rewrites the slot. */
|
|
40
45
|
export declare function clearExpiredSlotBlocks(slots: readonly SelectableSlot[], now?: number): SelectableSlot[];
|
|
41
46
|
/** Selects a pinned or HRW-ranked slot with no pool-global selection state. */
|
package/dist/auth/pool/select.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
export const DEFAULT_POOL_AFFINITY_KEY = "credential-pool-default";
|
|
2
2
|
export class AllSlotsBlockedError extends Error {
|
|
3
3
|
constructor(soonestUnblockAt) {
|
|
4
|
+
// Local time for the reader, the ISO instant for prose scanners, and one step (senpi#4329).
|
|
4
5
|
super(soonestUnblockAt === undefined
|
|
5
|
-
? "All credential slots are blocked until re-login."
|
|
6
|
-
: `All credential slots are blocked until ${new Date(soonestUnblockAt).
|
|
6
|
+
? "All credential slots are blocked until re-login. Sign in again or add a new API key for this provider, or choose another model."
|
|
7
|
+
: `All credential slots are blocked until ${new Date(soonestUnblockAt).toLocaleString("en-US", {
|
|
8
|
+
year: "numeric",
|
|
9
|
+
month: "short",
|
|
10
|
+
day: "numeric",
|
|
11
|
+
hour: "numeric",
|
|
12
|
+
minute: "2-digit",
|
|
13
|
+
timeZoneName: "short",
|
|
14
|
+
})} (${new Date(soonestUnblockAt).toISOString()}). Wait until then, or choose another model.`);
|
|
7
15
|
this.name = "AllSlotsBlockedError";
|
|
8
16
|
this.soonestUnblockAt = soonestUnblockAt;
|
|
9
17
|
}
|
|
@@ -51,7 +59,11 @@ export function withoutOrderedAccount(credential, name) {
|
|
|
51
59
|
next.order = order;
|
|
52
60
|
return next;
|
|
53
61
|
}
|
|
54
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Whether selection skips a slot now: an auth block holds until a login rewrites the slot, whatever its deadline;
|
|
64
|
+
* any other block holds until its deadline. Account listings ask this too, so they never call a skipped slot available.
|
|
65
|
+
*/
|
|
66
|
+
export function isSlotBlocked(slot, now) {
|
|
55
67
|
return slot.blockReason === "auth_error" || (slot.blockedUntil !== undefined && slot.blockedUntil > now);
|
|
56
68
|
}
|
|
57
69
|
/** Elapsed rate/capacity blocks clear; auth blocks persist until a login rewrites the slot. */
|
|
@@ -66,9 +78,9 @@ export function clearExpiredSlotBlocks(slots, now = Date.now()) {
|
|
|
66
78
|
}
|
|
67
79
|
function selectUnblocked(slots, options, now) {
|
|
68
80
|
const pinned = options.pinnedSlot === undefined ? undefined : slots.find((slot) => slot.name === options.pinnedSlot);
|
|
69
|
-
if (pinned && !
|
|
81
|
+
if (pinned && !isSlotBlocked(pinned, now))
|
|
70
82
|
return pinned;
|
|
71
|
-
return rendezvousOrder(getPoolAffinityKey(options), slots, options.hasher).find((slot) => !
|
|
83
|
+
return rendezvousOrder(getPoolAffinityKey(options), slots, options.hasher).find((slot) => !isSlotBlocked(slot, now));
|
|
72
84
|
}
|
|
73
85
|
function soonestUnblockAt(slots, now) {
|
|
74
86
|
const candidates = slots
|
|
@@ -11,6 +11,11 @@ export declare function isLegacyProviderId(id: string): boolean;
|
|
|
11
11
|
* earlier version. Returns an empty array for an id that was never renamed.
|
|
12
12
|
*/
|
|
13
13
|
export declare function legacyProviderIdsFor(canonicalId: string): string[];
|
|
14
|
+
/**
|
|
15
|
+
* The id upstream pi still uses for `providerId`: the legacy spelling of a renamed provider (the
|
|
16
|
+
* remote model catalog serves `openai-codex`, not `chatgpt-subscription`), the id itself otherwise.
|
|
17
|
+
*/
|
|
18
|
+
export declare function upstreamProviderIdFor(providerId: string): string;
|
|
14
19
|
/**
|
|
15
20
|
* Read `record` by provider id, trying the canonical key first and then every
|
|
16
21
|
* legacy spelling that normalizes to it. Never throws and never rewrites.
|
|
@@ -33,6 +33,13 @@ export function legacyProviderIdsFor(canonicalId) {
|
|
|
33
33
|
.filter(([, canonical]) => canonical === canonicalId)
|
|
34
34
|
.map(([legacy]) => legacy);
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* The id upstream pi still uses for `providerId`: the legacy spelling of a renamed provider (the
|
|
38
|
+
* remote model catalog serves `openai-codex`, not `chatgpt-subscription`), the id itself otherwise.
|
|
39
|
+
*/
|
|
40
|
+
export function upstreamProviderIdFor(providerId) {
|
|
41
|
+
return legacyProviderIdsFor(providerId)[0] ?? providerId;
|
|
42
|
+
}
|
|
36
43
|
/**
|
|
37
44
|
* Read `record` by provider id, trying the canonical key first and then every
|
|
38
45
|
* legacy spelling that normalizes to it. Never throws and never rewrites.
|
package/dist/models.d.ts
CHANGED
|
@@ -66,6 +66,11 @@ type ProviderModel<TApi extends Api> = Model<TApi> | ImageModel<ImageApi> | Clas
|
|
|
66
66
|
export interface Provider<TApi extends Api = Api> {
|
|
67
67
|
readonly id: string;
|
|
68
68
|
readonly name: string;
|
|
69
|
+
/**
|
|
70
|
+
* The provider's endpoint. Transports send each request to `model.baseUrl`, never to this value or a
|
|
71
|
+
* hard-coded host: senpi sets every model's `baseUrl` (and this field) to a user's models.json
|
|
72
|
+
* `baseUrl` when one is configured for the provider.
|
|
73
|
+
*/
|
|
69
74
|
readonly baseUrl?: string;
|
|
70
75
|
readonly headers?: ProviderHeaders;
|
|
71
76
|
/** Omitting it means the shipped senpi default profile applies. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schemaVersion":6,"generatedAt":"2026-10-
|
|
1
|
+
{"schemaVersion":6,"generatedAt":"2026-10-30T10:17:08.531Z","structureHash":"2afb7e11360dbbeb58bb3ee9faaa3603407df44f43ea38a0febaa36dea48eea0","files":{"alibaba-token-plan.json":"9f4d42cc765b2a875bcdcaa392bfdc1323c88968309baf9db9f611a26c595c73","amazon-bedrock.json":"a7e20838b095788cb9d5acbde49664b7f2868fad9b10fb4bbbd66635085bca2d","ant-ling.json":"628feab3ef6c7d80ce96f75999804e1d9f05fec3851e5302e30fff3b69db90f6","anthropic.json":"111384e9f5845e0247bd34edf2400ef7720fcbdac140b944cf8878192d8bd6ab","azure-openai-responses.json":"fd64c6a2a99fa87d768ed2f75f5c7813876df1dbe2f0d1776f7d9bd7ce2e61e4","bai.json":"7e6861aaf27d8af34e1771c6092602194fcec0a0046e6adfab9c3ee54d32b99f","baseten.json":"5bd3c98c61769388b3724368ef964d16b7a58e41a6edcf4ebceb9d4ac0a21d3b","cerebras.json":"2eb969b2956844f9a641d3de52c19f1791293c58f607282fb3b0ebfe85ff66f8","chatgpt-subscription.json":"98320f1d51709d26ca047b3d6e3191cfe2f192f1b27897cbb492f47b0e5a5030","cloudflare-ai-gateway.json":"1faa40d07413f2dd8a4c387dcae2c8d084e222d3191730f5bd4af48b2fa6ba34","cloudflare-workers-ai.json":"1b9ad4360bde817f0ea358431020308f1052840e2278a57a93629f1790072d2e","deepseek.json":"10a296fb3e898f7715c80890c8af0af4f5fd58f22dbcd6612fdc5d762157ccdc","fireworks.json":"56c557eb97573028e871c211cb17e1d60665eb12d67a712615db4bb255bc9253","github-copilot.json":"474fa92eb88ef242208ca93709ebe6d7f21754917d0cad6210bd1edf2b99a87e","google-vertex.json":"8f986b4aca8c685b0f3481bd252bda21e4858bf9015ad37fc5bcc44b7f01d076","google.json":"d25613a7377e81d785d571be514d67b35436511ce6946247dc66f8674e2a5035","groq.json":"087df37206e9eed8b10f1e558e4c496289bef60074b7e8afba4f20fb102b4ec2","huggingface.json":"209cdcf205961ef2ff203486da614232a86a069ebe0e98266189a14a235fac8f","meta.json":"563f5ec07973f52ab8c3eb26ef91a36ad8a79e950b37174935666cdcb624bf35","minimax-cn.json":"70df757e95e9ea2275bf451956b58a746020835f6cbcbd1a644d7fad5b9941d3","minimax.json":"747038b05f4fc24e41405e8bc810f893d7d5121e214e35e6f812f775769a3806","mistral.json":"aafecc66686645b1baa8c90e81c02856115f09999ff507f9bee004d2e1c77a28","moonshotai-cn.json":"a953eace729ef96c91195d477c63c776a1c40aa36085b61236ca1be0fe5b9337","moonshotai.json":"0435f9dc4e532c0764b6d33d8dfa83ce5fccdbcab54224c5ae74ec2d965290f5","nvidia.json":"0e45bcd4d5a897f6f6785c0e257a9fb03691cef3ff87d9254da5daa5075468da","openai.json":"d61200cdd22d931dfff8181a5ed8d636c89fb34637dcec80f07ec24f8c2ef5c6","opencode-go.json":"2a5e0424854edfc0ef9a49033e80a8eb32c01a98c56ba2879b36a9502baa4027","opencode.json":"0e08d3fc23284852968106c4e0c17e85adedf729db145b8c7871e9bd999845b1","opengateway.json":"f97aaf0bb610a7d812c5921d4bbd08008f603c6acce8e3d5521be0f35d69af6e","openrouter.json":"bee0669879f02deb114eed5129c29356ac012bd63156c5ba50d22db742e45eed","qwen-token-plan-cn.json":"751b18bd443fceb16659ea33013fed90fbf3bbdb4e0ffd7607c93cee2b4cf40d","qwen-token-plan-individual.json":"35ffb0ba1a1ce3f68fc73262dd5e07fbcb5bf5911ad1e6e17bc0621e2894676a","qwen-token-plan.json":"e59b0a45e238578f80d0eea937a093b9cec7cb93751ae20a9e88b16c09eb5cdd","radius.json":"5241be199f873fd7474b1ccb1fc911af223903af681909029fefe9fb8b49f83c","together.json":"a68b8386a2f28f9e1570d296223fdbdc0ebcca8a322ade5b999212c0e60b772c","typesafe.json":"83409437dbf4c353ac413c0db4e7cf29902fc35e0e0197bdb4eeda2d7f3b07cd","venice.json":"371678630c2b8c81110e170585cb545f2a667b4db7dcff3155bfb6b45a68ae0f","vercel-ai-gateway.json":"202c248c702425999d13548ecfd5523eca615d7cbd8e1b319bbe954a2acac20d","xai.json":"cf3f475fe5a13625f858171900ba3456c4d95ebb0bac5060cc25e29bb31d3457","xiaomi-token-plan-ams.json":"7fa339ba5675460b1ff4e5bca9e8ad0aa60b0277d75a989b1c196aa6ca2af34d","xiaomi-token-plan-cn.json":"ef7917c6ea0d3edc655c8a52082ee5f1330658aa6f10199d8f164eb4605ef0a0","xiaomi-token-plan-sgp.json":"addda93f6b70ba879db97e3cfd2e4f2efc7cda47d7daa78c23c5b0e51162de5c","xiaomi.json":"5a42caf49d3e4d7946d60386e9899c2146bf8e3cbaff4c576ee4f49b398cc11c","zai-coding-cn.json":"2b6f85e04b5c568e320b1bde25b1c1614af9342e4c1ba0e1d5bb248aaf50cfe9","zai.json":"e9cc408e1756de8abc70148d63d89d11a63c65b7ef06ad0661cd1328e4209ba3"}}
|