@code-yeongyu/senpi-ai 2026.10.20-1 → 2026.10.21-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.js +1 -1
- package/dist/api/azure-openai-responses.js +2 -2
- package/dist/api/cursor-agent.js +2 -6
- package/dist/api/google-generative-ai.js +3 -1
- package/dist/api/google-vertex.js +3 -1
- package/dist/api/openai-codex-responses.js +4 -4
- package/dist/api/openai-completions.js +3 -1
- package/dist/api/openai-prompt-cache.d.ts +3 -0
- package/dist/api/openai-prompt-cache.js +22 -0
- package/dist/api/openai-responses-shared.js +5 -2
- package/dist/api/openai-responses.js +4 -7
- package/dist/auth/pool/kinds.d.ts +17 -0
- package/dist/auth/pool/kinds.js +32 -0
- package/dist/auth/pool/slots.d.ts +1 -1
- package/dist/auth/pool/slots.js +4 -1
- package/dist/cursor/capability-table.d.ts +10 -0
- package/dist/cursor/capability-table.js +183 -0
- package/dist/cursor/catalog-grouping.js +4 -26
- package/dist/cursor/display-name.d.ts +31 -0
- package/dist/cursor/display-name.js +48 -0
- package/dist/cursor/model-capabilities.d.ts +3 -10
- package/dist/cursor/model-capabilities.js +2 -154
- package/dist/cursor/model-input.d.ts +2 -0
- package/dist/cursor/model-input.js +11 -0
- package/dist/cursor/selection-descriptor.js +1 -0
- package/dist/model.d.ts +2 -0
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/cerebras.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/groq.json +1 -1
- package/dist/providers/data/huggingface.json +1 -1
- package/dist/providers/data/nvidia.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/together.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 +31 -0
- package/dist/utils/github-copilot-tool-limit.d.ts +1 -1
- package/dist/utils/github-copilot-tool-limit.js +24 -1
- package/dist/utils/provider-diagnostic-sources.d.ts +2 -1
- package/dist/utils/provider-diagnostic-sources.js +14 -2
- package/dist/utils/reported-count.d.ts +6 -0
- package/dist/utils/reported-count.js +8 -0
- package/package.json +2 -2
|
@@ -75,7 +75,7 @@ function getCacheControl(model, cacheRetention, env) {
|
|
|
75
75
|
// The bundled Claude Code version and the floor of the advertised `claude-cli/<version>`
|
|
76
76
|
// (see utils/claude-code-version.ts). Keep this exact declaration: a downstream installer
|
|
77
77
|
// (oh-my-openagent) rewrites it byte-for-byte in the installed dist and bundle.
|
|
78
|
-
const claudeCodeVersion = "2.1.
|
|
78
|
+
const claudeCodeVersion = "2.1.306";
|
|
79
79
|
// Claude Code 2.x tool names (canonical casing)
|
|
80
80
|
// Source: https://cchistory.mariozechner.at/data/prompts-2.1.11.md
|
|
81
81
|
// To update: https://github.com/badlogic/cchistory
|
|
@@ -8,7 +8,7 @@ import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
|
8
8
|
import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
9
9
|
import { getDeclaredTools, resolveTranscript, resolveTranscriptTools } from "../utils/transcript.js";
|
|
10
10
|
import { createGrammarToolInputProperties } from "./constrained-sampling.js";
|
|
11
|
-
import {
|
|
11
|
+
import { deriveOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
12
12
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
|
|
13
13
|
import { buildBaseOptions } from "./simple-options.js";
|
|
14
14
|
const DEFAULT_AZURE_API_VERSION = "v1";
|
|
@@ -233,7 +233,7 @@ function buildParams(model, context, options, deploymentName, grammarToolInputPr
|
|
|
233
233
|
stream: true,
|
|
234
234
|
...((options?.cacheRetention ?? model.cacheRetention) === "none"
|
|
235
235
|
? {}
|
|
236
|
-
: { prompt_cache_key:
|
|
236
|
+
: { prompt_cache_key: deriveOpenAIPromptCacheKey(model.id, context) }),
|
|
237
237
|
store: false,
|
|
238
238
|
};
|
|
239
239
|
if (options?.maxTokens) {
|
package/dist/api/cursor-agent.js
CHANGED
|
@@ -20,6 +20,7 @@ import * as http2 from "node:http2";
|
|
|
20
20
|
import { create, fromBinary, fromJson, toBinary, toJson } from "@bufbuild/protobuf";
|
|
21
21
|
import { ValueSchema } from "@bufbuild/protobuf/wkt";
|
|
22
22
|
import { CURSOR_COMPOSER_PROMPT, isCursorComposerModel } from "../cursor/composer-prompt.js";
|
|
23
|
+
import { cursorDiscoveredInput } from "../cursor/model-input.js";
|
|
23
24
|
import { calculateCost } from "../models.js";
|
|
24
25
|
import { registerSessionResourceCleanup } from "../session-resources.js";
|
|
25
26
|
import { clearStreamingPartialJson, kCursorExecResolved, kStreamingBlockIndex, kStreamingBlockKind, kStreamingEnvelopeId, kStreamingLastParseLen, kStreamingPartialJson, } from "../utils/block-symbols.js";
|
|
@@ -3788,11 +3789,6 @@ const CURSOR_DEFAULT_MAX_TOKENS = 64_000;
|
|
|
3788
3789
|
const CURSOR_1M_CONTEXT_WINDOW = 1_000_000;
|
|
3789
3790
|
const CURSOR_1M_NAME_PATTERN = /\b1m\b/i;
|
|
3790
3791
|
const CURSOR_MAX_MODE_1M_ID_PATTERN = /claude|gemini/;
|
|
3791
|
-
/**
|
|
3792
|
-
* Model-id families whose native catalogs are multimodal. Cursor-only or
|
|
3793
|
-
* text-only families (`composer-*`, `grok-code-*`) stay outside this pattern.
|
|
3794
|
-
*/
|
|
3795
|
-
const CURSOR_MULTIMODAL_ID_PATTERN = /claude|gemini|gpt-|codex/;
|
|
3796
3792
|
/**
|
|
3797
3793
|
* Fetches Cursor models through `GetUsableModels` (unary protobuf over
|
|
3798
3794
|
* HTTP/2; the ALB rejects HTTP/1.1 with 464) and normalizes them.
|
|
@@ -3882,7 +3878,7 @@ export async function fetchCursorUsableModels(options) {
|
|
|
3882
3878
|
id,
|
|
3883
3879
|
name,
|
|
3884
3880
|
reasoning: Boolean(model.thinkingDetails),
|
|
3885
|
-
input:
|
|
3881
|
+
input: cursorDiscoveredInput(id),
|
|
3886
3882
|
contextWindow,
|
|
3887
3883
|
maxTokens: CURSOR_DEFAULT_MAX_TOKENS,
|
|
3888
3884
|
cursorMaxMode: maxMode,
|
|
@@ -4,6 +4,7 @@ import { formatProviderError, normalizeProviderError } from "../utils/error-body
|
|
|
4
4
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
5
5
|
import { providerHeadersToRecord } from "../utils/headers.js";
|
|
6
6
|
import { getPiUserAgent } from "../utils/pi-user-agent.js";
|
|
7
|
+
import { reportedCount } from "../utils/reported-count.js";
|
|
7
8
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
8
9
|
import { getSystemMessageText } from "../utils/text.js";
|
|
9
10
|
import { collapseSystemMessages, getCurrentTools, getInitialSystemMessage } from "../utils/transcript.js";
|
|
@@ -191,12 +192,13 @@ export const stream = (model, context, options) => {
|
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
if (chunk.usageMetadata) {
|
|
195
|
+
const reasoning = reportedCount(chunk.usageMetadata.thoughtsTokenCount);
|
|
194
196
|
output.usage = {
|
|
195
197
|
input: (chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),
|
|
196
198
|
output: (chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),
|
|
197
199
|
cacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,
|
|
198
200
|
cacheWrite: 0,
|
|
199
|
-
reasoning:
|
|
201
|
+
...(reasoning === undefined ? {} : { reasoning }),
|
|
200
202
|
totalTokens: chunk.usageMetadata.totalTokenCount || 0,
|
|
201
203
|
cost: {
|
|
202
204
|
input: 0,
|
|
@@ -5,6 +5,7 @@ import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
|
5
5
|
import { providerHeadersToRecord } from "../utils/headers.js";
|
|
6
6
|
import { getPiUserAgent } from "../utils/pi-user-agent.js";
|
|
7
7
|
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
8
|
+
import { reportedCount } from "../utils/reported-count.js";
|
|
8
9
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
9
10
|
import { getSystemMessageText } from "../utils/text.js";
|
|
10
11
|
import { collapseSystemMessages, getCurrentTools, getInitialSystemMessage } from "../utils/transcript.js";
|
|
@@ -195,12 +196,13 @@ export const stream = (model, context, options) => {
|
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
198
|
if (chunk.usageMetadata) {
|
|
199
|
+
const reasoning = reportedCount(chunk.usageMetadata.thoughtsTokenCount);
|
|
198
200
|
output.usage = {
|
|
199
201
|
input: (chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),
|
|
200
202
|
output: (chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),
|
|
201
203
|
cacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,
|
|
202
204
|
cacheWrite: 0,
|
|
203
|
-
reasoning:
|
|
205
|
+
...(reasoning === undefined ? {} : { reasoning }),
|
|
204
206
|
totalTokens: chunk.usageMetadata.totalTokenCount || 0,
|
|
205
207
|
cost: {
|
|
206
208
|
input: 0,
|
|
@@ -28,7 +28,7 @@ import { createGrammarToolInputProperties } from "./constrained-sampling.js";
|
|
|
28
28
|
import { clearWebSocketFallbackState, getOrCreateWebSocketDebugStats, getWebSocketDebugStats, isWebSocketSseFallbackActive, recordWebSocketFailure, recordWebSocketSseFallback, recordWebSocketSuccess, } from "./openai-codex-responses/fallback-state.js";
|
|
29
29
|
import { codexEventProviderDiagnostic, codexHttpProviderDiagnostic, } from "./openai-codex-responses/provider-diagnostic.js";
|
|
30
30
|
import { buildCodexReasoning } from "./openai-codex-responses/reasoning.js";
|
|
31
|
-
import { applyChatGptSubscriptionCacheAffinityHeaders, clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
31
|
+
import { applyChatGptSubscriptionCacheAffinityHeaders, clampOpenAIPromptCacheKey, deriveOpenAIPromptCacheKey, } from "./openai-prompt-cache.js";
|
|
32
32
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream, resolveResponsesDeferredToolsMode, resolveResponsesToolPlacement, } from "./openai-responses-shared.js";
|
|
33
33
|
import { applyExtraBody, buildBaseOptions, clampMaxForOpenAI, OPENAI_RESPONSES_RESERVED_BODY_KEYS, } from "./simple-options.js";
|
|
34
34
|
import { startWebSocketLiveness } from "./websocket-liveness.js";
|
|
@@ -171,7 +171,7 @@ export const stream = (model, context, options) => {
|
|
|
171
171
|
const grammarToolInputProperties = createGrammarToolInputProperties(getDeclaredTools(normalizedContext.messages), model.compat?.supportsOpenAIGrammarTools ?? false);
|
|
172
172
|
const cacheSessionId = options?.cacheRetention === "none" ? undefined : options?.sessionId;
|
|
173
173
|
const codexSessionId = clampOpenAIPromptCacheKey(cacheSessionId);
|
|
174
|
-
let body = buildRequestBody(model, normalizedContext, options,
|
|
174
|
+
let body = buildRequestBody(model, normalizedContext, options, grammarToolInputProperties);
|
|
175
175
|
const nextBody = await options?.onPayload?.(body, model);
|
|
176
176
|
if (nextBody !== undefined) {
|
|
177
177
|
body = nextBody;
|
|
@@ -402,7 +402,7 @@ export const streamSimple = (model, context, options) => {
|
|
|
402
402
|
// ============================================================================
|
|
403
403
|
// Request Building
|
|
404
404
|
// ============================================================================
|
|
405
|
-
function buildRequestBody(model, context, options,
|
|
405
|
+
function buildRequestBody(model, context, options, grammarToolInputProperties = createGrammarToolInputProperties(getDeclaredTools(context.messages), model.compat?.supportsOpenAIGrammarTools ?? false)) {
|
|
406
406
|
const requestedReasoningEffort = options?.reasoningEffort;
|
|
407
407
|
const mappedReasoningEffort = requestedReasoningEffort === undefined
|
|
408
408
|
? undefined
|
|
@@ -436,7 +436,7 @@ function buildRequestBody(model, context, options, cacheSessionId, grammarToolIn
|
|
|
436
436
|
input: messages,
|
|
437
437
|
text: { verbosity: options?.textVerbosity || "low" },
|
|
438
438
|
include: ["reasoning.encrypted_content"],
|
|
439
|
-
prompt_cache_key:
|
|
439
|
+
prompt_cache_key: options?.cacheRetention === "none" ? undefined : deriveOpenAIPromptCacheKey(model.id, context),
|
|
440
440
|
tool_choice: options?.toolChoice ?? "auto",
|
|
441
441
|
parallel_tool_calls: true,
|
|
442
442
|
};
|
|
@@ -12,6 +12,7 @@ import { getOpenAICompletionsCompat as getCompat, } from "../utils/prompt-cache-
|
|
|
12
12
|
import { awaitProviderTransport, iterateProviderTransport, openAICompatibleProviderDiagnosticFromError, } from "../utils/provider-diagnostic-sources.js";
|
|
13
13
|
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
14
14
|
import { retryProviderStreamRequest } from "../utils/provider-retry.js";
|
|
15
|
+
import { reportedCount } from "../utils/reported-count.js";
|
|
15
16
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
16
17
|
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
17
18
|
import { primeStreamUntilContent, sendWithForcedToolChoiceFallback } from "../utils/tool-choice-fallback.js";
|
|
@@ -1569,12 +1570,13 @@ function parseChunkUsage(rawUsage, model) {
|
|
|
1569
1570
|
const input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);
|
|
1570
1571
|
// OpenAI completion_tokens already includes reasoning_tokens.
|
|
1571
1572
|
const outputTokens = rawUsage.completion_tokens || 0;
|
|
1573
|
+
const reasoning = reportedCount(rawUsage.completion_tokens_details?.reasoning_tokens);
|
|
1572
1574
|
const usage = {
|
|
1573
1575
|
input,
|
|
1574
1576
|
output: outputTokens,
|
|
1575
1577
|
cacheRead: cacheReadTokens,
|
|
1576
1578
|
cacheWrite: cacheWriteTokens,
|
|
1577
|
-
reasoning:
|
|
1579
|
+
...(reasoning === undefined ? {} : { reasoning }),
|
|
1578
1580
|
totalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,
|
|
1579
1581
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
1580
1582
|
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { TranscriptContext } from "../types.ts";
|
|
1
2
|
export declare const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
|
|
3
|
+
/** Cache affinity belongs to the reusable leading prefix, never to a conversation UUID. */
|
|
4
|
+
export declare function deriveOpenAIPromptCacheKey(modelId: string, context: TranscriptContext): string | undefined;
|
|
2
5
|
export declare function clampOpenAIPromptCacheKey(key: string | undefined): string | undefined;
|
|
3
6
|
export declare function applyChatGptSubscriptionCacheAffinityHeaders(headers: Headers, sessionId: string | undefined): void;
|
|
4
7
|
//# sourceMappingURL=openai-prompt-cache.d.ts.map
|
|
@@ -1,4 +1,26 @@
|
|
|
1
|
+
import { shortHash } from "../utils/hash.js";
|
|
2
|
+
import { getSystemMessageText } from "../utils/text.js";
|
|
3
|
+
import { getInitialSystemMessage } from "../utils/transcript.js";
|
|
1
4
|
export const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
|
|
5
|
+
const PREFIX_VERSION = "senpi-responses-prefix-v1";
|
|
6
|
+
/** Cache affinity belongs to the reusable leading prefix, never to a conversation UUID. */
|
|
7
|
+
export function deriveOpenAIPromptCacheKey(modelId, context) {
|
|
8
|
+
const initial = getInitialSystemMessage(context.messages);
|
|
9
|
+
const tools = [...(initial?.toolsAdded ?? [])].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
10
|
+
const prefix = JSON.stringify([
|
|
11
|
+
PREFIX_VERSION,
|
|
12
|
+
modelId,
|
|
13
|
+
initial === undefined ? "" : getSystemMessageText(initial),
|
|
14
|
+
tools.map(({ name, description, parameters, freeform, constrainedSampling }) => ({
|
|
15
|
+
name,
|
|
16
|
+
description,
|
|
17
|
+
parameters,
|
|
18
|
+
freeform,
|
|
19
|
+
constrainedSampling,
|
|
20
|
+
})),
|
|
21
|
+
]);
|
|
22
|
+
return clampOpenAIPromptCacheKey(`${PREFIX_VERSION}-${shortHash(prefix)}`);
|
|
23
|
+
}
|
|
2
24
|
export function clampOpenAIPromptCacheKey(key) {
|
|
3
25
|
if (key === undefined)
|
|
4
26
|
return undefined;
|
|
@@ -3,6 +3,7 @@ import { calculateCost, supportsConfigurationUpdate } from "../models.js";
|
|
|
3
3
|
import { splitDeferredTools } from "../utils/deferred-tools.js";
|
|
4
4
|
import { shortHash } from "../utils/hash.js";
|
|
5
5
|
import { parseStreamingJson } from "../utils/json-parse.js";
|
|
6
|
+
import { reportedCount } from "../utils/reported-count.js";
|
|
6
7
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
7
8
|
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
8
9
|
import { getCurrentTools, getDeclaredTools, resolveTranscript, resolveTranscriptTools } from "../utils/transcript.js";
|
|
@@ -480,7 +481,8 @@ export function convertResponsesTools(tools, options) {
|
|
|
480
481
|
const defaultStrict = options?.strict === undefined ? false : options.strict;
|
|
481
482
|
const supportsStrictMode = options?.supportsStrictMode ?? true;
|
|
482
483
|
const supportsOpenAIGrammarTools = options?.supportsOpenAIGrammarTools ?? false;
|
|
483
|
-
|
|
484
|
+
const sortedTools = [...tools].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
485
|
+
return sortedTools.map((tool) => {
|
|
484
486
|
const grammar = resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools);
|
|
485
487
|
if (grammar) {
|
|
486
488
|
return {
|
|
@@ -772,13 +774,14 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
772
774
|
const cachedTokens = inputDetails?.cached_tokens || 0;
|
|
773
775
|
// OpenAI platform reports cache_write_tokens; some compatible gateways use cache_creation_tokens.
|
|
774
776
|
const cacheWriteTokens = inputDetails?.cache_write_tokens ?? inputDetails?.cache_creation_tokens ?? 0;
|
|
777
|
+
const reasoning = reportedCount(response.usage.output_tokens_details?.reasoning_tokens);
|
|
775
778
|
output.usage = {
|
|
776
779
|
// OpenAI includes cached and cache-write tokens in input_tokens, so subtract both.
|
|
777
780
|
input: Math.max(0, (response.usage.input_tokens || 0) - cachedTokens - cacheWriteTokens),
|
|
778
781
|
output: response.usage.output_tokens || 0,
|
|
779
782
|
cacheRead: cachedTokens,
|
|
780
783
|
cacheWrite: cacheWriteTokens,
|
|
781
|
-
reasoning:
|
|
784
|
+
...(reasoning === undefined ? {} : { reasoning }),
|
|
782
785
|
totalTokens: response.usage.total_tokens || 0,
|
|
783
786
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
784
787
|
};
|
|
@@ -17,7 +17,7 @@ import { createGrammarToolInputProperties } from "./constrained-sampling.js";
|
|
|
17
17
|
import { withGitHubCopilotFailureNote } from "./github-copilot-errors.js";
|
|
18
18
|
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
|
|
19
19
|
import { resolveOpenAIClientAuth } from "./openai-client-auth.js";
|
|
20
|
-
import {
|
|
20
|
+
import { deriveOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
21
21
|
import { applyAllowedToolsChoice, hasRefusedAllowedToolsChoice, isAllowedToolsChoiceRefusal, rememberAllowedToolsChoiceRefusal, restrictToAllowedTools, } from "./openai-responses-allowed-tools.js";
|
|
22
22
|
import { findPromptCacheComparisonResponseId, withPromptCacheComparison, } from "./openai-responses-prompt-cache.js";
|
|
23
23
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream, resolveResponsesDeferredToolsMode, resolveResponsesToolPlacement, } from "./openai-responses-shared.js";
|
|
@@ -195,7 +195,7 @@ export const stream = (model, context, options) => {
|
|
|
195
195
|
params = applyAllowedToolsChoice(params, normalizedContext, context.activeToolNames, compat);
|
|
196
196
|
if (hasRefusedAllowedToolsChoice(model))
|
|
197
197
|
params = restrictToAllowedTools(params);
|
|
198
|
-
const limitedTools = limitGitHubCopilotTools(model.provider, params.tools, params.tool_choice);
|
|
198
|
+
const limitedTools = limitGitHubCopilotTools(model.provider, params.tools, params.tool_choice, getDeclaredTools(normalizedContext.messages).map((tool) => tool.name));
|
|
199
199
|
if (limitedTools.omittedCount > 0) {
|
|
200
200
|
params = { ...params, tools: limitedTools.tools };
|
|
201
201
|
recordGitHubCopilotToolLimit(output, limitedTools.omittedCount);
|
|
@@ -348,7 +348,7 @@ export async function warmOpenAIResponsesPromptCache(model, context, options) {
|
|
|
348
348
|
if (nextParams !== undefined)
|
|
349
349
|
params = nextParams;
|
|
350
350
|
params = sanitizeUnsupportedNativeTools(params, compat);
|
|
351
|
-
const limitedTools = limitGitHubCopilotTools(model.provider, params.tools, params.tool_choice);
|
|
351
|
+
const limitedTools = limitGitHubCopilotTools(model.provider, params.tools, params.tool_choice, getDeclaredTools(prefix.messages).map((tool) => tool.name));
|
|
352
352
|
if (limitedTools.omittedCount > 0)
|
|
353
353
|
params = { ...params, tools: limitedTools.tools };
|
|
354
354
|
const body = {
|
|
@@ -443,10 +443,7 @@ function buildParams(model, context, options, compat = getCompat(model, options?
|
|
|
443
443
|
model: model.id,
|
|
444
444
|
input: messages,
|
|
445
445
|
stream: true,
|
|
446
|
-
prompt_cache_key: cacheRetention === "none"
|
|
447
|
-
(isNativeEndpoint && (compat.supportsExplicitPromptCacheMode || model.cost.cacheWrite > 0))
|
|
448
|
-
? undefined
|
|
449
|
-
: clampOpenAIPromptCacheKey(options?.sessionId),
|
|
446
|
+
prompt_cache_key: cacheRetention === "none" ? undefined : deriveOpenAIPromptCacheKey(model.id, context),
|
|
450
447
|
prompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),
|
|
451
448
|
prompt_cache_options: withPromptCacheComparison(getPromptCacheOptions(compat, cacheRetention), comparisonResponseId),
|
|
452
449
|
store: false,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Credential } from "../types.ts";
|
|
2
|
+
import { type CredentialSlot, type PooledCredential } from "./slots.ts";
|
|
3
|
+
export type CredentialKind = Credential["type"];
|
|
4
|
+
/**
|
|
5
|
+
* A slot's kind from its own material: OAuth tokens make an OAuth login, a key alone makes an API
|
|
6
|
+
* key. A slot with neither is not classified, so a caller never drops or reports it by guess.
|
|
7
|
+
*/
|
|
8
|
+
export declare function slotKind(slot: Pick<CredentialSlot, "access" | "refresh" | "key">): CredentialKind | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Kinds held by a credential's slots that its top-level type cannot use: slots are projected
|
|
11
|
+
* through that type, so a slot of the other kind is never used (senpi#3448). Builds before the
|
|
12
|
+
* fix appended a login of the other kind this way.
|
|
13
|
+
*/
|
|
14
|
+
export declare function unusedSlotKinds(credential: PooledCredential | undefined): ReadonlyArray<CredentialKind>;
|
|
15
|
+
/** The slots a credential can actually use: a slot of the other kind never projects (senpi#3486). */
|
|
16
|
+
export declare function slotsOfOwnKind(credential: PooledCredential): CredentialSlot[];
|
|
17
|
+
//# sourceMappingURL=kinds.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { listSlots } from "./slots.js";
|
|
2
|
+
/**
|
|
3
|
+
* A slot's kind from its own material: OAuth tokens make an OAuth login, a key alone makes an API
|
|
4
|
+
* key. A slot with neither is not classified, so a caller never drops or reports it by guess.
|
|
5
|
+
*/
|
|
6
|
+
export function slotKind(slot) {
|
|
7
|
+
if (slot.access !== undefined || slot.refresh !== undefined)
|
|
8
|
+
return "oauth";
|
|
9
|
+
return slot.key !== undefined ? "api_key" : undefined;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Kinds held by a credential's slots that its top-level type cannot use: slots are projected
|
|
13
|
+
* through that type, so a slot of the other kind is never used (senpi#3448). Builds before the
|
|
14
|
+
* fix appended a login of the other kind this way.
|
|
15
|
+
*/
|
|
16
|
+
export function unusedSlotKinds(credential) {
|
|
17
|
+
if (!credential || !Array.isArray(credential.accounts))
|
|
18
|
+
return [];
|
|
19
|
+
const kinds = new Set();
|
|
20
|
+
for (const slot of listSlots(credential)) {
|
|
21
|
+
const kind = slotKind(slot);
|
|
22
|
+
if (kind !== undefined && kind !== credential.type)
|
|
23
|
+
kinds.add(kind);
|
|
24
|
+
}
|
|
25
|
+
return [...kinds];
|
|
26
|
+
}
|
|
27
|
+
/** The slots a credential can actually use: a slot of the other kind never projects (senpi#3486). */
|
|
28
|
+
export function slotsOfOwnKind(credential) {
|
|
29
|
+
return listSlots(credential).filter((slot) => slotKind(slot) !== otherKind(credential.type));
|
|
30
|
+
}
|
|
31
|
+
const otherKind = (kind) => (kind === "oauth" ? "api_key" : "oauth");
|
|
32
|
+
//# sourceMappingURL=kinds.js.map
|
|
@@ -89,7 +89,7 @@ export declare function projectSlot(credential: PooledCredential | undefined, na
|
|
|
89
89
|
* `onAllocated` reports the account this login committed, so a caller can name
|
|
90
90
|
* it in a receipt without re-reading storage.
|
|
91
91
|
*/
|
|
92
|
-
export declare function appendLoginSlot(
|
|
92
|
+
export declare function appendLoginSlot(stored: PooledCredential | undefined, flat: Credential, onAllocated?: (name: string, origin: "generated" | "provider") => void): Credential;
|
|
93
93
|
/**
|
|
94
94
|
* Material a provider writes into the flat credential when the real token lives
|
|
95
95
|
* outside auth.json (an SDK subprocess or a vendor CLI owns it): the literal
|
package/dist/auth/pool/slots.js
CHANGED
|
@@ -306,7 +306,10 @@ function hasNewerMaterial(candidate, stored) {
|
|
|
306
306
|
* `onAllocated` reports the account this login committed, so a caller can name
|
|
307
307
|
* it in a receipt without re-reading storage.
|
|
308
308
|
*/
|
|
309
|
-
export function appendLoginSlot(
|
|
309
|
+
export function appendLoginSlot(stored, flat, onAllocated) {
|
|
310
|
+
// A pool holds one kind: a login of the other kind replaces the credential instead of joining it
|
|
311
|
+
// as a slot nothing can project (senpi#3448). The caller backs up what it replaces.
|
|
312
|
+
const current = stored?.type === flat.type ? stored : undefined;
|
|
310
313
|
const provided = providedSlots(flat);
|
|
311
314
|
if (provided) {
|
|
312
315
|
// Provider-owned envelopes identify an addition by immutable ID, never by
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CursorModelCapability } from "./model-capabilities.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Static cursor capability table. Values come from the live
|
|
4
|
+
* aiserver.v1 AvailableModels capture of 2026-08-18 (evidence:
|
|
5
|
+
* local-ignore/qa-evidence/20260818-cursor-reasoning-levels/available-models-catalog.json).
|
|
6
|
+
* `GetUsableModels` carries no window or parameter field, so this table is the
|
|
7
|
+
* authoritative source; see .omo/plans/cursor-reasoning-levels.md §3.1/§6.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CURSOR_MODEL_CAPABILITIES: Record<string, CursorModelCapability>;
|
|
10
|
+
//# sourceMappingURL=capability-table.d.ts.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
const P = "parameters";
|
|
2
|
+
const V = "variant-id";
|
|
3
|
+
function ladder(values, encoding = P) {
|
|
4
|
+
const out = {};
|
|
5
|
+
for (const value of values)
|
|
6
|
+
out[value === "none" ? "off" : value] = { value, encoding };
|
|
7
|
+
return out;
|
|
8
|
+
}
|
|
9
|
+
const CLAUDE_ORDER = ["thinking", "context", "effort"];
|
|
10
|
+
const GPT_ORDER = ["context", "reasoning", "fast"];
|
|
11
|
+
function claude(window, maxWindow, levels, defaultContext) {
|
|
12
|
+
return {
|
|
13
|
+
evidence: "available-models",
|
|
14
|
+
window,
|
|
15
|
+
maxWindow,
|
|
16
|
+
parameterOrder: CLAUDE_ORDER,
|
|
17
|
+
defaultContext,
|
|
18
|
+
requestContext: window >= 1_000_000 ? "1m" : defaultContext,
|
|
19
|
+
levels: ladder(levels),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function gpt(levels, order = GPT_ORDER, window = 400000, maxWindow = 400000) {
|
|
23
|
+
return {
|
|
24
|
+
evidence: "available-models",
|
|
25
|
+
window,
|
|
26
|
+
maxWindow,
|
|
27
|
+
parameterOrder: order,
|
|
28
|
+
defaultContext: "272k",
|
|
29
|
+
requestContext: order.includes("context") && window >= 1_000_000 ? "1m" : undefined,
|
|
30
|
+
levels: ladder(levels),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const LEVELS_LOW_MAX = ["low", "medium", "high", "xhigh", "max"];
|
|
34
|
+
const CONTEXT_TOKEN = { 300000: "300k", 256000: "256k" };
|
|
35
|
+
/** A family whose window is the default context option the server reported serving. */
|
|
36
|
+
function served(window, maxWindow, order, levels) {
|
|
37
|
+
const context = order.includes("context") ? CONTEXT_TOKEN[window] : undefined;
|
|
38
|
+
return {
|
|
39
|
+
evidence: "served-checkpoint",
|
|
40
|
+
window,
|
|
41
|
+
...(maxWindow !== undefined ? { maxWindow } : {}),
|
|
42
|
+
parameterOrder: order,
|
|
43
|
+
...(context !== undefined ? { defaultContext: context, requestContext: context } : {}),
|
|
44
|
+
levels: ladder(levels),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Static cursor capability table. Values come from the live
|
|
49
|
+
* aiserver.v1 AvailableModels capture of 2026-08-18 (evidence:
|
|
50
|
+
* local-ignore/qa-evidence/20260818-cursor-reasoning-levels/available-models-catalog.json).
|
|
51
|
+
* `GetUsableModels` carries no window or parameter field, so this table is the
|
|
52
|
+
* authoritative source; see .omo/plans/cursor-reasoning-levels.md §3.1/§6.
|
|
53
|
+
*/
|
|
54
|
+
export const CURSOR_MODEL_CAPABILITIES = {
|
|
55
|
+
"claude-fable-5": claude(1000000, 1000000, ["low", "medium", "high", "xhigh", "max"], "300k"),
|
|
56
|
+
"claude-sonnet-5": claude(1000000, 1000000, ["low", "medium", "high", "xhigh", "max"], "300k"),
|
|
57
|
+
"claude-opus-4-7": claude(1000000, 1000000, ["low", "medium", "high", "xhigh", "max"], "300k"),
|
|
58
|
+
"claude-opus-4-8": claude(1000000, 1000000, ["low", "medium", "high", "xhigh", "max"], "300k"),
|
|
59
|
+
"claude-opus-5": claude(1000000, 1000000, ["low", "medium", "high", "xhigh", "max"], "300k"),
|
|
60
|
+
"claude-4.6-opus": claude(1000000, 1000000, ["high", "max"], "200k"),
|
|
61
|
+
"claude-4.6-sonnet": claude(1000000, 1000000, ["medium"], "200k"),
|
|
62
|
+
"claude-4.5-opus": {
|
|
63
|
+
evidence: "available-models",
|
|
64
|
+
window: 200000,
|
|
65
|
+
parameterOrder: ["thinking"],
|
|
66
|
+
levels: { high: { value: "high", encoding: V } },
|
|
67
|
+
},
|
|
68
|
+
"gpt-5.6-sol": gpt(["none", "low", "medium", "high", "xhigh", "max"], GPT_ORDER, 1000000, 1000000),
|
|
69
|
+
"gpt-5.6-luna": gpt(["none", "low", "medium", "high", "xhigh", "max"], GPT_ORDER, 1000000, 1000000),
|
|
70
|
+
"gpt-5.6-terra": gpt(["none", "low", "medium", "high", "xhigh", "max"], GPT_ORDER, 272000, 272000),
|
|
71
|
+
"gpt-5.5": {
|
|
72
|
+
...gpt(["none", "low", "medium", "high"], GPT_ORDER, 1000000, 1000000),
|
|
73
|
+
levels: { ...ladder(["none", "low", "medium", "high"]), xhigh: { value: "extra-high", encoding: P } },
|
|
74
|
+
},
|
|
75
|
+
"gpt-5.3-codex": {
|
|
76
|
+
...gpt([], ["reasoning", "fast"]),
|
|
77
|
+
maxWindow: undefined,
|
|
78
|
+
defaultContext: undefined,
|
|
79
|
+
levels: { ...ladder(["low", "medium", "high"]), xhigh: { value: "extra-high", encoding: P } },
|
|
80
|
+
},
|
|
81
|
+
"gpt-5.1": {
|
|
82
|
+
...gpt([], ["reasoning"]),
|
|
83
|
+
maxWindow: undefined,
|
|
84
|
+
defaultContext: undefined,
|
|
85
|
+
levels: ladder(["low", "high"]),
|
|
86
|
+
},
|
|
87
|
+
"gpt-5.2": {
|
|
88
|
+
...gpt([], ["reasoning"]),
|
|
89
|
+
maxWindow: undefined,
|
|
90
|
+
defaultContext: undefined,
|
|
91
|
+
levels: { ...ladder(["low", "high"]), xhigh: { value: "xhigh", encoding: V } },
|
|
92
|
+
},
|
|
93
|
+
"gpt-5.4": {
|
|
94
|
+
...gpt([], ["reasoning"]),
|
|
95
|
+
maxWindow: undefined,
|
|
96
|
+
defaultContext: undefined,
|
|
97
|
+
levels: { ...ladder(["low", "medium", "high"]), xhigh: { value: "xhigh", encoding: V } },
|
|
98
|
+
},
|
|
99
|
+
"gpt-5.4-mini": {
|
|
100
|
+
evidence: "available-models",
|
|
101
|
+
window: 400_000,
|
|
102
|
+
parameterOrder: [],
|
|
103
|
+
levels: ladder(["none", "low", "medium", "high", "xhigh"], V),
|
|
104
|
+
},
|
|
105
|
+
"gpt-5.4-nano": {
|
|
106
|
+
...gpt([], ["reasoning"]),
|
|
107
|
+
maxWindow: undefined,
|
|
108
|
+
defaultContext: undefined,
|
|
109
|
+
levels: ladder(["none", "low", "medium", "high", "xhigh"]),
|
|
110
|
+
},
|
|
111
|
+
"gemini-3.7-flash": {
|
|
112
|
+
evidence: "cli-live",
|
|
113
|
+
window: 1_048_576,
|
|
114
|
+
parameterOrder: ["effort"],
|
|
115
|
+
levels: ladder(["low", "medium", "high"]),
|
|
116
|
+
},
|
|
117
|
+
"gemini-3.6-flash": {
|
|
118
|
+
evidence: "suffix-only",
|
|
119
|
+
window: 1_048_576,
|
|
120
|
+
parameterOrder: [],
|
|
121
|
+
levels: ladder(["minimal", "low", "medium", "high"], V),
|
|
122
|
+
},
|
|
123
|
+
"cursor-grok-4.6": {
|
|
124
|
+
evidence: "available-models",
|
|
125
|
+
window: 500_000,
|
|
126
|
+
parameterOrder: ["effort", "fast"],
|
|
127
|
+
levels: ladder(["low", "medium", "high", "xhigh"]),
|
|
128
|
+
},
|
|
129
|
+
"cursor-grok-4.5": {
|
|
130
|
+
evidence: "suffix-only",
|
|
131
|
+
window: 500_000,
|
|
132
|
+
parameterOrder: [],
|
|
133
|
+
levels: ladder(["low", "medium", "high"], V),
|
|
134
|
+
},
|
|
135
|
+
"glm-5.2": {
|
|
136
|
+
evidence: "available-models",
|
|
137
|
+
window: 1000000,
|
|
138
|
+
parameterOrder: ["reasoning"],
|
|
139
|
+
levels: ladder(["high", "max"]),
|
|
140
|
+
},
|
|
141
|
+
"kimi-k3": {
|
|
142
|
+
evidence: "available-models",
|
|
143
|
+
window: 1048576,
|
|
144
|
+
parameterOrder: ["reasoning"],
|
|
145
|
+
levels: ladder(["low", "high", "max"]),
|
|
146
|
+
},
|
|
147
|
+
"composer-2.5": { evidence: "available-models", window: 200000, parameterOrder: ["fast"], levels: {} },
|
|
148
|
+
"claude-haiku-4-5": { evidence: "available-models", window: 200000, parameterOrder: ["thinking"], levels: {} },
|
|
149
|
+
"claude-4-sonnet": {
|
|
150
|
+
evidence: "available-models",
|
|
151
|
+
window: 200000,
|
|
152
|
+
parameterOrder: ["thinking", "context"],
|
|
153
|
+
defaultContext: "200k",
|
|
154
|
+
levels: {},
|
|
155
|
+
},
|
|
156
|
+
"claude-4.5-sonnet": {
|
|
157
|
+
evidence: "available-models",
|
|
158
|
+
window: 200_000,
|
|
159
|
+
parameterOrder: ["thinking", "context"],
|
|
160
|
+
defaultContext: "200k",
|
|
161
|
+
levels: {},
|
|
162
|
+
},
|
|
163
|
+
"kimi-k2.7-code": { evidence: "available-models", window: 262_144, parameterOrder: [], levels: {} },
|
|
164
|
+
"gemini-3-flash": { evidence: "available-models", window: 1000000, parameterOrder: [], levels: {} },
|
|
165
|
+
"gemini-3.1-pro": { evidence: "available-models", window: 1000000, parameterOrder: [], levels: {} },
|
|
166
|
+
"gemini-3.5-flash": { evidence: "available-models", window: 1_048_576, parameterOrder: [], levels: {} },
|
|
167
|
+
"gpt-5-mini": { evidence: "available-models", window: 400_000, parameterOrder: [], levels: {} },
|
|
168
|
+
// Families published after the 2026-08-18 capture (senpi#3620). Windows are the
|
|
169
|
+
// ceilings the server reported on the first checkpoint on 2026-10-18 for the
|
|
170
|
+
// suffix variant senpi sends (no context parameter, so Cursor's default option);
|
|
171
|
+
// maxWindow is the largest context option AvailableModels offers.
|
|
172
|
+
"claude-opus-5-5": served(300_000, 1_000_000, ["context", "effort", "fast"], LEVELS_LOW_MAX),
|
|
173
|
+
"claude-fable-5-1": served(300_000, 1_000_000, ["thinking", "context", "effort"], LEVELS_LOW_MAX),
|
|
174
|
+
"claude-sonnet-5-5": served(300_000, 1_000_000, ["context", "reasoning_effort"], LEVELS_LOW_MAX),
|
|
175
|
+
"claude-haiku-5-5": served(300_000, 1_000_000, ["thinking", "context", "reasoning_effort"], LEVELS_LOW_MAX),
|
|
176
|
+
"muse-wonder-1.0": served(300_000, 1_000_000, ["context", "reasoning_effort"], ["minimal", ...LEVELS_LOW_MAX]),
|
|
177
|
+
"muse-spark-1.3": served(300_000, 1_000_000, ["context", "effort"], ["minimal", ...LEVELS_LOW_MAX]),
|
|
178
|
+
"grok-4.7": served(256_000, 500_000, ["context", "reasoning_effort", "fast"], ["low", "medium", "high", "xhigh"]),
|
|
179
|
+
"gemini-4-argon": served(200_000, undefined, ["reasoning_effort"], ["low", "medium", "high"]),
|
|
180
|
+
"gemini-3.8-flash": served(200_000, undefined, ["reasoning_effort"], ["low", "medium", "high"]),
|
|
181
|
+
default: served(256_000, undefined, [], []),
|
|
182
|
+
};
|
|
183
|
+
//# sourceMappingURL=capability-table.js.map
|
|
@@ -1,32 +1,10 @@
|
|
|
1
1
|
import aliasData from "./cursor-variant-aliases.json" with { type: "json" };
|
|
2
|
+
import { cleanCursorGroupName, dropUnservedSizeToken, sanitizeCursorDisplayName } from "./display-name.js";
|
|
2
3
|
import { CURSOR_MODEL_CAPABILITIES, getCursorVariantAlias, parseCursorVariantId, } from "./model-capabilities.js";
|
|
3
4
|
export { parseCursorVariantId } from "./model-capabilities.js";
|
|
4
5
|
const ALL_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
5
6
|
const FALLBACK_WINDOW = 200000;
|
|
6
7
|
const STATIC_TARGETS = new Set(Object.values(aliasData.aliases).map((alias) => alias.targetId));
|
|
7
|
-
function isClaude(baseId) {
|
|
8
|
-
return baseId.startsWith("claude-");
|
|
9
|
-
}
|
|
10
|
-
function cleanName(members, baseId, thinkingMode) {
|
|
11
|
-
const levelWords = /(Minimal|Low|Medium|High|Extra High|XHigh|Max|None)/g;
|
|
12
|
-
const representative = members.find((member) => member.level === "high") ??
|
|
13
|
-
members.find((member) => member.level === "medium") ??
|
|
14
|
-
members.find((member) => member.level === "low") ??
|
|
15
|
-
members[0];
|
|
16
|
-
let name = representative.raw.name;
|
|
17
|
-
name = name.replace(/\s*\(NO ZDR\)\s*/g, " \u0001").trim();
|
|
18
|
-
name = name.replace(new RegExp(`\\s+${levelWords.source}\\b`, "g"), "");
|
|
19
|
-
name = name.replace(/\s+Fast\b/g, "");
|
|
20
|
-
if (thinkingMode !== true)
|
|
21
|
-
name = name.replace(/\s+Thinking\b/g, "");
|
|
22
|
-
name = name
|
|
23
|
-
.replace(/\u0001/g, "(NO ZDR)")
|
|
24
|
-
.replace(/\s+/g, " ")
|
|
25
|
-
.trim();
|
|
26
|
-
if (name.length === 0)
|
|
27
|
-
name = baseId;
|
|
28
|
-
return name;
|
|
29
|
-
}
|
|
30
8
|
function buildLevelMap(members, capability) {
|
|
31
9
|
const observed = new Set(members.map((member) => member.level).filter((level) => level !== undefined));
|
|
32
10
|
const map = {};
|
|
@@ -196,10 +174,10 @@ export function normalizeCursorCatalog(rawEntries) {
|
|
|
196
174
|
const isGrouped = members.length > 1 || first.alias.targetId !== first.raw.id;
|
|
197
175
|
const efforts = members.filter((member) => member.level !== undefined && member.level !== "none");
|
|
198
176
|
if (isGrouped && efforts.length > 0 && !first.fast) {
|
|
199
|
-
const thinkingMode =
|
|
177
|
+
const thinkingMode = baseId.startsWith("claude-") ? first.thinking === true : undefined;
|
|
200
178
|
out.push({
|
|
201
179
|
id: first.alias.targetId,
|
|
202
|
-
name:
|
|
180
|
+
name: dropUnservedSizeToken(cleanCursorGroupName(members, baseId, thinkingMode), capability),
|
|
203
181
|
reasoning: true,
|
|
204
182
|
thinkingLevelMap: derivedGroup ? buildDerivedLevelMap(members) : buildLevelMap(members, capability),
|
|
205
183
|
window: capability?.window ?? FALLBACK_WINDOW,
|
|
@@ -219,7 +197,7 @@ export function normalizeCursorCatalog(rawEntries) {
|
|
|
219
197
|
const memberCapability = CURSOR_MODEL_CAPABILITIES[memberBase];
|
|
220
198
|
out.push({
|
|
221
199
|
id: member.raw.id,
|
|
222
|
-
name: member.raw.name,
|
|
200
|
+
name: dropUnservedSizeToken(sanitizeCursorDisplayName(member.raw.name), memberCapability),
|
|
223
201
|
reasoning: false,
|
|
224
202
|
window: memberCapability?.window ?? FALLBACK_WINDOW,
|
|
225
203
|
...(memberCapability?.maxWindow !== undefined ? { maxWindow: memberCapability.maxWindow } : {}),
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Cursor display-name cleanup for catalog identities (senpi#3620). */
|
|
2
|
+
export interface CursorNamedMember {
|
|
3
|
+
readonly raw: {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
};
|
|
6
|
+
readonly level: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
/** Drops zero-width characters and collapses whitespace in a raw Cursor label. */
|
|
9
|
+
export declare function sanitizeCursorDisplayName(name: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Names a grouped identity after its representative variant, without the level, fast and
|
|
12
|
+
* thinking words that the identity's level map and thinking flag now carry. Cursor labels
|
|
13
|
+
* the Haiku 5.5 split the other way round ("No Thinking" on the plain variants, nothing on
|
|
14
|
+
* the thinking ones), so the plain group drops "No Thinking" whole and a thinking group
|
|
15
|
+
* whose label never said so gains "Thinking".
|
|
16
|
+
*/
|
|
17
|
+
export declare function cleanCursorGroupName(members: readonly CursorNamedMember[], baseId: string, thinkingMode: boolean | undefined): string;
|
|
18
|
+
/** A window the server was measured serving; `window` is what senpi sends. */
|
|
19
|
+
export interface CursorSizedCapability {
|
|
20
|
+
readonly evidence?: string;
|
|
21
|
+
readonly window: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A size token may stay in a display name only while the served window backs it. Cursor
|
|
25
|
+
* labels the 2026-10 generation "1M" for the extended-context tier; the checkpoint the
|
|
26
|
+
* catalog measures reports 300k for the default option senpi requests, so the token
|
|
27
|
+
* misleads (senpi#3620 review LOW-1). Entries whose window is only advertised
|
|
28
|
+
* (`available-models`) keep Cursor's label; their mismatch is senpi#3621's call.
|
|
29
|
+
*/
|
|
30
|
+
export declare function dropUnservedSizeToken(name: string, capability: CursorSizedCapability | undefined): string;
|
|
31
|
+
//# sourceMappingURL=display-name.d.ts.map
|