@oh-my-pi/pi-catalog 16.1.22 → 16.1.23

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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.1.23] - 2026-06-26
6
+
7
+ ### Added
8
+
9
+ - Added `OpenAICompat.qwenPreserveThinking` — auto-enabled when the resolved `thinkingFormat` is `"qwen"` or `"qwen-chat-template"` AND `replayReasoningContent` is on (i.e. the four built-in local OpenAI-compatible providers, or a custom provider pointed at a loopback / RFC1918 / `*.local` baseUrl). Pairs with the chat-completions encoder change so the request body carries `preserve_thinking: true` (twin top-level + `chat_template_kwargs` emission), keeping Qwen3.6+ from stripping `<think>...</think>` off older assistant turns and breaking the local slot's KV cache between user messages. Non-Qwen chat templates ignore the parameter, so the flag stays a no-op outside the Qwen path; users on a cloud Qwen host (Alibaba Dashscope / Qwen Portal) can opt in with `compat.qwenPreserveThinking: true`. ([#3541](https://github.com/can1357/oh-my-pi/issues/3541))
10
+ - Added CoreWeave Serverless Inference as an OpenAI-compatible provider with models.dev-backed bundled catalog metadata.
11
+
5
12
  ## [16.1.22] - 2026-06-26
6
13
 
7
14
  ### Added
@@ -12,5 +12,6 @@ export * from "./types";
12
12
  export * from "./utils";
13
13
  export * from "./variant-collapse";
14
14
  export * from "./wire/codex";
15
+ export * from "./wire/coreweave";
15
16
  export * from "./wire/gemini-headers";
16
17
  export * from "./wire/github-copilot";
@@ -339,6 +339,14 @@ export declare const CATALOG_PROVIDERS: readonly [{
339
339
  readonly label: "Wafer Serverless";
340
340
  readonly oauthProvider: "wafer-serverless";
341
341
  };
342
+ }, {
343
+ readonly id: "coreweave";
344
+ readonly defaultModel: "openai/gpt-oss-120b";
345
+ readonly envVars: readonly ["COREWEAVE_API_KEY", "WANDB_API_KEY"];
346
+ readonly createModelManagerOptions: (config: ModelManagerConfig) => import("..").ModelManagerOptions<"openai-completions", unknown>;
347
+ readonly catalogDiscovery: {
348
+ readonly label: "CoreWeave Serverless Inference";
349
+ };
342
350
  }, {
343
351
  readonly id: "xai";
344
352
  readonly defaultModel: "grok-4-fast-non-reasoning";
@@ -34,10 +34,12 @@ export interface ModelsDevModel {
34
34
  * by the generator's policy pass (scripts/generated-policies.ts).
35
35
  */
36
36
  export declare const ANTHROPIC_CURATED_FALLBACK_MODELS: readonly ModelSpec<"anthropic-messages">[];
37
+ type SimpleProviderDiscoveryHeaders = Record<string, string> | (() => Record<string, string> | undefined);
37
38
  type SimpleProviderConfig = {
38
39
  apiKey?: string;
39
40
  baseUrl?: string;
40
41
  fetch?: FetchImpl;
42
+ headers?: SimpleProviderDiscoveryHeaders;
41
43
  };
42
44
  export declare function createSimpleOpenAICompletionsOptions(providerId: Parameters<typeof getBundledModels>[0], defaultBaseUrl: string, config?: SimpleProviderConfig): ModelManagerOptions<"openai-completions">;
43
45
  export interface UmansModelManagerConfig {
@@ -307,6 +309,12 @@ export interface TogetherModelManagerConfig {
307
309
  fetch?: FetchImpl;
308
310
  }
309
311
  export declare function togetherModelManagerOptions(config?: TogetherModelManagerConfig): ModelManagerOptions<"openai-completions">;
312
+ export interface CoreWeaveModelManagerConfig {
313
+ apiKey?: string;
314
+ baseUrl?: string;
315
+ fetch?: FetchImpl;
316
+ }
317
+ export declare function coreWeaveModelManagerOptions(config?: CoreWeaveModelManagerConfig): ModelManagerOptions<"openai-completions">;
310
318
  export interface MoonshotModelManagerConfig {
311
319
  apiKey?: string;
312
320
  baseUrl?: string;
@@ -199,6 +199,28 @@ export interface OpenAICompat {
199
199
  * models).
200
200
  */
201
201
  replayReasoningContent?: boolean;
202
+ /**
203
+ * Send `preserve_thinking: true` so the Qwen3.6+ chat template renders
204
+ * `<think>...</think>` markup for EVERY assistant turn (not just turns
205
+ * after the last user message). Without it, the template strips the think
206
+ * block from older assistant turns:
207
+ *
208
+ * ```jinja
209
+ * {%- if (preserve_thinking is defined and preserve_thinking is true)
210
+ * or (loop.index0 > ns.last_query_index) %}
211
+ * <|im_start|>assistant\n<think>\n{rc}\n</think>\n\n{content}
212
+ * {%- else %}
213
+ * <|im_start|>assistant\n{content}
214
+ * ```
215
+ *
216
+ * The cache from the original generation has `<think>...</think>` tokens,
217
+ * so once a new user message arrives the prior assistant turns become
218
+ * "older" and the stripped re-render diverges — full prompt re-processing
219
+ * on SWA models (#3541). Default: auto-detected (Qwen thinking format on
220
+ * a local llama.cpp-style backend, paired with `replayReasoningContent`).
221
+ * Non-Qwen templates ignore the flag, so the auto-detection is safe.
222
+ */
223
+ qwenPreserveThinking?: boolean;
202
224
  /** Whether assistant tool-call messages must include non-empty content. Default: false. */
203
225
  requiresAssistantContentForToolCalls?: boolean;
204
226
  /** Whether the provider supports the `tool_choice` parameter. Default: true. */
@@ -406,6 +428,7 @@ export interface ResolvedOpenAISharedCompat {
406
428
  requiresReasoningContentForAllAssistantTurns: boolean;
407
429
  allowsSyntheticReasoningContentForToolCalls: boolean;
408
430
  replayReasoningContent: boolean;
431
+ qwenPreserveThinking: boolean;
409
432
  requiresThinkingAsText: boolean;
410
433
  requiresMistralToolIds: boolean;
411
434
  requiresToolResultName: boolean;
@@ -433,7 +456,7 @@ export interface ResolvedOpenAISharedCompat {
433
456
  * `buildModel`; request handlers read fields and never detect, resolve, or
434
457
  * allocate.
435
458
  */
436
- export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "thinkingFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "replayReasoningContent" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamIdleTimeoutMs" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "requiresJuiceZeroHack" | "enableGeminiThinkingLoopGuard" | "whenThinking">> & {
459
+ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "thinkingFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "replayReasoningContent" | "qwenPreserveThinking" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamIdleTimeoutMs" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "requiresJuiceZeroHack" | "enableGeminiThinkingLoopGuard" | "whenThinking">> & {
437
460
  vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
438
461
  extraBody?: OpenAICompat["extraBody"];
439
462
  cacheControlFormat?: OpenAICompat["cacheControlFormat"];
@@ -0,0 +1,11 @@
1
+ export declare const COREWEAVE_PROJECT_HEADER: "OpenAI-Project";
2
+ export interface CoreWeaveProjectEnv {
3
+ [key: string]: string | undefined;
4
+ COREWEAVE_PROJECT?: string;
5
+ WANDB_INFERENCE_PROJECT?: string;
6
+ WANDB_ENTITY?: string;
7
+ WANDB_PROJECT?: string;
8
+ }
9
+ export declare function resolveCoreWeaveProject(env: CoreWeaveProjectEnv): string | undefined;
10
+ export declare function coreWeaveProjectHeaders(env: CoreWeaveProjectEnv): Record<string, string> | undefined;
11
+ export declare function hasCoreWeaveProjectHeader(headers: Record<string, string>): boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "16.1.22",
4
+ "version": "16.1.23",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -34,12 +34,12 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@bufbuild/protobuf": "^2.12.0",
37
- "@oh-my-pi/pi-utils": "16.1.22",
37
+ "@oh-my-pi/pi-utils": "16.1.23",
38
38
  "arktype": "^2.2.0",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.1.22",
42
+ "@oh-my-pi/pi-ai": "16.1.23",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -468,6 +468,20 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
468
468
  replayReasoningContent:
469
469
  !PROXY_OPENAI_COMPAT_PROVIDERS.has(provider) &&
470
470
  (LOCAL_OPENAI_COMPAT_PROVIDERS.has(provider) || hasLocalLoopbackBaseUrl(baseUrl)),
471
+ // `preserve_thinking: true` makes the Qwen3.6+ chat template render
472
+ // `<think>...</think>` for older assistant turns too, instead of
473
+ // stripping it the moment a new user message moves them past
474
+ // `last_query_index`. Without it, the slot's KV cache (which holds the
475
+ // raw `<think>X</think>` tokens emitted during generation) diverges
476
+ // from the next-turn render and llama.cpp falls back to full prompt
477
+ // re-processing — the exact symptom reported in #3541. Auto-enabled
478
+ // for Qwen thinking dialects on local llama.cpp-style backends (paired
479
+ // with `replayReasoningContent` above). Non-Qwen templates ignore the
480
+ // parameter, so the flag stays a no-op outside the Qwen path.
481
+ qwenPreserveThinking:
482
+ (thinkingFormat === "qwen" || thinkingFormat === "qwen-chat-template") &&
483
+ !PROXY_OPENAI_COMPAT_PROVIDERS.has(provider) &&
484
+ (LOCAL_OPENAI_COMPAT_PROVIDERS.has(provider) || hasLocalLoopbackBaseUrl(baseUrl)),
471
485
  requiresAssistantContentForToolCalls: isKimiModel || isDirectDeepseekReasoning,
472
486
  cacheControlFormat: isOpenRouter && spec.id.startsWith("anthropic/") ? "anthropic" : undefined,
473
487
  openRouterRouting: undefined,
@@ -589,6 +603,9 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
589
603
  // not via a top-level `reasoning_content` field — this flag is
590
604
  // chat-completions-only.
591
605
  replayReasoningContent: false,
606
+ // Responses-only; the Qwen `preserve_thinking` template knob lives on
607
+ // the chat-completions wire shape, never on Responses.
608
+ qwenPreserveThinking: false,
592
609
  requiresThinkingAsText: false,
593
610
  requiresMistralToolIds: false,
594
611
  requiresToolResultName: false,
package/src/index.ts CHANGED
@@ -12,5 +12,6 @@ export * from "./types";
12
12
  export * from "./utils";
13
13
  export * from "./variant-collapse";
14
14
  export * from "./wire/codex";
15
+ export * from "./wire/coreweave";
15
16
  export * from "./wire/gemini-headers";
16
17
  export * from "./wire/github-copilot";
package/src/models.json CHANGED
@@ -13487,6 +13487,802 @@
13487
13487
  }
13488
13488
  }
13489
13489
  },
13490
+ "coreweave": {
13491
+ "deepseek-ai/DeepSeek-V3.1": {
13492
+ "id": "deepseek-ai/DeepSeek-V3.1",
13493
+ "name": "DeepSeek V3.1",
13494
+ "api": "openai-completions",
13495
+ "provider": "coreweave",
13496
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13497
+ "reasoning": false,
13498
+ "input": [
13499
+ "text"
13500
+ ],
13501
+ "cost": {
13502
+ "input": 0.55,
13503
+ "output": 1.65,
13504
+ "cacheRead": 0,
13505
+ "cacheWrite": 0
13506
+ },
13507
+ "contextWindow": 161000,
13508
+ "maxTokens": 161000
13509
+ },
13510
+ "deepseek-ai/DeepSeek-V4-Flash": {
13511
+ "id": "deepseek-ai/DeepSeek-V4-Flash",
13512
+ "name": "DeepSeek V4 Flash",
13513
+ "api": "openai-completions",
13514
+ "provider": "coreweave",
13515
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13516
+ "reasoning": true,
13517
+ "input": [
13518
+ "text"
13519
+ ],
13520
+ "cost": {
13521
+ "input": 0,
13522
+ "output": 0,
13523
+ "cacheRead": 0,
13524
+ "cacheWrite": 0
13525
+ },
13526
+ "contextWindow": 1048576,
13527
+ "maxTokens": 384000,
13528
+ "thinking": {
13529
+ "mode": "effort",
13530
+ "efforts": [
13531
+ "minimal",
13532
+ "low",
13533
+ "medium",
13534
+ "high",
13535
+ "xhigh"
13536
+ ],
13537
+ "effortMap": {
13538
+ "minimal": "high",
13539
+ "low": "high",
13540
+ "medium": "high",
13541
+ "high": "high",
13542
+ "xhigh": "max"
13543
+ }
13544
+ }
13545
+ },
13546
+ "deepseek-ai/DeepSeek-V4-Pro": {
13547
+ "id": "deepseek-ai/DeepSeek-V4-Pro",
13548
+ "name": "DeepSeek V4 Pro",
13549
+ "api": "openai-completions",
13550
+ "provider": "coreweave",
13551
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13552
+ "reasoning": true,
13553
+ "input": [
13554
+ "text"
13555
+ ],
13556
+ "cost": {
13557
+ "input": 0,
13558
+ "output": 0,
13559
+ "cacheRead": 0,
13560
+ "cacheWrite": 0
13561
+ },
13562
+ "contextWindow": 1048576,
13563
+ "maxTokens": 393216,
13564
+ "thinking": {
13565
+ "mode": "effort",
13566
+ "efforts": [
13567
+ "minimal",
13568
+ "low",
13569
+ "medium",
13570
+ "high",
13571
+ "xhigh"
13572
+ ],
13573
+ "effortMap": {
13574
+ "minimal": "high",
13575
+ "low": "high",
13576
+ "medium": "high",
13577
+ "high": "high",
13578
+ "xhigh": "max"
13579
+ }
13580
+ }
13581
+ },
13582
+ "google/gemma-4-31B-it": {
13583
+ "id": "google/gemma-4-31B-it",
13584
+ "name": "Gemma 4 31B Instruct",
13585
+ "api": "openai-completions",
13586
+ "provider": "coreweave",
13587
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13588
+ "reasoning": true,
13589
+ "input": [
13590
+ "text",
13591
+ "image"
13592
+ ],
13593
+ "cost": {
13594
+ "input": 0,
13595
+ "output": 0,
13596
+ "cacheRead": 0,
13597
+ "cacheWrite": 0
13598
+ },
13599
+ "contextWindow": 262144,
13600
+ "maxTokens": 131072,
13601
+ "thinking": {
13602
+ "mode": "effort",
13603
+ "efforts": [
13604
+ "minimal",
13605
+ "low",
13606
+ "medium",
13607
+ "high",
13608
+ "xhigh"
13609
+ ]
13610
+ }
13611
+ },
13612
+ "ibm-granite/granite-4.1-8b": {
13613
+ "id": "ibm-granite/granite-4.1-8b",
13614
+ "name": "Granite 4.1 8B",
13615
+ "api": "openai-completions",
13616
+ "provider": "coreweave",
13617
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13618
+ "reasoning": false,
13619
+ "input": [
13620
+ "text"
13621
+ ],
13622
+ "cost": {
13623
+ "input": 0,
13624
+ "output": 0,
13625
+ "cacheRead": 0,
13626
+ "cacheWrite": 0
13627
+ },
13628
+ "contextWindow": 131072,
13629
+ "maxTokens": 131072
13630
+ },
13631
+ "JetBrains/Mellum2-12B-A2.5B-Instruct": {
13632
+ "id": "JetBrains/Mellum2-12B-A2.5B-Instruct",
13633
+ "name": "JetBrains/Mellum2-12B-A2.5B-Instruct",
13634
+ "api": "openai-completions",
13635
+ "provider": "coreweave",
13636
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13637
+ "reasoning": false,
13638
+ "input": [
13639
+ "text"
13640
+ ],
13641
+ "cost": {
13642
+ "input": 0,
13643
+ "output": 0,
13644
+ "cacheRead": 0,
13645
+ "cacheWrite": 0
13646
+ },
13647
+ "contextWindow": null,
13648
+ "maxTokens": null
13649
+ },
13650
+ "meta-llama/Llama-3.1-70B-Instruct": {
13651
+ "id": "meta-llama/Llama-3.1-70B-Instruct",
13652
+ "name": "Llama 3.1 70B",
13653
+ "api": "openai-completions",
13654
+ "provider": "coreweave",
13655
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13656
+ "reasoning": false,
13657
+ "input": [
13658
+ "text"
13659
+ ],
13660
+ "cost": {
13661
+ "input": 0.8,
13662
+ "output": 0.8,
13663
+ "cacheRead": 0,
13664
+ "cacheWrite": 0
13665
+ },
13666
+ "contextWindow": 128000,
13667
+ "maxTokens": 128000
13668
+ },
13669
+ "meta-llama/Llama-3.1-8B-Instruct": {
13670
+ "id": "meta-llama/Llama-3.1-8B-Instruct",
13671
+ "name": "Meta-Llama-3.1-8B-Instruct",
13672
+ "api": "openai-completions",
13673
+ "provider": "coreweave",
13674
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13675
+ "reasoning": true,
13676
+ "input": [
13677
+ "text"
13678
+ ],
13679
+ "cost": {
13680
+ "input": 0.22,
13681
+ "output": 0.22,
13682
+ "cacheRead": 0,
13683
+ "cacheWrite": 0
13684
+ },
13685
+ "contextWindow": 128000,
13686
+ "maxTokens": 128000,
13687
+ "thinking": {
13688
+ "mode": "effort",
13689
+ "efforts": [
13690
+ "minimal",
13691
+ "low",
13692
+ "medium",
13693
+ "high",
13694
+ "xhigh"
13695
+ ]
13696
+ }
13697
+ },
13698
+ "meta-llama/Llama-3.3-70B-Instruct": {
13699
+ "id": "meta-llama/Llama-3.3-70B-Instruct",
13700
+ "name": "Llama-3.3-70B-Instruct",
13701
+ "api": "openai-completions",
13702
+ "provider": "coreweave",
13703
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13704
+ "reasoning": true,
13705
+ "input": [
13706
+ "text"
13707
+ ],
13708
+ "cost": {
13709
+ "input": 0.71,
13710
+ "output": 0.71,
13711
+ "cacheRead": 0,
13712
+ "cacheWrite": 0
13713
+ },
13714
+ "contextWindow": 128000,
13715
+ "maxTokens": 128000,
13716
+ "thinking": {
13717
+ "mode": "effort",
13718
+ "efforts": [
13719
+ "minimal",
13720
+ "low",
13721
+ "medium",
13722
+ "high",
13723
+ "xhigh"
13724
+ ]
13725
+ }
13726
+ },
13727
+ "meta-llama/Llama-4-Scout-17B-16E-Instruct": {
13728
+ "id": "meta-llama/Llama-4-Scout-17B-16E-Instruct",
13729
+ "name": "Llama 4 Scout 17B 16E Instruct",
13730
+ "api": "openai-completions",
13731
+ "provider": "coreweave",
13732
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13733
+ "reasoning": true,
13734
+ "input": [
13735
+ "text",
13736
+ "image"
13737
+ ],
13738
+ "cost": {
13739
+ "input": 0.17,
13740
+ "output": 0.66,
13741
+ "cacheRead": 0,
13742
+ "cacheWrite": 0
13743
+ },
13744
+ "contextWindow": 64000,
13745
+ "maxTokens": 64000,
13746
+ "thinking": {
13747
+ "mode": "effort",
13748
+ "efforts": [
13749
+ "minimal",
13750
+ "low",
13751
+ "medium",
13752
+ "high",
13753
+ "xhigh"
13754
+ ]
13755
+ }
13756
+ },
13757
+ "microsoft/Phi-4-mini-instruct": {
13758
+ "id": "microsoft/Phi-4-mini-instruct",
13759
+ "name": "Phi-4-mini-instruct",
13760
+ "api": "openai-completions",
13761
+ "provider": "coreweave",
13762
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13763
+ "reasoning": true,
13764
+ "input": [
13765
+ "text"
13766
+ ],
13767
+ "cost": {
13768
+ "input": 0.08,
13769
+ "output": 0.35,
13770
+ "cacheRead": 0,
13771
+ "cacheWrite": 0
13772
+ },
13773
+ "contextWindow": 128000,
13774
+ "maxTokens": 128000,
13775
+ "thinking": {
13776
+ "mode": "effort",
13777
+ "efforts": [
13778
+ "minimal",
13779
+ "low",
13780
+ "medium",
13781
+ "high",
13782
+ "xhigh"
13783
+ ]
13784
+ }
13785
+ },
13786
+ "MiniMaxAI/MiniMax-M2.5": {
13787
+ "id": "MiniMaxAI/MiniMax-M2.5",
13788
+ "name": "MiniMax M2.5",
13789
+ "api": "openai-completions",
13790
+ "provider": "coreweave",
13791
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13792
+ "reasoning": false,
13793
+ "input": [
13794
+ "text"
13795
+ ],
13796
+ "cost": {
13797
+ "input": 0.3,
13798
+ "output": 1.2,
13799
+ "cacheRead": 0,
13800
+ "cacheWrite": 0
13801
+ },
13802
+ "contextWindow": 196608,
13803
+ "maxTokens": 196608
13804
+ },
13805
+ "moonshotai/Kimi-K2.5": {
13806
+ "id": "moonshotai/Kimi-K2.5",
13807
+ "name": "Kimi K2.5",
13808
+ "api": "openai-completions",
13809
+ "provider": "coreweave",
13810
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13811
+ "reasoning": true,
13812
+ "input": [
13813
+ "text",
13814
+ "image"
13815
+ ],
13816
+ "cost": {
13817
+ "input": 0.5,
13818
+ "output": 2.85,
13819
+ "cacheRead": 0,
13820
+ "cacheWrite": 0
13821
+ },
13822
+ "contextWindow": 262144,
13823
+ "maxTokens": 262144,
13824
+ "thinking": {
13825
+ "mode": "effort",
13826
+ "efforts": [
13827
+ "minimal",
13828
+ "low",
13829
+ "medium",
13830
+ "high",
13831
+ "xhigh"
13832
+ ]
13833
+ }
13834
+ },
13835
+ "moonshotai/Kimi-K2.6": {
13836
+ "id": "moonshotai/Kimi-K2.6",
13837
+ "name": "Kimi-K2.6",
13838
+ "api": "openai-completions",
13839
+ "provider": "coreweave",
13840
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13841
+ "reasoning": true,
13842
+ "input": [
13843
+ "text",
13844
+ "image"
13845
+ ],
13846
+ "cost": {
13847
+ "input": 0,
13848
+ "output": 0,
13849
+ "cacheRead": 0,
13850
+ "cacheWrite": 0
13851
+ },
13852
+ "contextWindow": 262144,
13853
+ "maxTokens": 262144,
13854
+ "thinking": {
13855
+ "mode": "effort",
13856
+ "efforts": [
13857
+ "minimal",
13858
+ "low",
13859
+ "medium",
13860
+ "high",
13861
+ "xhigh"
13862
+ ]
13863
+ }
13864
+ },
13865
+ "moonshotai/Kimi-K2.7-Code": {
13866
+ "id": "moonshotai/Kimi-K2.7-Code",
13867
+ "name": "Kimi K2.7 Code",
13868
+ "api": "openai-completions",
13869
+ "provider": "coreweave",
13870
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13871
+ "reasoning": true,
13872
+ "input": [
13873
+ "text",
13874
+ "image"
13875
+ ],
13876
+ "cost": {
13877
+ "input": 0,
13878
+ "output": 0,
13879
+ "cacheRead": 0,
13880
+ "cacheWrite": 0
13881
+ },
13882
+ "contextWindow": 262144,
13883
+ "maxTokens": 262144,
13884
+ "thinking": {
13885
+ "mode": "effort",
13886
+ "efforts": [
13887
+ "minimal",
13888
+ "low",
13889
+ "medium",
13890
+ "high",
13891
+ "xhigh"
13892
+ ]
13893
+ }
13894
+ },
13895
+ "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8": {
13896
+ "id": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8",
13897
+ "name": "NVIDIA Nemotron 3 Super 120B",
13898
+ "api": "openai-completions",
13899
+ "provider": "coreweave",
13900
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13901
+ "reasoning": false,
13902
+ "input": [
13903
+ "text"
13904
+ ],
13905
+ "cost": {
13906
+ "input": 0.2,
13907
+ "output": 0.8,
13908
+ "cacheRead": 0,
13909
+ "cacheWrite": 0
13910
+ },
13911
+ "contextWindow": 262144,
13912
+ "maxTokens": 262144
13913
+ },
13914
+ "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B": {
13915
+ "id": "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
13916
+ "name": "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
13917
+ "api": "openai-completions",
13918
+ "provider": "coreweave",
13919
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13920
+ "reasoning": false,
13921
+ "input": [
13922
+ "text"
13923
+ ],
13924
+ "cost": {
13925
+ "input": 0,
13926
+ "output": 0,
13927
+ "cacheRead": 0,
13928
+ "cacheWrite": 0
13929
+ },
13930
+ "contextWindow": null,
13931
+ "maxTokens": null
13932
+ },
13933
+ "openai/gpt-oss-120b": {
13934
+ "id": "openai/gpt-oss-120b",
13935
+ "name": "gpt-oss-120b",
13936
+ "api": "openai-completions",
13937
+ "provider": "coreweave",
13938
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13939
+ "reasoning": true,
13940
+ "input": [
13941
+ "text"
13942
+ ],
13943
+ "cost": {
13944
+ "input": 0.15,
13945
+ "output": 0.6,
13946
+ "cacheRead": 0,
13947
+ "cacheWrite": 0
13948
+ },
13949
+ "contextWindow": 131072,
13950
+ "maxTokens": 131072,
13951
+ "thinking": {
13952
+ "mode": "effort",
13953
+ "efforts": [
13954
+ "low",
13955
+ "medium",
13956
+ "high"
13957
+ ]
13958
+ }
13959
+ },
13960
+ "openai/gpt-oss-20b": {
13961
+ "id": "openai/gpt-oss-20b",
13962
+ "name": "gpt-oss-20b",
13963
+ "api": "openai-completions",
13964
+ "provider": "coreweave",
13965
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13966
+ "reasoning": true,
13967
+ "input": [
13968
+ "text"
13969
+ ],
13970
+ "cost": {
13971
+ "input": 0.05,
13972
+ "output": 0.2,
13973
+ "cacheRead": 0,
13974
+ "cacheWrite": 0
13975
+ },
13976
+ "contextWindow": 131072,
13977
+ "maxTokens": 131072,
13978
+ "thinking": {
13979
+ "mode": "effort",
13980
+ "efforts": [
13981
+ "low",
13982
+ "medium",
13983
+ "high"
13984
+ ]
13985
+ }
13986
+ },
13987
+ "OpenPipe/Qwen3-14B-Instruct": {
13988
+ "id": "OpenPipe/Qwen3-14B-Instruct",
13989
+ "name": "OpenPipe Qwen3 14B Instruct",
13990
+ "api": "openai-completions",
13991
+ "provider": "coreweave",
13992
+ "baseUrl": "https://api.inference.wandb.ai/v1",
13993
+ "reasoning": false,
13994
+ "input": [
13995
+ "text"
13996
+ ],
13997
+ "cost": {
13998
+ "input": 0.05,
13999
+ "output": 0.22,
14000
+ "cacheRead": 0,
14001
+ "cacheWrite": 0
14002
+ },
14003
+ "contextWindow": 32768,
14004
+ "maxTokens": 32768
14005
+ },
14006
+ "Qwen/Qwen3-235B-A22B-Instruct-2507": {
14007
+ "id": "Qwen/Qwen3-235B-A22B-Instruct-2507",
14008
+ "name": "Qwen3 235B A22B Instruct 2507",
14009
+ "api": "openai-completions",
14010
+ "provider": "coreweave",
14011
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14012
+ "reasoning": false,
14013
+ "input": [
14014
+ "text"
14015
+ ],
14016
+ "cost": {
14017
+ "input": 0.1,
14018
+ "output": 0.1,
14019
+ "cacheRead": 0,
14020
+ "cacheWrite": 0
14021
+ },
14022
+ "contextWindow": 262144,
14023
+ "maxTokens": 262144
14024
+ },
14025
+ "Qwen/Qwen3-235B-A22B-Thinking-2507": {
14026
+ "id": "Qwen/Qwen3-235B-A22B-Thinking-2507",
14027
+ "name": "Qwen3-235B-A22B-Thinking-2507",
14028
+ "api": "openai-completions",
14029
+ "provider": "coreweave",
14030
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14031
+ "reasoning": true,
14032
+ "input": [
14033
+ "text"
14034
+ ],
14035
+ "cost": {
14036
+ "input": 0.1,
14037
+ "output": 0.1,
14038
+ "cacheRead": 0,
14039
+ "cacheWrite": 0
14040
+ },
14041
+ "contextWindow": 262144,
14042
+ "maxTokens": 262144,
14043
+ "thinking": {
14044
+ "mode": "effort",
14045
+ "efforts": [
14046
+ "minimal",
14047
+ "low",
14048
+ "medium",
14049
+ "high"
14050
+ ],
14051
+ "requiresEffort": true
14052
+ }
14053
+ },
14054
+ "Qwen/Qwen3-30B-A3B-Instruct-2507": {
14055
+ "id": "Qwen/Qwen3-30B-A3B-Instruct-2507",
14056
+ "name": "Qwen3 30B A3B Instruct 2507",
14057
+ "api": "openai-completions",
14058
+ "provider": "coreweave",
14059
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14060
+ "reasoning": false,
14061
+ "input": [
14062
+ "text"
14063
+ ],
14064
+ "cost": {
14065
+ "input": 0.1,
14066
+ "output": 0.3,
14067
+ "cacheRead": 0,
14068
+ "cacheWrite": 0
14069
+ },
14070
+ "contextWindow": 262144,
14071
+ "maxTokens": 262144
14072
+ },
14073
+ "Qwen/Qwen3-Coder-480B-A35B-Instruct": {
14074
+ "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct",
14075
+ "name": "Qwen3-Coder-480B-A35B-Instruct",
14076
+ "api": "openai-completions",
14077
+ "provider": "coreweave",
14078
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14079
+ "reasoning": false,
14080
+ "input": [
14081
+ "text"
14082
+ ],
14083
+ "cost": {
14084
+ "input": 1,
14085
+ "output": 1.5,
14086
+ "cacheRead": 0,
14087
+ "cacheWrite": 0
14088
+ },
14089
+ "contextWindow": 262144,
14090
+ "maxTokens": 262144
14091
+ },
14092
+ "Qwen/Qwen3.5-27B": {
14093
+ "id": "Qwen/Qwen3.5-27B",
14094
+ "name": "Qwen3.5 27B",
14095
+ "api": "openai-completions",
14096
+ "provider": "coreweave",
14097
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14098
+ "reasoning": true,
14099
+ "input": [
14100
+ "text",
14101
+ "image"
14102
+ ],
14103
+ "cost": {
14104
+ "input": 0,
14105
+ "output": 0,
14106
+ "cacheRead": 0,
14107
+ "cacheWrite": 0
14108
+ },
14109
+ "contextWindow": 262144,
14110
+ "maxTokens": 65536,
14111
+ "thinking": {
14112
+ "mode": "effort",
14113
+ "efforts": [
14114
+ "minimal",
14115
+ "low",
14116
+ "medium",
14117
+ "high"
14118
+ ]
14119
+ }
14120
+ },
14121
+ "Qwen/Qwen3.5-35B-A3B": {
14122
+ "id": "Qwen/Qwen3.5-35B-A3B",
14123
+ "name": "Qwen3.5 35B-A3B",
14124
+ "api": "openai-completions",
14125
+ "provider": "coreweave",
14126
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14127
+ "reasoning": true,
14128
+ "input": [
14129
+ "text",
14130
+ "image"
14131
+ ],
14132
+ "cost": {
14133
+ "input": 0,
14134
+ "output": 0,
14135
+ "cacheRead": 0,
14136
+ "cacheWrite": 0
14137
+ },
14138
+ "contextWindow": 262144,
14139
+ "maxTokens": 65536,
14140
+ "thinking": {
14141
+ "mode": "effort",
14142
+ "efforts": [
14143
+ "minimal",
14144
+ "low",
14145
+ "medium",
14146
+ "high"
14147
+ ]
14148
+ }
14149
+ },
14150
+ "Qwen/Qwen3.6-27B": {
14151
+ "id": "Qwen/Qwen3.6-27B",
14152
+ "name": "Qwen3.6 27B",
14153
+ "api": "openai-completions",
14154
+ "provider": "coreweave",
14155
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14156
+ "reasoning": true,
14157
+ "input": [
14158
+ "text",
14159
+ "image"
14160
+ ],
14161
+ "cost": {
14162
+ "input": 0,
14163
+ "output": 0,
14164
+ "cacheRead": 0,
14165
+ "cacheWrite": 0
14166
+ },
14167
+ "contextWindow": 262144,
14168
+ "maxTokens": 65536,
14169
+ "thinking": {
14170
+ "mode": "effort",
14171
+ "efforts": [
14172
+ "minimal",
14173
+ "low",
14174
+ "medium",
14175
+ "high"
14176
+ ]
14177
+ }
14178
+ },
14179
+ "Qwen/Qwen3.6-35B-A3B": {
14180
+ "id": "Qwen/Qwen3.6-35B-A3B",
14181
+ "name": "Qwen3.6 35B-A3B",
14182
+ "api": "openai-completions",
14183
+ "provider": "coreweave",
14184
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14185
+ "reasoning": true,
14186
+ "input": [
14187
+ "text",
14188
+ "image"
14189
+ ],
14190
+ "cost": {
14191
+ "input": 0,
14192
+ "output": 0,
14193
+ "cacheRead": 0,
14194
+ "cacheWrite": 0
14195
+ },
14196
+ "contextWindow": 262144,
14197
+ "maxTokens": 65536,
14198
+ "thinking": {
14199
+ "mode": "effort",
14200
+ "efforts": [
14201
+ "minimal",
14202
+ "low",
14203
+ "medium",
14204
+ "high"
14205
+ ]
14206
+ }
14207
+ },
14208
+ "zai-org/GLM-5-FP8": {
14209
+ "id": "zai-org/GLM-5-FP8",
14210
+ "name": "GLM 5",
14211
+ "api": "openai-completions",
14212
+ "provider": "coreweave",
14213
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14214
+ "reasoning": false,
14215
+ "input": [
14216
+ "text"
14217
+ ],
14218
+ "cost": {
14219
+ "input": 1,
14220
+ "output": 3.2,
14221
+ "cacheRead": 0,
14222
+ "cacheWrite": 0
14223
+ },
14224
+ "contextWindow": 200000,
14225
+ "maxTokens": 200000
14226
+ },
14227
+ "zai-org/GLM-5.1": {
14228
+ "id": "zai-org/GLM-5.1",
14229
+ "name": "GLM-5.1",
14230
+ "api": "openai-completions",
14231
+ "provider": "coreweave",
14232
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14233
+ "reasoning": true,
14234
+ "input": [
14235
+ "text"
14236
+ ],
14237
+ "cost": {
14238
+ "input": 1.4,
14239
+ "output": 4.4,
14240
+ "cacheRead": 0.26,
14241
+ "cacheWrite": 0
14242
+ },
14243
+ "contextWindow": 200000,
14244
+ "maxTokens": 131072,
14245
+ "thinking": {
14246
+ "mode": "effort",
14247
+ "efforts": [
14248
+ "minimal",
14249
+ "low",
14250
+ "medium",
14251
+ "high",
14252
+ "xhigh"
14253
+ ]
14254
+ }
14255
+ },
14256
+ "zai-org/GLM-5.2": {
14257
+ "id": "zai-org/GLM-5.2",
14258
+ "name": "GLM-5.2",
14259
+ "api": "openai-completions",
14260
+ "provider": "coreweave",
14261
+ "baseUrl": "https://api.inference.wandb.ai/v1",
14262
+ "reasoning": true,
14263
+ "input": [
14264
+ "text"
14265
+ ],
14266
+ "cost": {
14267
+ "input": 0,
14268
+ "output": 0,
14269
+ "cacheRead": 0,
14270
+ "cacheWrite": 0
14271
+ },
14272
+ "contextWindow": 262144,
14273
+ "maxTokens": 164000,
14274
+ "thinking": {
14275
+ "mode": "effort",
14276
+ "efforts": [
14277
+ "minimal",
14278
+ "low",
14279
+ "medium",
14280
+ "high",
14281
+ "xhigh"
14282
+ ]
14283
+ }
14284
+ }
14285
+ },
13490
14286
  "cursor": {
13491
14287
  "claude-4.5-opus-high": {
13492
14288
  "id": "claude-4.5-opus-high",
@@ -87658,4 +88454,4 @@
87658
88454
  }
87659
88455
  }
87660
88456
  }
87661
- }
88457
+ }
@@ -14,6 +14,7 @@ import {
14
14
  anthropicModelManagerOptions,
15
15
  cerebrasModelManagerOptions,
16
16
  cloudflareAiGatewayModelManagerOptions,
17
+ coreWeaveModelManagerOptions,
17
18
  deepseekModelManagerOptions,
18
19
  firepassModelManagerOptions,
19
20
  fireworksModelManagerOptions,
@@ -375,6 +376,13 @@ export const CATALOG_PROVIDERS = [
375
376
  oauthProvider: "wafer-serverless",
376
377
  },
377
378
  },
379
+ {
380
+ id: "coreweave",
381
+ defaultModel: "openai/gpt-oss-120b",
382
+ envVars: ["COREWEAVE_API_KEY", "WANDB_API_KEY"],
383
+ createModelManagerOptions: (config: ModelManagerConfig) => coreWeaveModelManagerOptions(config),
384
+ catalogDiscovery: { label: "CoreWeave Serverless Inference" },
385
+ },
378
386
  {
379
387
  id: "xai",
380
388
  defaultModel: "grok-4-fast-non-reasoning",
@@ -10,6 +10,7 @@ import type { ModelManagerOptions } from "../model-manager";
10
10
  import { getBundledModels } from "../models";
11
11
  import type { Api, FetchImpl, Model, ModelSpec, Provider, ThinkingConfig } from "../types";
12
12
  import { isAnthropicOAuthToken, isRecord, toBoolean, toNumber, toPositiveNumber } from "../utils";
13
+ import { coreWeaveProjectHeaders } from "../wire/coreweave";
13
14
  import {
14
15
  COPILOT_API_HEADERS,
15
16
  getGitHubCopilotBaseUrl,
@@ -470,7 +471,19 @@ function isLikelyNanoGptTextModelId(id: string): boolean {
470
471
  return !NANO_GPT_NON_TEXT_MODEL_TOKENS.some(token => normalized.includes(token));
471
472
  }
472
473
 
473
- type SimpleProviderConfig = { apiKey?: string; baseUrl?: string; fetch?: FetchImpl };
474
+ type SimpleProviderDiscoveryHeaders = Record<string, string> | (() => Record<string, string> | undefined);
475
+ type SimpleProviderConfig = {
476
+ apiKey?: string;
477
+ baseUrl?: string;
478
+ fetch?: FetchImpl;
479
+ headers?: SimpleProviderDiscoveryHeaders;
480
+ };
481
+
482
+ function resolveSimpleProviderHeaders(
483
+ headers: SimpleProviderDiscoveryHeaders | undefined,
484
+ ): Record<string, string> | undefined {
485
+ return typeof headers === "function" ? headers() : headers;
486
+ }
474
487
 
475
488
  export function createSimpleOpenAICompletionsOptions(
476
489
  providerId: Parameters<typeof getBundledModels>[0],
@@ -489,6 +502,7 @@ export function createSimpleOpenAICompletionsOptions(
489
502
  provider: providerId,
490
503
  baseUrl,
491
504
  apiKey,
505
+ headers: resolveSimpleProviderHeaders(config?.headers),
492
506
  mapModel: (entry, defaults) => {
493
507
  const reference = references.get(defaults.id);
494
508
  return mapWithBundledReference(entry, defaults, reference);
@@ -516,6 +530,7 @@ function createSimpleOpenAIResponsesOptions(
516
530
  provider: providerId,
517
531
  baseUrl,
518
532
  apiKey,
533
+ headers: resolveSimpleProviderHeaders(config?.headers),
519
534
  mapModel: (entry, defaults) => {
520
535
  const reference = references.get(defaults.id);
521
536
  return mapWithBundledReference(entry, defaults, reference);
@@ -2480,6 +2495,25 @@ export function togetherModelManagerOptions(
2480
2495
  return createSimpleOpenAICompletionsOptions("together", "https://api.together.xyz/v1", config);
2481
2496
  }
2482
2497
 
2498
+ // ---------------------------------------------------------------------------
2499
+ // 15.5 CoreWeave Serverless Inference
2500
+ // ---------------------------------------------------------------------------
2501
+
2502
+ export interface CoreWeaveModelManagerConfig {
2503
+ apiKey?: string;
2504
+ baseUrl?: string;
2505
+ fetch?: FetchImpl;
2506
+ }
2507
+
2508
+ export function coreWeaveModelManagerOptions(
2509
+ config?: CoreWeaveModelManagerConfig,
2510
+ ): ModelManagerOptions<"openai-completions"> {
2511
+ return createSimpleOpenAICompletionsOptions("coreweave", "https://api.inference.wandb.ai/v1", {
2512
+ ...config,
2513
+ headers: () => coreWeaveProjectHeaders(Bun.env),
2514
+ });
2515
+ }
2516
+
2483
2517
  // ---------------------------------------------------------------------------
2484
2518
  // 16. Moonshot
2485
2519
  // ---------------------------------------------------------------------------
@@ -3653,6 +3687,19 @@ const MODELS_DEV_PROVIDER_DESCRIPTORS_CORE: readonly ModelsDevProviderDescriptor
3653
3687
  openAiCompletionsDescriptor("cerebras", "cerebras", "https://api.cerebras.ai/v1"),
3654
3688
  // --- Together ---
3655
3689
  openAiCompletionsDescriptor("togetherai", "together", "https://api.together.xyz/v1"),
3690
+ // --- CoreWeave Serverless Inference ---
3691
+ openAiCompletionsDescriptor("wandb", "coreweave", "https://api.inference.wandb.ai/v1", {
3692
+ transformModel: model => {
3693
+ if (!model.id.startsWith("openai/gpt-oss-")) {
3694
+ return model;
3695
+ }
3696
+ return {
3697
+ ...model,
3698
+ reasoning: true,
3699
+ thinking: { mode: "effort", efforts: [Effort.Low, Effort.Medium, Effort.High] },
3700
+ };
3701
+ },
3702
+ }),
3656
3703
  // --- NVIDIA ---
3657
3704
  openAiCompletionsDescriptor("nvidia", "nvidia", "https://integrate.api.nvidia.com/v1", {
3658
3705
  defaultContextWindow: 131072,
package/src/types.ts CHANGED
@@ -236,6 +236,28 @@ export interface OpenAICompat {
236
236
  * models).
237
237
  */
238
238
  replayReasoningContent?: boolean;
239
+ /**
240
+ * Send `preserve_thinking: true` so the Qwen3.6+ chat template renders
241
+ * `<think>...</think>` markup for EVERY assistant turn (not just turns
242
+ * after the last user message). Without it, the template strips the think
243
+ * block from older assistant turns:
244
+ *
245
+ * ```jinja
246
+ * {%- if (preserve_thinking is defined and preserve_thinking is true)
247
+ * or (loop.index0 > ns.last_query_index) %}
248
+ * <|im_start|>assistant\n<think>\n{rc}\n</think>\n\n{content}
249
+ * {%- else %}
250
+ * <|im_start|>assistant\n{content}
251
+ * ```
252
+ *
253
+ * The cache from the original generation has `<think>...</think>` tokens,
254
+ * so once a new user message arrives the prior assistant turns become
255
+ * "older" and the stripped re-render diverges — full prompt re-processing
256
+ * on SWA models (#3541). Default: auto-detected (Qwen thinking format on
257
+ * a local llama.cpp-style backend, paired with `replayReasoningContent`).
258
+ * Non-Qwen templates ignore the flag, so the auto-detection is safe.
259
+ */
260
+ qwenPreserveThinking?: boolean;
239
261
  /** Whether assistant tool-call messages must include non-empty content. Default: false. */
240
262
  requiresAssistantContentForToolCalls?: boolean;
241
263
  /** Whether the provider supports the `tool_choice` parameter. Default: true. */
@@ -448,6 +470,7 @@ export interface ResolvedOpenAISharedCompat {
448
470
  requiresReasoningContentForAllAssistantTurns: boolean;
449
471
  allowsSyntheticReasoningContentForToolCalls: boolean;
450
472
  replayReasoningContent: boolean;
473
+ qwenPreserveThinking: boolean;
451
474
  requiresThinkingAsText: boolean;
452
475
  requiresMistralToolIds: boolean;
453
476
  requiresToolResultName: boolean;
@@ -498,6 +521,7 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
498
521
  | "requiresReasoningContentForAllAssistantTurns"
499
522
  | "allowsSyntheticReasoningContentForToolCalls"
500
523
  | "replayReasoningContent"
524
+ | "qwenPreserveThinking"
501
525
  | "requiresThinkingAsText"
502
526
  | "requiresMistralToolIds"
503
527
  | "requiresToolResultName"
@@ -0,0 +1,42 @@
1
+ export const COREWEAVE_PROJECT_HEADER = "OpenAI-Project" as const;
2
+
3
+ export interface CoreWeaveProjectEnv {
4
+ [key: string]: string | undefined;
5
+ COREWEAVE_PROJECT?: string;
6
+ WANDB_INFERENCE_PROJECT?: string;
7
+ WANDB_ENTITY?: string;
8
+ WANDB_PROJECT?: string;
9
+ }
10
+
11
+ function cleanEnvValue(value: string | undefined): string | undefined {
12
+ const trimmed = value?.trim();
13
+ return trimmed ? trimmed : undefined;
14
+ }
15
+
16
+ export function resolveCoreWeaveProject(env: CoreWeaveProjectEnv): string | undefined {
17
+ const explicitProject = cleanEnvValue(env.COREWEAVE_PROJECT) ?? cleanEnvValue(env.WANDB_INFERENCE_PROJECT);
18
+ if (explicitProject) {
19
+ return explicitProject;
20
+ }
21
+
22
+ const wandbProject = cleanEnvValue(env.WANDB_PROJECT);
23
+ if (!wandbProject) {
24
+ return undefined;
25
+ }
26
+ if (wandbProject.includes("/")) {
27
+ return wandbProject;
28
+ }
29
+
30
+ const wandbEntity = cleanEnvValue(env.WANDB_ENTITY);
31
+ return wandbEntity ? `${wandbEntity}/${wandbProject}` : undefined;
32
+ }
33
+
34
+ export function coreWeaveProjectHeaders(env: CoreWeaveProjectEnv): Record<string, string> | undefined {
35
+ const project = resolveCoreWeaveProject(env);
36
+ return project ? { [COREWEAVE_PROJECT_HEADER]: project } : undefined;
37
+ }
38
+
39
+ export function hasCoreWeaveProjectHeader(headers: Record<string, string>): boolean {
40
+ const normalized = COREWEAVE_PROJECT_HEADER.toLowerCase();
41
+ return Object.keys(headers).some(header => header.toLowerCase() === normalized);
42
+ }