@code-yeongyu/senpi-ai 2026.10.30-2 → 2026.10.31-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/dist/api/anthropic-messages.d.ts +13 -3
- package/dist/api/anthropic-messages.js +62 -185
- package/dist/api/anthropic-system-blocks.d.ts +12 -0
- package/dist/api/anthropic-system-blocks.js +35 -0
- package/dist/api/openai-completions.js +19 -2
- package/dist/auth/helpers.d.ts +1 -0
- package/dist/auth/helpers.js +1 -0
- package/dist/auth/oauth/load.d.ts +0 -2
- package/dist/auth/oauth/load.js +0 -5
- package/dist/auth/pool/slots.d.ts +11 -1
- package/dist/auth/pool/slots.js +63 -1
- package/dist/auth/types.d.ts +7 -0
- package/dist/bun-oauth.js +0 -2
- package/dist/compat/extension-oauth-types.d.ts +1 -0
- package/dist/models.js +1 -1
- package/dist/oauth.d.ts +1 -1
- package/dist/oauth.js +1 -1
- package/dist/providers/anthropic.js +2 -1
- package/dist/providers/chatgpt-subscription.js +2 -0
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/venice.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/utils/chatgpt-subscription-auth.d.ts +7 -0
- package/dist/utils/chatgpt-subscription-auth.js +21 -4
- package/dist/utils/prompt-cache-ttl.d.ts +2 -1
- package/dist/utils/prompt-cache-ttl.js +2 -0
- package/dist/utils/retry-hint.d.ts +3 -1
- package/dist/utils/retry-hint.js +80 -2
- package/dist/utils/tool-schema-compat.js +35 -0
- package/dist/utils/transcript.d.ts +1 -1
- package/dist/utils/transcript.js +12 -2
- package/dist/utils/validation.js +111 -4
- package/package.json +2 -2
- package/dist/auth/oauth/anthropic-callback-listener.d.ts +0 -40
- package/dist/auth/oauth/anthropic-callback-listener.js +0 -138
- package/dist/auth/oauth/anthropic.d.ts +0 -13
- package/dist/auth/oauth/anthropic.js +0 -285
- package/dist/auth/oauth/authorization-input.d.ts +0 -6
- package/dist/auth/oauth/authorization-input.js +0 -29
- package/dist/auth/oauth/error-details.d.ts +0 -3
- package/dist/auth/oauth/error-details.js +0 -20
- package/dist/utils/claude-code-version-cache.d.ts +0 -12
- package/dist/utils/claude-code-version-cache.js +0 -60
- package/dist/utils/claude-code-version.d.ts +0 -78
- package/dist/utils/claude-code-version.js +0 -203
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { getProviderEnvValue } from "./provider-env.js";
|
|
2
|
-
/** Exact `X.Y.Z` pins the fingerprint and skips the network lookup. */
|
|
3
|
-
export const CLAUDE_CODE_VERSION_PIN_ENV = "PI_CLAUDE_CODE_VERSION";
|
|
4
|
-
/**
|
|
5
|
-
* Anthropic's native-installer release channel. `stable` lags the npm package during a staged
|
|
6
|
-
* rollout, so `latest` is the channel that matches what a freshly updated Claude Code reports.
|
|
7
|
-
*/
|
|
8
|
-
export const CLAUDE_RELEASE_CHANNEL_URL = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest";
|
|
9
|
-
export const CLAUDE_NPM_DIST_TAG_URL = "https://registry.npmjs.org/@anthropic-ai/claude-code/latest";
|
|
10
|
-
const REFRESH_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
11
|
-
const FETCH_TIMEOUT_MS = 5_000;
|
|
12
|
-
const EXACT_SEMVER = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
13
|
-
const EMBEDDED_SEMVER = /(\d+\.\d+\.\d+)/;
|
|
14
|
-
const TOO_OLD_REJECTION = /claude_code_version_too_old|does not support this model; version (\d+\.\d+\.\d+) or newer/i;
|
|
15
|
-
export function compareClaudeCodeVersions(a, b) {
|
|
16
|
-
const left = a.split(".").map(Number);
|
|
17
|
-
const right = b.split(".").map(Number);
|
|
18
|
-
for (let i = 0; i < 3; i++) {
|
|
19
|
-
const diff = (left[i] ?? 0) - (right[i] ?? 0);
|
|
20
|
-
if (diff !== 0)
|
|
21
|
-
return diff;
|
|
22
|
-
}
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
25
|
-
function isExactSemver(value) {
|
|
26
|
-
return typeof value === "string" && EXACT_SEMVER.test(value);
|
|
27
|
-
}
|
|
28
|
-
function highest(candidates) {
|
|
29
|
-
let best;
|
|
30
|
-
for (const candidate of candidates) {
|
|
31
|
-
if (!isExactSemver(candidate))
|
|
32
|
-
continue;
|
|
33
|
-
if (best === undefined || compareClaudeCodeVersions(candidate, best) > 0)
|
|
34
|
-
best = candidate;
|
|
35
|
-
}
|
|
36
|
-
return best;
|
|
37
|
-
}
|
|
38
|
-
async function fetchText(fetchImpl, url) {
|
|
39
|
-
try {
|
|
40
|
-
const response = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
41
|
-
return response.ok ? await response.text() : undefined;
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
// Offline, DNS failure, or timeout: the caller keeps the floor or the cached value.
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
async function fetchReleaseChannel(fetchImpl) {
|
|
49
|
-
const text = await fetchText(fetchImpl, CLAUDE_RELEASE_CHANNEL_URL);
|
|
50
|
-
return text === undefined ? undefined : EMBEDDED_SEMVER.exec(text.trim())?.[1];
|
|
51
|
-
}
|
|
52
|
-
async function fetchNpmDistTag(fetchImpl) {
|
|
53
|
-
const text = await fetchText(fetchImpl, CLAUDE_NPM_DIST_TAG_URL);
|
|
54
|
-
if (text === undefined)
|
|
55
|
-
return undefined;
|
|
56
|
-
try {
|
|
57
|
-
const data = JSON.parse(text);
|
|
58
|
-
const version = typeof data === "object" && data !== null && "version" in data ? data.version : undefined;
|
|
59
|
-
return typeof version === "string" ? EMBEDDED_SEMVER.exec(version)?.[1] : undefined;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// A registry error page is not a dist-tag document.
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Latest published Claude Code version: the higher of the native-installer `latest` channel and
|
|
68
|
-
* the npm dist-tag, so one lagging or unavailable source cannot hold the fingerprint back.
|
|
69
|
-
*/
|
|
70
|
-
export async function fetchLatestClaudeCodeVersion(fetchImpl = fetch) {
|
|
71
|
-
return highest(await Promise.all([fetchReleaseChannel(fetchImpl), fetchNpmDistTag(fetchImpl)]));
|
|
72
|
-
}
|
|
73
|
-
export function requiredClaudeCodeVersionFromError(message) {
|
|
74
|
-
const match = TOO_OLD_REJECTION.exec(message);
|
|
75
|
-
if (!match)
|
|
76
|
-
return undefined;
|
|
77
|
-
return match[1] ?? /version (\d+\.\d+\.\d+) or newer/i.exec(message)?.[1];
|
|
78
|
-
}
|
|
79
|
-
export function isClaudeCodeVersionTooOldError(error) {
|
|
80
|
-
return error instanceof Error && "status" in error && error.status === 400 && TOO_OLD_REJECTION.test(error.message);
|
|
81
|
-
}
|
|
82
|
-
export function createClaudeCodeVersionResolver(options) {
|
|
83
|
-
const { floor, store } = options;
|
|
84
|
-
const offline = options.offline === true;
|
|
85
|
-
const fetchImpl = options.fetch ?? fetch;
|
|
86
|
-
const now = options.now ?? Date.now;
|
|
87
|
-
const refreshIntervalMs = options.refreshIntervalMs ?? REFRESH_INTERVAL_MS;
|
|
88
|
-
const pinned = isExactSemver(options.pinned) ? options.pinned : undefined;
|
|
89
|
-
let loaded = false;
|
|
90
|
-
let resolved;
|
|
91
|
-
let checkedAt = 0;
|
|
92
|
-
let inflight;
|
|
93
|
-
const current = () => resolved !== undefined && compareClaudeCodeVersions(resolved, floor) > 0 ? resolved : floor;
|
|
94
|
-
const loadCache = () => {
|
|
95
|
-
if (loaded || store === null)
|
|
96
|
-
return;
|
|
97
|
-
loaded = true;
|
|
98
|
-
const record = store.load();
|
|
99
|
-
if (record && isExactSemver(record.version) && Number.isFinite(record.checkedAt)) {
|
|
100
|
-
resolved = record.version;
|
|
101
|
-
checkedAt = record.checkedAt;
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
const persist = () => {
|
|
105
|
-
if (store !== null && resolved !== undefined)
|
|
106
|
-
store.save({ version: resolved, checkedAt });
|
|
107
|
-
};
|
|
108
|
-
const refresh = () => {
|
|
109
|
-
if (pinned !== undefined || store === null)
|
|
110
|
-
return Promise.resolve(pinned ?? current());
|
|
111
|
-
loadCache();
|
|
112
|
-
if (offline)
|
|
113
|
-
return Promise.resolve(current());
|
|
114
|
-
inflight ??= (async () => {
|
|
115
|
-
try {
|
|
116
|
-
const latest = await fetchLatestClaudeCodeVersion(fetchImpl);
|
|
117
|
-
// A failed lookup still counts as a check: an offline host waits a full interval
|
|
118
|
-
// before trying again instead of retrying on every request.
|
|
119
|
-
checkedAt = now();
|
|
120
|
-
if (latest !== undefined && (resolved === undefined || compareClaudeCodeVersions(latest, resolved) > 0)) {
|
|
121
|
-
resolved = latest;
|
|
122
|
-
}
|
|
123
|
-
persist();
|
|
124
|
-
}
|
|
125
|
-
finally {
|
|
126
|
-
inflight = undefined;
|
|
127
|
-
}
|
|
128
|
-
return current();
|
|
129
|
-
})();
|
|
130
|
-
return inflight;
|
|
131
|
-
};
|
|
132
|
-
return {
|
|
133
|
-
get() {
|
|
134
|
-
if (pinned !== undefined)
|
|
135
|
-
return pinned;
|
|
136
|
-
if (store === null)
|
|
137
|
-
return current();
|
|
138
|
-
loadCache();
|
|
139
|
-
if (!offline && inflight === undefined && now() - checkedAt >= refreshIntervalMs)
|
|
140
|
-
void refresh();
|
|
141
|
-
return current();
|
|
142
|
-
},
|
|
143
|
-
refresh,
|
|
144
|
-
raise(version) {
|
|
145
|
-
if (pinned !== undefined)
|
|
146
|
-
return pinned;
|
|
147
|
-
loadCache();
|
|
148
|
-
if (isExactSemver(version) && compareClaudeCodeVersions(version, current()) > 0) {
|
|
149
|
-
resolved = version;
|
|
150
|
-
persist();
|
|
151
|
-
}
|
|
152
|
-
return current();
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
let installedStore = null;
|
|
157
|
-
let installedOffline = false;
|
|
158
|
-
let defaultResolver;
|
|
159
|
-
let defaultFloor;
|
|
160
|
-
/**
|
|
161
|
-
* Hosts with a filesystem install their cache here once at startup (see
|
|
162
|
-
* `utils/claude-code-version-cache.ts`); until then, and in browsers, the resolver answers
|
|
163
|
-
* the floor without touching the network.
|
|
164
|
-
*/
|
|
165
|
-
export function installClaudeCodeVersionStore(store, options = {}) {
|
|
166
|
-
installedStore = store;
|
|
167
|
-
installedOffline = options.offline === true;
|
|
168
|
-
defaultResolver = undefined;
|
|
169
|
-
}
|
|
170
|
-
function resolver(floor) {
|
|
171
|
-
if (defaultResolver === undefined || defaultFloor !== floor) {
|
|
172
|
-
defaultFloor = floor;
|
|
173
|
-
defaultResolver = createClaudeCodeVersionResolver({ floor, store: installedStore, offline: installedOffline });
|
|
174
|
-
}
|
|
175
|
-
return defaultResolver;
|
|
176
|
-
}
|
|
177
|
-
function pinnedClaudeCodeVersion(env) {
|
|
178
|
-
const pin = getProviderEnvValue(CLAUDE_CODE_VERSION_PIN_ENV, env)?.trim();
|
|
179
|
-
return isExactSemver(pin) ? pin : undefined;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* The version the next OAuth request signs with. `floor` is the bundled Claude Code version the
|
|
183
|
-
* caller declares (the `claudeCodeVersion` constant in `api/anthropic-messages.ts`).
|
|
184
|
-
*/
|
|
185
|
-
export function getClaudeCodeVersion(floor, env) {
|
|
186
|
-
return pinnedClaudeCodeVersion(env) ?? resolver(floor).get();
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* After a `claude_code_version_too_old` rejection: adopt the version the error names, or the
|
|
190
|
-
* latest published one, and report the fingerprint to retry with; `undefined` when nothing
|
|
191
|
-
* newer is available (pinned, or already at the required version).
|
|
192
|
-
*/
|
|
193
|
-
export async function recoverClaudeCodeVersion(error, floor, advertised, env) {
|
|
194
|
-
if (pinnedClaudeCodeVersion(env) !== undefined)
|
|
195
|
-
return undefined;
|
|
196
|
-
const required = requiredClaudeCodeVersionFromError(error.message);
|
|
197
|
-
const next = required === undefined ? await resolver(floor).refresh() : resolver(floor).raise(required);
|
|
198
|
-
return compareClaudeCodeVersions(next, advertised) > 0 ? next : undefined;
|
|
199
|
-
}
|
|
200
|
-
export function claudeCodeVersionTooOldHint(advertised) {
|
|
201
|
-
return `senpi advertised claude-cli/${advertised}; Anthropic requires a newer Claude Code for this model. senpi refreshes the version automatically when online; set ${CLAUDE_CODE_VERSION_PIN_ENV}=X.Y.Z to advertise a specific one.`;
|
|
202
|
-
}
|
|
203
|
-
//# sourceMappingURL=claude-code-version.js.map
|