@oh-my-pi/pi-catalog 17.1.2 → 17.1.4

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.
@@ -7,6 +7,7 @@ import {
7
7
  import { Effort, THINKING_EFFORTS } from "../effort";
8
8
  import { FIREWORKS_FAST_SUFFIX, toFireworksPublicModelId } from "../fireworks-model-id";
9
9
  import {
10
+ anthropicModelSupportsThinking,
10
11
  isGlmVisionModelId,
11
12
  isGrokReasoningEffortCapable,
12
13
  isKimiK3ModelId,
@@ -17,7 +18,7 @@ import type { ModelManagerOptions } from "../model-manager";
17
18
  import { getBundledModels } from "../models";
18
19
  import type { Api, FetchImpl, Model, ModelSpec, OpenAICompat, Provider, ThinkingConfig } from "../types";
19
20
  import { discoveryFetch, isAnthropicOAuthToken, isRecord, toBoolean, toNumber, toPositiveNumber } from "../utils";
20
- import { parseAlibabaTokenPlanCredential } from "../wire/alibaba-token-plan";
21
+ import { ALIBABA_TOKEN_PLAN_BASE_URL, parseAlibabaTokenPlanCredential } from "../wire/alibaba-token-plan";
21
22
  import { coreWeaveProjectHeaders } from "../wire/coreweave";
22
23
  import {
23
24
  COPILOT_API_HEADERS,
@@ -2434,7 +2435,7 @@ export function alibabaCodingPlanModelManagerOptions(
2434
2435
  // Alibaba Token Plan
2435
2436
  // ---------------------------------------------------------------------------
2436
2437
 
2437
- export const ALIBABA_TOKEN_PLAN_BASE_URL = "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1";
2438
+ export { ALIBABA_TOKEN_PLAN_BASE_URL };
2438
2439
 
2439
2440
  const ALIBABA_TOKEN_PLAN_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } as const;
2440
2441
  const ALIBABA_TOKEN_PLAN_COMPAT: OpenAICompat = {
@@ -2556,7 +2557,10 @@ export function alibabaTokenPlanModelManagerOptions(
2556
2557
  ): ModelManagerOptions<"openai-completions"> {
2557
2558
  const credential = config?.apiKey ? parseAlibabaTokenPlanCredential(config.apiKey) : undefined;
2558
2559
  const apiKey = credential?.token;
2559
- const baseUrl = config?.baseUrl ?? ALIBABA_TOKEN_PLAN_BASE_URL;
2560
+ // A region-locked credential (China/custom) dictates the discovery endpoint:
2561
+ // its key only authenticates against its own region, so fetching /models from
2562
+ // any other base URL would 401 (#6682).
2563
+ const baseUrl = credential?.baseUrl ?? config?.baseUrl ?? ALIBABA_TOKEN_PLAN_BASE_URL;
2560
2564
  return {
2561
2565
  providerId: "alibaba-token-plan",
2562
2566
  dynamicModelsAuthoritative: true,
@@ -4279,6 +4283,13 @@ export function githubCopilotModelManagerOptions(config?: GithubCopilotModelMana
4279
4283
  return {
4280
4284
  providerId: "github-copilot",
4281
4285
  dropCachedModelIdsOnStaticMismatch: COPILOT_CACHE_INVALIDATED_MODEL_IDS,
4286
+ // COPILOT_API_HEADERS are compile-time constants (User-Agent + API
4287
+ // version), not credentials. The cache omits all request headers for
4288
+ // safety and can only restore them from a bundled static entry — so a
4289
+ // Copilot model with no bundled reference (e.g. a freshly served
4290
+ // claude-opus-5 and its synthesized -1m sibling) is dropped on offline
4291
+ // reads. Declaring the constant lets the cache restore it by value.
4292
+ restorableHeaderFallback: { ...COPILOT_API_HEADERS },
4282
4293
  ...(apiKey && {
4283
4294
  fetchDynamicModels: async () => {
4284
4295
  const longContextVariants: ModelSpec<Api>[] = [];
@@ -4377,6 +4388,17 @@ export function githubCopilotModelManagerOptions(config?: GithubCopilotModelMana
4377
4388
  contextWindow: defaultTierWindow,
4378
4389
  maxTokens,
4379
4390
  headers: { ...COPILOT_API_HEADERS },
4391
+ // Copilot's `/models` advertises no reasoning bit, so a
4392
+ // thinking-capable Claude with no bundled reference would
4393
+ // fall back to `reasoning: false` and lose its effort dial.
4394
+ // Gate on the id classifier (not the transport alone) so a
4395
+ // lagging enterprise catalog serving a pre-thinking Claude
4396
+ // (<= 3.5) over the Messages proxy is not handed a fabricated
4397
+ // dial it would reject; a modern reference-less model (e.g.
4398
+ // claude-opus-5) is marked so `buildModel` derives the ladder.
4399
+ ...(api === "anthropic-messages" && anthropicModelSupportsThinking(defaults.id)
4400
+ ? { reasoning: true }
4401
+ : {}),
4380
4402
  ...(api === "openai-completions"
4381
4403
  ? {
4382
4404
  compat: {
package/src/types.ts CHANGED
@@ -341,6 +341,12 @@ export interface OpenAICompat {
341
341
  * to opt a host out.
342
342
  */
343
343
  toolSchemaFlavor?: "moonshot-mfjs" | "grammar" | "none";
344
+ /**
345
+ * Stream-watchdog first-event timeout in ms.
346
+ * Set to `0` to allow unbounded prompt processing. Default: auto-detected
347
+ * (disabled for local OpenAI-compatible backends).
348
+ */
349
+ streamFirstEventTimeoutMs?: number;
344
350
  /**
345
351
  * Stream-watchdog idle-timeout floor in ms for slow reasoning hosts.
346
352
  * Default: auto-detected (GLM coding-plan hosts, direct DeepSeek reasoning).
@@ -565,6 +571,8 @@ export interface ResolvedOpenAISharedCompat {
565
571
  requiresAssistantContentForToolCalls: boolean;
566
572
  stripDeepseekSpecialTokens: boolean;
567
573
  streamMarkupHealingPattern?: OpenAIStreamMarkupHealingPattern;
574
+ /** See {@link OpenAICompat.streamFirstEventTimeoutMs}. */
575
+ streamFirstEventTimeoutMs?: number;
568
576
  reasoningDeltasMayBeCumulative: boolean;
569
577
  emptyLengthFinishIsContextError: boolean;
570
578
  usesOpenAIToolCallIdLimit: boolean;
@@ -645,6 +653,7 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
645
653
  | "extraBody"
646
654
  | "toolStrictMode"
647
655
  | "toolSchemaFlavor"
656
+ | "streamFirstEventTimeoutMs"
648
657
  | "streamIdleTimeoutMs"
649
658
  | "cacheControlFormat"
650
659
  | "thinkingKeep"
@@ -816,6 +825,8 @@ export interface Model<TApi extends Api = Api> {
816
825
  supportsTools?: boolean;
817
826
  /** Whether this model accepts the GA OpenAI Responses `{ type: "computer" }` native tool. */
818
827
  supportsComputerUse?: boolean;
828
+ /** Verbatim explicit computer-use support from the spec; undefined when `buildModel` inferred the runtime value. */
829
+ supportsComputerUseConfig?: boolean;
819
830
  /** GitLab Duo Workflow root namespace selected during catalog discovery. */
820
831
  gitlabDuoWorkflowRootNamespaceId?: string;
821
832
  /** Cursor `max_mode` request flag returned by `GetUsableModels` for premium models that require max mode. */
@@ -901,7 +912,8 @@ export interface Model<TApi extends Api = Api> {
901
912
  * vocabulary of `buildModel`. Identical to `Model` except `compat` carries the
902
913
  * sparse override shape and nothing is resolved yet.
903
914
  */
904
- export interface ModelSpec<TApi extends Api = Api> extends Omit<Model<TApi>, "compat" | "compatConfig"> {
915
+ export interface ModelSpec<TApi extends Api = Api>
916
+ extends Omit<Model<TApi>, "compat" | "compatConfig" | "supportsComputerUseConfig"> {
905
917
  /** Sparse compatibility overrides; resolved into `Model.compat` by `buildModel`. */
906
918
  compat?: CompatConfigOf<TApi>;
907
919
  }
@@ -1,6 +1,23 @@
1
+ /**
2
+ * International (Singapore) Token Plan endpoint. Default region; keys issued by
3
+ * the international product authenticate only here.
4
+ */
5
+ export const ALIBABA_TOKEN_PLAN_BASE_URL = "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1";
6
+ /**
7
+ * China (Beijing) Token Plan endpoint (百炼 Token Plan). Keys are region-locked:
8
+ * a Beijing-issued key is rejected by the international endpoint with
9
+ * `invalid_api_key`, and vice versa (#6682).
10
+ */
11
+ export const ALIBABA_TOKEN_PLAN_CN_BASE_URL = "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1";
12
+
1
13
  export interface AlibabaTokenPlanCredential {
2
14
  token: string;
3
15
  cookie?: string;
16
+ /**
17
+ * Region base URL the key authenticates against. Absent means the default
18
+ * international endpoint ({@link ALIBABA_TOKEN_PLAN_BASE_URL}).
19
+ */
20
+ baseUrl?: string;
4
21
  }
5
22
 
6
23
  const TOKEN_PATTERN = /^sk-[A-Za-z0-9._~+/-]+={0,2}$/;
@@ -10,18 +27,28 @@ export function parseAlibabaTokenPlanCredential(value: string): AlibabaTokenPlan
10
27
  if (!trimmed) return null;
11
28
  if (!trimmed.startsWith("{")) return TOKEN_PATTERN.test(trimmed) ? { token: trimmed } : null;
12
29
  try {
13
- const parsed = JSON.parse(trimmed) as { token?: unknown; cookie?: unknown };
30
+ const parsed = JSON.parse(trimmed) as { token?: unknown; cookie?: unknown; baseUrl?: unknown };
14
31
  if (typeof parsed.token !== "string" || !TOKEN_PATTERN.test(parsed.token.trim())) return null;
15
32
  if (parsed.cookie !== undefined && typeof parsed.cookie !== "string") return null;
33
+ if (parsed.baseUrl !== undefined && typeof parsed.baseUrl !== "string") return null;
16
34
  const token = parsed.token.trim();
17
35
  const cookie = parsed.cookie?.trim();
18
- return cookie ? { token, cookie } : { token };
36
+ const baseUrl = parsed.baseUrl?.trim();
37
+ const credential: AlibabaTokenPlanCredential = { token };
38
+ if (cookie) credential.cookie = cookie;
39
+ if (baseUrl) credential.baseUrl = baseUrl;
40
+ return credential;
19
41
  } catch {
20
42
  return null;
21
43
  }
22
44
  }
23
45
 
24
- export function serializeAlibabaTokenPlanCredential(token: string, cookie: string): string {
46
+ export function serializeAlibabaTokenPlanCredential(token: string, cookie: string, baseUrl?: string): string {
25
47
  const trimmedCookie = cookie.trim();
26
- return trimmedCookie ? JSON.stringify({ token, cookie: trimmedCookie }) : token;
48
+ const trimmedBaseUrl = baseUrl?.trim();
49
+ if (!trimmedCookie && !trimmedBaseUrl) return token;
50
+ const payload: { token: string; cookie?: string; baseUrl?: string } = { token };
51
+ if (trimmedCookie) payload.cookie = trimmedCookie;
52
+ if (trimmedBaseUrl) payload.baseUrl = trimmedBaseUrl;
53
+ return JSON.stringify(payload);
27
54
  }