@code-yeongyu/senpi-ai 2026.11.9 → 2026.11.10-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/api/openai-responses-prompt-cache.d.ts +1 -1
- package/dist/api/openai-responses.js +1 -1
- package/dist/cursor/capability-table.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/openai-responses-compat.d.ts +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/meta.json +1 -1
- package/dist/providers/data/opencode-go.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/openai-prompt-cache-lane.d.ts +14 -0
- package/dist/utils/openai-prompt-cache-lane.js +58 -0
- package/dist/utils/prompt-cache-ttl.d.ts +7 -4
- package/dist/utils/prompt-cache-ttl.js +12 -22
- package/dist/utils/retry-hint.js +4 -1
- package/dist/utils/validation.js +79 -0
- package/package.json +2 -2
- package/dist/utils/fable55-launch.d.ts +0 -21
- package/dist/utils/fable55-launch.js +0 -37
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Api, CacheRetention, Model } from "../types.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Which OpenAI prompt-cache contract a Responses-lane request runs under
|
|
4
|
+
* (https://developers.openai.com/api/docs/guides/prompt-caching, "Cache lifetime"):
|
|
5
|
+
*
|
|
6
|
+
* - `chatgpt-subscription`: signed-in ChatGPT usage (Codex backend or Sign in with ChatGPT). OpenAI keeps this
|
|
7
|
+
* cache with no expiry (senpi#6290); no API doc publishes a lifetime, so it carries no TTL to schedule around.
|
|
8
|
+
* - `api-long`: GPT-5.6+ on a request that sends `prompt_cache_options.ttl: "12h"` (12-hour minimum lifetime).
|
|
9
|
+
* - `api-extended`: GPT-5.6+ at the default `"30m"` minimum lifetime.
|
|
10
|
+
* - `api-short`: earlier models, and gateways that proxy GPT-5.6+ ids without OpenAI's contract.
|
|
11
|
+
*/
|
|
12
|
+
export type OpenAIPromptCacheLane = "chatgpt-subscription" | "api-long" | "api-extended" | "api-short";
|
|
13
|
+
export declare function classifyOpenAIPromptCacheLane(model: Model<Api>, retention: CacheRetention): OpenAIPromptCacheLane;
|
|
14
|
+
//# sourceMappingURL=openai-prompt-cache-lane.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** GPT-5.6 and later (`gpt-5.6-*`, `gpt-5.10`, `gpt-6-*`, `gpt-7`, ...). */
|
|
2
|
+
const OPENAI_EXTENDED_CACHE_MODEL_ID = /^gpt-(?:5\.(?:[6-9]|\d{2,})|(?:[6-9]|\d{2,})(?:\.\d+)?)(?:-|$)/i;
|
|
3
|
+
/** The Codex backend serves only signed-in ChatGPT usage, whatever provider id a models.json entry gives it. */
|
|
4
|
+
const CHATGPT_CODEX_BACKEND_HOST = "chatgpt.com";
|
|
5
|
+
/** Sign in with ChatGPT routes plan usage to the API host, so only the `siwc` compat flag tells it from an API key. */
|
|
6
|
+
const SIWC_HOST = "api.openai.com";
|
|
7
|
+
function hostnameOf(baseUrl) {
|
|
8
|
+
try {
|
|
9
|
+
return new URL(baseUrl).hostname.toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function responsesCompat(model) {
|
|
16
|
+
return model.compat;
|
|
17
|
+
}
|
|
18
|
+
function isChatGptSubscription(model) {
|
|
19
|
+
const host = hostnameOf(model.baseUrl);
|
|
20
|
+
if (model.api === "openai-codex-responses")
|
|
21
|
+
return host === CHATGPT_CODEX_BACKEND_HOST;
|
|
22
|
+
return model.api === "openai-responses" && host === SIWC_HOST && responsesCompat(model)?.siwc === true;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The OpenAI-operated Responses lanes serving a GPT-5.6+ model, where OpenAI documents a cache lifetime of at
|
|
26
|
+
* least 30 minutes. Gateways that merely proxy the same model ids keep the short lifetime: their routing does
|
|
27
|
+
* not carry that contract.
|
|
28
|
+
*/
|
|
29
|
+
function hasExtendedPromptCache(model) {
|
|
30
|
+
if (model.api === "openai-responses") {
|
|
31
|
+
if (responsesCompat(model)?.supportsExplicitPromptCacheMode === true)
|
|
32
|
+
return true;
|
|
33
|
+
if (model.provider !== "openai" && hostnameOf(model.baseUrl) !== "api.openai.com")
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return OPENAI_EXTENDED_CACHE_MODEL_ID.test(model.id);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mirrors the `openai-responses` adapter's `getPromptCacheOptions()`: `"12h"` is sent only on `long` retention,
|
|
40
|
+
* to a model that accepts `prompt_cache_options` outside Sign in with ChatGPT, unless compat opts out of long
|
|
41
|
+
* retention. Azure and Codex-protocol requests carry no `prompt_cache_options`.
|
|
42
|
+
*/
|
|
43
|
+
function sendsTwelveHourTtl(model, retention) {
|
|
44
|
+
const compat = responsesCompat(model);
|
|
45
|
+
return (retention === "long" &&
|
|
46
|
+
model.api === "openai-responses" &&
|
|
47
|
+
compat?.siwc !== true &&
|
|
48
|
+
compat?.supportsExplicitPromptCacheMode === true &&
|
|
49
|
+
compat.supportsLongCacheRetention !== false);
|
|
50
|
+
}
|
|
51
|
+
export function classifyOpenAIPromptCacheLane(model, retention) {
|
|
52
|
+
if (isChatGptSubscription(model))
|
|
53
|
+
return "chatgpt-subscription";
|
|
54
|
+
if (sendsTwelveHourTtl(model, retention))
|
|
55
|
+
return "api-long";
|
|
56
|
+
return hasExtendedPromptCache(model) ? "api-extended" : "api-short";
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=openai-prompt-cache-lane.js.map
|
|
@@ -2,16 +2,19 @@ import type { AnthropicMessagesCompat, Api, Model, OpenAICompletionsCompat, Prov
|
|
|
2
2
|
export declare const PROMPT_CACHE_TTL_SHORT_SECONDS = 300;
|
|
3
3
|
export declare const PROMPT_CACHE_TTL_LONG_SECONDS = 3600;
|
|
4
4
|
/**
|
|
5
|
-
* OpenAI GPT-5.6 and later: `prompt_cache_options.ttl
|
|
6
|
-
*
|
|
5
|
+
* OpenAI GPT-5.6 and later: the default `prompt_cache_options.ttl: "30m"` keeps the cache eligible at least
|
|
6
|
+
* 30 minutes after the latest write or reuse.
|
|
7
7
|
*/
|
|
8
8
|
export declare const PROMPT_CACHE_TTL_OPENAI_EXTENDED_SECONDS = 1800;
|
|
9
|
+
/** OpenAI GPT-5.6 and later on the Responses API: `prompt_cache_options.ttl: "12h"`, a 12-hour minimum lifetime. */
|
|
10
|
+
export declare const PROMPT_CACHE_TTL_OPENAI_LONG_SECONDS = 43200;
|
|
9
11
|
/**
|
|
10
12
|
* How long a provider promises to keep a prompt prefix cached.
|
|
11
13
|
*
|
|
12
14
|
* - `ttl`: an explicit expiry contract; `ttlSeconds` is the conservative lifetime after the last write or reuse.
|
|
13
|
-
* - `best-effort`: the provider caches automatically
|
|
14
|
-
* after hours to days
|
|
15
|
+
* - `best-effort`: the provider caches automatically with no expiry senpi can schedule around (direct DeepSeek
|
|
16
|
+
* clears unused entries after hours to days; signed-in ChatGPT keeps its cache with no expiry), so nothing needs
|
|
17
|
+
* to wake or ping solely to preserve the cache.
|
|
15
18
|
* - `none`: caching is disabled or the lane has no known cache contract.
|
|
16
19
|
*/
|
|
17
20
|
export type PromptCacheLifetime = {
|
|
@@ -1,16 +1,25 @@
|
|
|
1
|
+
import { classifyOpenAIPromptCacheLane } from "./openai-prompt-cache-lane.js";
|
|
1
2
|
import { getProviderEnvValue } from "./provider-env.js";
|
|
2
3
|
export const PROMPT_CACHE_TTL_SHORT_SECONDS = 300;
|
|
3
4
|
export const PROMPT_CACHE_TTL_LONG_SECONDS = 3600;
|
|
4
5
|
/**
|
|
5
|
-
* OpenAI GPT-5.6 and later: `prompt_cache_options.ttl
|
|
6
|
-
*
|
|
6
|
+
* OpenAI GPT-5.6 and later: the default `prompt_cache_options.ttl: "30m"` keeps the cache eligible at least
|
|
7
|
+
* 30 minutes after the latest write or reuse.
|
|
7
8
|
*/
|
|
8
9
|
export const PROMPT_CACHE_TTL_OPENAI_EXTENDED_SECONDS = 1800;
|
|
10
|
+
/** OpenAI GPT-5.6 and later on the Responses API: `prompt_cache_options.ttl: "12h"`, a 12-hour minimum lifetime. */
|
|
11
|
+
export const PROMPT_CACHE_TTL_OPENAI_LONG_SECONDS = 43_200;
|
|
9
12
|
const NO_PROMPT_CACHE = { kind: "none" };
|
|
10
13
|
const BEST_EFFORT_PROMPT_CACHE = { kind: "best-effort" };
|
|
11
14
|
function ttl(ttlSeconds) {
|
|
12
15
|
return { kind: "ttl", ttlSeconds };
|
|
13
16
|
}
|
|
17
|
+
const OPENAI_LANE_PROMPT_CACHE_LIFETIME = {
|
|
18
|
+
"chatgpt-subscription": BEST_EFFORT_PROMPT_CACHE,
|
|
19
|
+
"api-long": ttl(PROMPT_CACHE_TTL_OPENAI_LONG_SECONDS),
|
|
20
|
+
"api-extended": ttl(PROMPT_CACHE_TTL_OPENAI_EXTENDED_SECONDS),
|
|
21
|
+
"api-short": ttl(PROMPT_CACHE_TTL_SHORT_SECONDS),
|
|
22
|
+
};
|
|
14
23
|
function hostnameOf(baseUrl) {
|
|
15
24
|
try {
|
|
16
25
|
return new URL(baseUrl).hostname.toLowerCase();
|
|
@@ -333,23 +342,6 @@ function resolveOpenAIResponsesCacheRetention(cacheRetention, env) {
|
|
|
333
342
|
function isDirectDeepSeekModel(model) {
|
|
334
343
|
return model.provider === "deepseek" || hostnameOf(model.baseUrl) === "api.deepseek.com";
|
|
335
344
|
}
|
|
336
|
-
/** GPT-5.6 and later (`gpt-5.6-*`, `gpt-5.10`, `gpt-6-*`, `gpt-7`, ...). */
|
|
337
|
-
const OPENAI_EXTENDED_CACHE_MODEL_ID = /^gpt-(?:5\.(?:[6-9]|\d{2,})|(?:[6-9]|\d{2,})(?:\.\d+)?)(?:-|$)/i;
|
|
338
|
-
/**
|
|
339
|
-
* The OpenAI-operated Responses lanes (OpenAI API, Azure OpenAI, ChatGPT subscription) serving a GPT-5.6+
|
|
340
|
-
* model, where OpenAI documents a cache lifetime of at least 30 minutes. Gateways that merely proxy the same
|
|
341
|
-
* model ids keep the conservative short lifetime because their routing does not carry that contract.
|
|
342
|
-
*/
|
|
343
|
-
function hasOpenAIExtendedPromptCache(model) {
|
|
344
|
-
if (model.api === "openai-responses") {
|
|
345
|
-
const responsesModel = model;
|
|
346
|
-
if (responsesModel.compat?.supportsExplicitPromptCacheMode === true)
|
|
347
|
-
return true;
|
|
348
|
-
if (responsesModel.provider !== "openai" && hostnameOf(responsesModel.baseUrl) !== "api.openai.com")
|
|
349
|
-
return false;
|
|
350
|
-
}
|
|
351
|
-
return OPENAI_EXTENDED_CACHE_MODEL_ID.test(model.id);
|
|
352
|
-
}
|
|
353
345
|
/** Env that puts Claude Code on API-key, gateway or cloud billing, where it caches the main conversation for 5 minutes. */
|
|
354
346
|
const CLAUDE_CODE_API_BILLING_ENV = [
|
|
355
347
|
"ANTHROPIC_API_KEY",
|
|
@@ -429,9 +421,7 @@ export function resolvePromptCacheLifetime(model, env) {
|
|
|
429
421
|
const retention = resolveOpenAIResponsesCacheRetention(model.cacheRetention, env);
|
|
430
422
|
if (retention === "none")
|
|
431
423
|
return NO_PROMPT_CACHE;
|
|
432
|
-
return
|
|
433
|
-
? ttl(PROMPT_CACHE_TTL_OPENAI_EXTENDED_SECONDS)
|
|
434
|
-
: ttl(PROMPT_CACHE_TTL_SHORT_SECONDS);
|
|
424
|
+
return OPENAI_LANE_PROMPT_CACHE_LIFETIME[classifyOpenAIPromptCacheLane(model, retention)];
|
|
435
425
|
}
|
|
436
426
|
default:
|
|
437
427
|
return NO_PROMPT_CACHE;
|
package/dist/utils/retry-hint.js
CHANGED
|
@@ -239,7 +239,10 @@ export function parseRetryAfterMsMarker(message) {
|
|
|
239
239
|
/* ---------- wall-clock reset prose ---------- */
|
|
240
240
|
// A reset written as a wall clock: "resets 12am (Asia/Seoul)", "resets Oct 2, 9am", "try again at 12:00 AM".
|
|
241
241
|
// Shared with the credential pool (reset-time.ts) so both read the text the same way (senpi#1771). Milliseconds
|
|
242
|
-
// from `nowMs` to the next such moment, or undefined
|
|
242
|
+
// from `nowMs` to the next such moment, or undefined.
|
|
243
|
+
// Zone rule (senpi#5097): a time with no zone reads in the host's local zone, for every caller, as the user's own
|
|
244
|
+
// clock. A reset in another zone is read correctly only when the text names it ("(UTC)", "(Asia/Seoul)"); a
|
|
245
|
+
// zone-less time far from the truth only makes the hint long, and long hints already defer or fail over.
|
|
243
246
|
const MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
244
247
|
const CLOCK_RE = /\b(?:resets?|try again)\s+(?:at\s+|on\s+)?(?:([a-z]{3})[a-z]*\.?\s+(\d{1,2}),?\s+(?:at\s+)?)?(\d{1,2})(?::(\d{2}))?\s*([ap])\.?\s?m\b\.?(?:\s*\(([A-Za-z_]+(?:\/[A-Za-z0-9_+-]+)*)\))?/i;
|
|
245
248
|
export function clockResetMs(text, nowMs) {
|
package/dist/utils/validation.js
CHANGED
|
@@ -164,6 +164,84 @@ function normalizeOptionalNulls(value, schema) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
+
/** JSON types a schema accepts, or undefined when its shape does not say (const/enum/$ref/allOf). */
|
|
168
|
+
function acceptedJsonTypes(schema) {
|
|
169
|
+
const types = getSchemaTypes(schema);
|
|
170
|
+
if (types.length > 0)
|
|
171
|
+
return new Set(types);
|
|
172
|
+
const members = schema.anyOf ?? schema.oneOf;
|
|
173
|
+
if (!Array.isArray(members) || members.length === 0)
|
|
174
|
+
return undefined;
|
|
175
|
+
const accepted = new Set();
|
|
176
|
+
for (const member of members) {
|
|
177
|
+
const memberTypes = acceptedJsonTypes(member);
|
|
178
|
+
if (memberTypes === undefined)
|
|
179
|
+
return undefined;
|
|
180
|
+
for (const type of memberTypes)
|
|
181
|
+
accepted.add(type);
|
|
182
|
+
}
|
|
183
|
+
return accepted;
|
|
184
|
+
}
|
|
185
|
+
function parseJsonStructure(text, accepted) {
|
|
186
|
+
const trimmed = text.trim();
|
|
187
|
+
const wantsArray = accepted.has("array") && trimmed.startsWith("[");
|
|
188
|
+
const wantsObject = accepted.has("object") && trimmed.startsWith("{");
|
|
189
|
+
if (!wantsArray && !wantsObject)
|
|
190
|
+
return undefined;
|
|
191
|
+
try {
|
|
192
|
+
const parsed = JSON.parse(trimmed);
|
|
193
|
+
if (wantsArray && Array.isArray(parsed))
|
|
194
|
+
return parsed;
|
|
195
|
+
if (wantsObject && matchesJsonType(parsed, "object"))
|
|
196
|
+
return parsed;
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (!(error instanceof SyntaxError))
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Models sometimes send an array or object argument as its JSON text (senpi#6265: the later calls of a
|
|
206
|
+
* parallel generate_image turn carried `reference_image_paths` as `'["/a.png"]'`). Value.Convert would
|
|
207
|
+
* wrap that text into a one-element array that passes validation, so the tool ran with the JSON text
|
|
208
|
+
* as a path. Decode the text back to the structure the schema declares before conversion, only where
|
|
209
|
+
* the schema rejects strings and the text parses to that declared array/object.
|
|
210
|
+
*/
|
|
211
|
+
function decodeJsonEncodedStructures(value, schema) {
|
|
212
|
+
if (typeof value === "string") {
|
|
213
|
+
const accepted = acceptedJsonTypes(schema);
|
|
214
|
+
if (accepted === undefined || accepted.has("string"))
|
|
215
|
+
return value;
|
|
216
|
+
const decoded = parseJsonStructure(value, accepted);
|
|
217
|
+
return decoded === undefined ? value : decodeJsonEncodedStructures(decoded, schema);
|
|
218
|
+
}
|
|
219
|
+
const types = getSchemaTypes(schema);
|
|
220
|
+
if (Array.isArray(value) && types.includes("array")) {
|
|
221
|
+
const items = schema.items;
|
|
222
|
+
for (let index = 0; index < value.length; index++) {
|
|
223
|
+
const itemSchema = Array.isArray(items) ? items[index] : items;
|
|
224
|
+
if (itemSchema)
|
|
225
|
+
value[index] = decodeJsonEncodedStructures(value[index], itemSchema);
|
|
226
|
+
}
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
if (matchesJsonType(value, "object") && types.includes("object")) {
|
|
230
|
+
const record = value;
|
|
231
|
+
const properties = schema.properties ?? {};
|
|
232
|
+
const additional = schema.additionalProperties;
|
|
233
|
+
for (const key of Object.keys(record)) {
|
|
234
|
+
const propertySchema = Object.hasOwn(properties, key)
|
|
235
|
+
? properties[key]
|
|
236
|
+
: typeof additional === "object"
|
|
237
|
+
? additional
|
|
238
|
+
: undefined;
|
|
239
|
+
if (propertySchema)
|
|
240
|
+
record[key] = decodeJsonEncodedStructures(record[key], propertySchema);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
167
245
|
function getValidator(schema) {
|
|
168
246
|
const key = schema;
|
|
169
247
|
const cached = validatorCache.get(key);
|
|
@@ -324,6 +402,7 @@ export function validateToolArguments(tool, toolCall) {
|
|
|
324
402
|
return args;
|
|
325
403
|
}
|
|
326
404
|
normalizeOptionalNulls(args, tool.parameters);
|
|
405
|
+
decodeJsonEncodedStructures(args, tool.parameters);
|
|
327
406
|
Value.Convert(tool.parameters, args);
|
|
328
407
|
const validator = getValidator(tool.parameters);
|
|
329
408
|
if (!Object.getOwnPropertySymbols(tool.parameters).includes(TYPEBOX_KIND)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-ai",
|
|
3
|
-
"version": "2026.11.
|
|
3
|
+
"version": "2026.11.10-1",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@anthropic-ai/sdk": "0.127.0",
|
|
90
90
|
"@aws-sdk/client-bedrock-runtime": "3.1136.0",
|
|
91
|
-
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.11.
|
|
91
|
+
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.11.10-1",
|
|
92
92
|
"@google/genai": "2.23.0",
|
|
93
93
|
"@smithy/node-http-handler": "4.12.1",
|
|
94
94
|
"google-auth-library": "10.6.2",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Launch-day edit block. Fable 5.5 is UNRELEASED; these ids are provisional.
|
|
3
|
-
* Confirm identity, optional snapshot and Claude Code floor from live evidence.
|
|
4
|
-
* Prices, context/output limits and status/deprecation come ONLY from models.dev
|
|
5
|
-
* during regeneration, never from a local guessed price card or catalog row.
|
|
6
|
-
* Keep recommendations disabled unless the optional promotion commit is wanted.
|
|
7
|
-
*/
|
|
8
|
-
export declare const FABLE55_LAUNCH: {
|
|
9
|
-
readonly modelId: "claude-fable-5-5";
|
|
10
|
-
readonly mythosModelId: "claude-mythos-5-5";
|
|
11
|
-
readonly snapshotId: string | null;
|
|
12
|
-
readonly minimumClaudeCodeVersion: string | null;
|
|
13
|
-
readonly released: false;
|
|
14
|
-
readonly promoteDefaults: false;
|
|
15
|
-
/** Server-side refusal fallbacks. Fable 5.1 baseline until Anthropic's launch docs name the 5.5 list. */
|
|
16
|
-
readonly refusalFallbackModels: readonly string[];
|
|
17
|
-
readonly metadataSource: "models.dev";
|
|
18
|
-
};
|
|
19
|
-
/** Carry the existing Fable/Mythos routing convention, including gateway spellings. */
|
|
20
|
-
export declare function isFable55ModelId(modelId: string): boolean;
|
|
21
|
-
//# sourceMappingURL=fable55-launch.d.ts.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Launch-day edit block. Fable 5.5 is UNRELEASED; these ids are provisional.
|
|
3
|
-
* Confirm identity, optional snapshot and Claude Code floor from live evidence.
|
|
4
|
-
* Prices, context/output limits and status/deprecation come ONLY from models.dev
|
|
5
|
-
* during regeneration, never from a local guessed price card or catalog row.
|
|
6
|
-
* Keep recommendations disabled unless the optional promotion commit is wanted.
|
|
7
|
-
*/
|
|
8
|
-
export const FABLE55_LAUNCH = {
|
|
9
|
-
modelId: "claude-fable-5-5",
|
|
10
|
-
mythosModelId: "claude-mythos-5-5",
|
|
11
|
-
snapshotId: null,
|
|
12
|
-
minimumClaudeCodeVersion: null,
|
|
13
|
-
released: false,
|
|
14
|
-
promoteDefaults: false,
|
|
15
|
-
/** Server-side refusal fallbacks. Fable 5.1 baseline until Anthropic's launch docs name the 5.5 list. */
|
|
16
|
-
refusalFallbackModels: ["claude-opus-4-8", "claude-opus-5"],
|
|
17
|
-
metadataSource: "models.dev",
|
|
18
|
-
};
|
|
19
|
-
/** Carry the existing Fable/Mythos routing convention, including gateway spellings. */
|
|
20
|
-
export function isFable55ModelId(modelId) {
|
|
21
|
-
const normalized = modelId.toLowerCase().replace(/\s+/g, "-");
|
|
22
|
-
return [FABLE55_LAUNCH.modelId, FABLE55_LAUNCH.mythosModelId, FABLE55_LAUNCH.snapshotId].some((id) => {
|
|
23
|
-
if (!id)
|
|
24
|
-
return false;
|
|
25
|
-
const family = id.replace(/^claude-/, "");
|
|
26
|
-
const dotted = family.replace(/-(\d+)-(\d+)$/, "-$1.$2");
|
|
27
|
-
return [family, dotted].some((marker) => {
|
|
28
|
-
const at = normalized.indexOf(marker);
|
|
29
|
-
if (at < 0)
|
|
30
|
-
return false;
|
|
31
|
-
const before = normalized[at - 1];
|
|
32
|
-
const after = normalized[at + marker.length];
|
|
33
|
-
return (!before || /[/@:._-]/.test(before)) && (!after || /[/@:._-]/.test(after));
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=fable55-launch.js.map
|