@linxiraos/pi-catalog 1.1.26 → 1.2.0

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.
Files changed (128) hide show
  1. package/CHANGELOG.md +4 -6
  2. package/dist/types/compat/auth-ids.d.ts +2 -2
  3. package/dist/types/compat/collapse.d.ts +7 -0
  4. package/dist/types/compat/image-tokenization.d.ts +52 -0
  5. package/dist/types/compat/judgment-questions.d.ts +7 -0
  6. package/dist/types/compat/prompt-cache-lookback.d.ts +7 -0
  7. package/dist/types/compat/provider-ids.d.ts +1 -1
  8. package/dist/types/compat/reasoning-carry.d.ts +21 -0
  9. package/dist/types/compat/request-size.d.ts +7 -0
  10. package/dist/types/compat/taxonomy.d.ts +0 -10
  11. package/dist/types/compat/types.d.ts +4 -0
  12. package/dist/types/discovery/antigravity.d.ts +13 -3
  13. package/dist/types/hosts.d.ts +4 -0
  14. package/dist/types/model-cache.d.ts +6 -0
  15. package/dist/types/model-manager.d.ts +16 -0
  16. package/dist/types/provider-models/account-access.d.ts +11 -0
  17. package/dist/types/provider-models/google.d.ts +23 -1
  18. package/dist/types/provider-models/openai-compat.d.ts +19 -1
  19. package/dist/types/provider-models/special.d.ts +8 -0
  20. package/dist/types/types.d.ts +134 -23
  21. package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -10
  22. package/dist/types/wire/cloudflare.d.ts +10 -0
  23. package/dist/types/wire/factory-droid.d.ts +1 -1
  24. package/dist/types/wire/gemini-headers.d.ts +6 -3
  25. package/package.json +4 -4
  26. package/src/build.ts +39 -35
  27. package/src/compat/auth-ids.ts +6 -0
  28. package/src/compat/axes.ts +43 -5
  29. package/src/compat/cascade.ts +6 -1
  30. package/src/compat/collapse.d.ts +7 -0
  31. package/src/compat/collapse.ts +11 -0
  32. package/src/compat/image-tokenization.ts +166 -0
  33. package/src/compat/judgment-questions.ts +12 -0
  34. package/src/compat/prompt-cache-lookback.ts +23 -0
  35. package/src/compat/provider-ids.d.ts +1 -1
  36. package/src/compat/provider-ids.ts +3 -0
  37. package/src/compat/reasoning-carry.ts +64 -0
  38. package/src/compat/request-size.ts +25 -0
  39. package/src/compat/resolve.ts +36 -25
  40. package/src/compat/rules/README.md +13 -3
  41. package/src/compat/rules/auth/_order.kdl +2 -2
  42. package/src/compat/rules/auth/cloudflare-workers-ai.kdl +9 -0
  43. package/src/compat/rules/auth/coralbricks.kdl +13 -0
  44. package/src/compat/rules/auth/minimax-code-cn.kdl +1 -1
  45. package/src/compat/rules/auth/minimax-code.kdl +1 -1
  46. package/src/compat/rules/auth/openai-codex.kdl +1 -1
  47. package/src/compat/rules/auth/snowflake.kdl +11 -0
  48. package/src/compat/rules/auth/stencil.kdl +1 -1
  49. package/src/compat/rules/classes/anthropic.kdl +188 -7
  50. package/src/compat/rules/classes/deepseek.kdl +11 -3
  51. package/src/compat/rules/classes/gemini.kdl +12 -0
  52. package/src/compat/rules/classes/glm.kdl +17 -8
  53. package/src/compat/rules/classes/kimi.kdl +15 -0
  54. package/src/compat/rules/classes/meta.kdl +4 -4
  55. package/src/compat/rules/classes/minimax.kdl +31 -1
  56. package/src/compat/rules/classes/openai.kdl +114 -4
  57. package/src/compat/rules/classes/qwen.kdl +2 -1
  58. package/src/compat/rules/providers/abliteration.kdl +7 -0
  59. package/src/compat/rules/providers/amazon-bedrock.kdl +0 -7
  60. package/src/compat/rules/providers/anthropic.kdl +13 -0
  61. package/src/compat/rules/providers/apple.kdl +1 -0
  62. package/src/compat/rules/providers/cloudflare-workers-ai.kdl +34 -0
  63. package/src/compat/rules/providers/coralbricks.kdl +62 -0
  64. package/src/compat/rules/providers/cursor.kdl +28 -8
  65. package/src/compat/rules/providers/devin.kdl +2 -2
  66. package/src/compat/rules/providers/factory-droid.kdl +77 -13
  67. package/src/compat/rules/providers/github-copilot.kdl +29 -0
  68. package/src/compat/rules/providers/google-antigravity.kdl +8 -1
  69. package/src/compat/rules/providers/groq.kdl +21 -0
  70. package/src/compat/rules/providers/image-tokenization.kdl +42 -0
  71. package/src/compat/rules/providers/judgment-questions.kdl +53 -0
  72. package/src/compat/rules/providers/litellm.kdl +4 -1
  73. package/src/compat/rules/providers/meta.kdl +3 -3
  74. package/src/compat/rules/providers/minimax-code-cn.kdl +10 -5
  75. package/src/compat/rules/providers/minimax-code.kdl +10 -5
  76. package/src/compat/rules/providers/mistral.kdl +25 -1
  77. package/src/compat/rules/providers/moonshot.kdl +11 -0
  78. package/src/compat/rules/providers/muse-code.kdl +7 -0
  79. package/src/compat/rules/providers/ollama.kdl +3 -0
  80. package/src/compat/rules/providers/openai-codex.kdl +18 -13
  81. package/src/compat/rules/providers/openai.kdl +22 -0
  82. package/src/compat/rules/providers/opencode-go.kdl +11 -0
  83. package/src/compat/rules/providers/opencode-zen.kdl +20 -0
  84. package/src/compat/rules/providers/openrouter.kdl +6 -0
  85. package/src/compat/rules/providers/snowflake.kdl +135 -0
  86. package/src/compat/rules/providers/tool-result-images.kdl +16 -0
  87. package/src/compat/rules/providers/zhipu-coding-plan.kdl +10 -0
  88. package/src/compat/rules/runtime/behavior.kdl +8 -5
  89. package/src/compat/rules/taxonomy/_collapse.kdl +52 -2
  90. package/src/compat/rules/taxonomy/deepseek.kdl +4 -0
  91. package/src/compat/rules/taxonomy/kimi.kdl +5 -0
  92. package/src/compat/rules.json +1 -1
  93. package/src/compat/taxonomy.d.ts +0 -10
  94. package/src/compat/taxonomy.ts +3 -3
  95. package/src/compat/types.d.ts +4 -0
  96. package/src/compat/types.ts +4 -0
  97. package/src/discovery/antigravity.d.ts +13 -3
  98. package/src/discovery/antigravity.ts +33 -17
  99. package/src/discovery/cursor.ts +28 -4
  100. package/src/discovery/devin.ts +20 -2
  101. package/src/hosts.d.ts +4 -0
  102. package/src/hosts.ts +2 -0
  103. package/src/model-cache.d.ts +6 -0
  104. package/src/model-cache.ts +123 -47
  105. package/src/model-manager.d.ts +16 -0
  106. package/src/model-manager.ts +107 -41
  107. package/src/model-tokenizer.ts +3 -0
  108. package/src/models.json +1 -1
  109. package/src/provider-models/account-access.d.ts +11 -0
  110. package/src/provider-models/account-access.ts +30 -0
  111. package/src/provider-models/cache-provider-id.ts +13 -6
  112. package/src/provider-models/cline-pass.ts +33 -0
  113. package/src/provider-models/descriptors.ts +4 -0
  114. package/src/provider-models/google.d.ts +23 -1
  115. package/src/provider-models/google.ts +72 -14
  116. package/src/provider-models/openai-compat.d.ts +19 -1
  117. package/src/provider-models/openai-compat.ts +281 -42
  118. package/src/provider-models/special.d.ts +8 -0
  119. package/src/provider-models/special.ts +26 -22
  120. package/src/types.d.ts +134 -23
  121. package/src/types.ts +183 -20
  122. package/src/wire/cloudflare-ai-gateway.d.ts +0 -10
  123. package/src/wire/cloudflare-ai-gateway.ts +0 -36
  124. package/src/wire/cloudflare.ts +40 -0
  125. package/src/wire/factory-droid.d.ts +1 -1
  126. package/src/wire/factory-droid.ts +1 -1
  127. package/src/wire/gemini-headers.d.ts +6 -3
  128. package/src/wire/gemini-headers.ts +39 -21
@@ -14,7 +14,23 @@ export type KindApiKind = (typeof KIND_API_KINDS)[number];
14
14
  /** Grounding transport available to chat models selected by the web role. */
15
15
  export type WebSearchGrounding = "gemini" | "anthropic" | "codex" | "xai" | "openrouter" | "openai";
16
16
  /** Non-chat runner protocols accepted by catalog seeds, outside the chat dispatch union. */
17
- export declare const RUNNER_APIS: readonly ["local-inference", "web-search", "typesafe", "openrouter-decisions", "openai-images", "openrouter-images", "xai-tts", "openai-speech", "openai-embeddings", "openrouter-rerank", "openrouter-video", "openai-transcriptions"];
17
+ export declare const RUNNER_APIS: readonly ["local-inference", "web-search", "typesafe", "openrouter-decisions", "openai-decisions", "workers-ai-systemone", "openai-images", "openrouter-images", "xai-tts", "openai-speech", "openai-embeddings", "openrouter-rerank", "openrouter-video", "openai-transcriptions"];
18
+ /** Kind each single-purpose runner API serves; `local-inference` hosts several kinds. */
19
+ export declare const RUNNER_API_KINDS: Record<Exclude<(typeof RUNNER_APIS)[number], "local-inference">, ModelKind>;
20
+ /** Kind a runner API serves; `undefined` for chat transports and multi-kind `local-inference`. */
21
+ export declare function runnerApiKind(api: Api): ModelKind | undefined;
22
+ /** Catalog APIs `generate_image` runs through a pi-ai image client; the hosted Responses pair needs a carrier model. */
23
+ export declare const IMAGE_GENERATION_APIS: readonly ["openai-images", "openrouter-images", "google-generative-ai", "google-gemini-cli", "openai-responses", "openai-codex-responses"];
24
+ export type ImageGenerationApi = (typeof IMAGE_GENERATION_APIS)[number];
25
+ /**
26
+ * Kinds a model on `api` may declare: a runner api serves its own kind; a chat
27
+ * transport serves `chat` and `tiny`, plus `image` when `generate_image` runs it
28
+ * (hosted Responses image tool, Gemini image models). `undefined` for
29
+ * `local-inference`, which hosts several kinds chosen by the model itself.
30
+ */
31
+ export declare function servedKinds(api: Api): readonly ModelKind[] | undefined;
32
+ /** Whether a model of `kind` can run on `api`. */
33
+ export declare function apiServesKind(api: Api, kind: ModelKind): boolean;
18
34
  /** Resolve a model's kind while preserving chat semantics for existing catalog rows. */
19
35
  export declare function modelKind(model: Pick<Model, "kind">): ModelKind;
20
36
  /** Canonical thinking transport used by a model. */
@@ -176,6 +192,8 @@ export interface OpenAICompat {
176
192
  supportsMultipleSystemMessages?: boolean;
177
193
  /** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */
178
194
  supportsReasoningEffort?: boolean;
195
+ /** Do not infer a thinking dial when discovery supplies no explicit thinking configuration. */
196
+ trustExplicitThinkingOnly?: boolean;
179
197
  /** Optional mapping from pi-ai reasoning levels to provider/model-specific `reasoning_effort` values. */
180
198
  reasoningEffortMap?: Partial<Record<Effort, string>>;
181
199
  /** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */
@@ -322,6 +340,8 @@ export interface OpenAICompat {
322
340
  extraBody?: Record<string, unknown>;
323
341
  /** Request-session header that should mirror the normalized prompt-cache key. Default: unset. */
324
342
  promptCacheSessionHeader?: "x-grok-conv-id";
343
+ /** Request header carrying the conversation session id, independent of prompt caching. Default: unset. */
344
+ sessionHeader?: "x-litellm-session-id";
325
345
  /** Whether chat-completions payloads should include provider-specific prompt-cache markers. */
326
346
  cacheControlFormat?: "anthropic" | undefined;
327
347
  /**
@@ -378,6 +398,8 @@ export interface OpenAICompat {
378
398
  supportsReasoningParams?: boolean;
379
399
  /** Whether Responses requests may include `reasoning.summary`. Default: true except on known incompatible hosts. */
380
400
  supportsReasoningSummary?: boolean;
401
+ /** Whether to chain OpenAI Responses turns using stored response ids. Unset uses the official-endpoint default; env and call options take precedence. */
402
+ statefulResponses?: boolean;
381
403
  /**
382
404
  * Whether the endpoint accepts explicit sampling parameters (`temperature`,
383
405
  * `top_p`, `top_k`, `min_p`, penalties). OpenAI proprietary reasoning models
@@ -398,13 +420,13 @@ export interface OpenAICompat {
398
420
  alwaysSendMaxTokens?: boolean;
399
421
  /** Whether Responses-API tool-call/result history must be strictly paired. Default: auto-detected (Azure OpenAI, GitHub Copilot). */
400
422
  strictResponsesPairing?: boolean;
401
- /** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
423
+ /** Whether the Responses API accepts the `detail: "original"` image hint. Default: true for OpenAI, Azure OpenAI, and Codex; false for other hosts. Explicit overrides win. */
402
424
  supportsImageDetailOriginal?: boolean;
403
425
  /**
404
426
  * Whether the Responses endpoint accepts `configuration_update` input items
405
427
  * that change `reasoning.effort` mid-conversation while the request-level
406
- * effort stays pinned for prompt caching (GPT-6 Astra). Default:
407
- * rule-detected (`true` for `gpt-6-astra` on any host, `false` otherwise).
428
+ * effort stays pinned for prompt caching (GPT-6 family). Default:
429
+ * rule-detected (`true` for GPT-6 models on any host, `false` otherwise).
408
430
  * Set `false` for custom `openai-responses` / `openai-codex-responses`
409
431
  * endpoints that reject the item type with HTTP 400; effort changes are then
410
432
  * sent as the top-level `reasoning.effort`.
@@ -601,12 +623,31 @@ export interface AnthropicCompat {
601
623
  injectClaudeCodeInstruction?: boolean;
602
624
  /** Strip image inputs before encoding (text-only serving of a multimodal id). */
603
625
  stripImageInput?: boolean;
626
+ /**
627
+ * Largest width or height a single image block may carry. The canonical
628
+ * Anthropic API rejects anything larger with `At least one of the image
629
+ * dimensions exceed max allowed size: 8000 pixels`, and the rejection
630
+ * poisons every retry and model fallback because the block stays in
631
+ * context, so the request builder downscales to this value first. Hosts
632
+ * with a different image contract override it. Default: 8000.
633
+ */
634
+ maxImageDimension?: number;
635
+ /**
636
+ * Largest base64 payload a single image block may carry, in bytes. The
637
+ * canonical Anthropic API measures the encoded string, not the decoded
638
+ * bytes (`image exceeds 10 MB maximum: 14012300 bytes > 10485760 bytes`),
639
+ * and an image inside {@link maxImageDimension} can still cross it, so
640
+ * payload size is clamped on its own. Hosts with a different image
641
+ * contract override it. Default: 10485760.
642
+ */
643
+ maxImagePayloadBytes?: number;
604
644
  /** Thinking-loop watchdog guard family applied to streamed reasoning. */
605
645
  thinkingLoopGuard?: "gemini" | "deepseek" | "xai";
606
646
  /**
607
647
  * Drop the enabled `thinking` config and replayed thinking blocks when the
608
648
  * conversation is not thinking-led (a proxy contract for non-interleaved
609
- * budget models). Default: false.
649
+ * budget models), and replay history without thinking blocks on every turn
650
+ * that sends `thinking: { type: "disabled" }`. Default: false.
610
651
  */
611
652
  stripThinkingHistory?: boolean;
612
653
  /**
@@ -616,10 +657,15 @@ export interface AnthropicCompat {
616
657
  effortBeta?: boolean;
617
658
  /**
618
659
  * Wire form of a disabled-thinking turn: omit the field, send
619
- * `{ type: "disabled" }`, or keep adaptive thinking. Unset keeps the
620
- * direct-provider behavior.
660
+ * `{ type: "disabled" }`, keep adaptive thinking, or send
661
+ * `{ type: "between_tools" }`. Unset keeps the direct-provider behavior.
662
+ */
663
+ disabledThinking?: "omit" | "disabled" | "adaptive" | "between-tools";
664
+ /**
665
+ * `output_config.effort` pinned on a `between_tools` turn. Unset leaves
666
+ * the turn's effort untouched.
621
667
  */
622
- disabledThinking?: "omit" | "disabled" | "adaptive";
668
+ betweenToolsEffort?: "low" | "medium" | "high";
623
669
  /** The model is a fast-mode SKU: send `speed: "fast"` with the fast-mode beta. Default: false. */
624
670
  fastMode?: boolean;
625
671
  }
@@ -628,6 +674,8 @@ export interface AnthropicCompat {
628
674
  * deliberately not used to infer these request-shape capabilities.
629
675
  */
630
676
  export interface BedrockCompat {
677
+ /** Explicit disabled-thinking wire form; unset preserves the provider's existing behavior. */
678
+ disabledThinking?: AnthropicCompat["disabledThinking"];
631
679
  /** Whether this endpoint accepts no checkpoints, automatic caching, or explicit cachePoint blocks. */
632
680
  promptCacheMode?: "none" | "automatic" | "explicit";
633
681
  /** Whether this wire may revise already-streamed text (`stream-revision` axis). Unassigned: append-only. */
@@ -651,22 +699,42 @@ export interface BedrockCompat {
651
699
  * `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS` alias, then the 300s default.
652
700
  */
653
701
  streamIdleTimeoutMs?: number;
702
+ /**
703
+ * Whether the served model accepts explicit sampling parameters
704
+ * (`temperature`, `topP`, …). Class rules set `false` for model lines that
705
+ * reject them on every host. Unassigned: accepted.
706
+ */
707
+ supportsSamplingParams?: boolean;
654
708
  /**
655
709
  * Whether the model accepts a forced `toolChoice` (`any` / `tool`). Claude
656
710
  * Opus/Sonnet 5.5 reject it outright; the request builder downgrades forced
657
711
  * choices to `auto` when this is false. Default: true.
658
712
  */
659
713
  supportsForcedToolChoice?: boolean;
714
+ /**
715
+ * Whether the endpoint accepts thinking-binding controls (`thinking.block_binding`,
716
+ * the `thinking-binding-controls-2026-08-01` beta and the `/input_transformations`
717
+ * response path) on prefix-bound models. Only consulted when
718
+ * `thinking.prefixBinding` is set; `false` omits the controls while keeping the
719
+ * local prefix-binding safeguards. Default: true.
720
+ */
721
+ supportsThinkingBindingControls?: boolean;
660
722
  }
661
723
  /** Fully-resolved Bedrock Converse prompt-cache capabilities, materialized once by `buildModel`. */
662
724
  export interface ResolvedBedrockCompat {
725
+ /** See {@link BedrockCompat.disabledThinking}. */
726
+ disabledThinking?: BedrockCompat["disabledThinking"];
663
727
  promptCacheMode: NonNullable<BedrockCompat["promptCacheMode"]>;
664
728
  /** See {@link BedrockCompat.streamRevision}. */
665
729
  streamRevision?: BedrockCompat["streamRevision"];
666
730
  supportsLongPromptCacheRetention: boolean;
667
731
  promptCacheMinimumTokens: number;
668
732
  promptCacheMaximumCheckpoints: number;
733
+ /** See {@link BedrockCompat.supportsSamplingParams}. */
734
+ supportsSamplingParams?: boolean;
669
735
  supportsForcedToolChoice: boolean;
736
+ /** See {@link BedrockCompat.supportsThinkingBindingControls}. */
737
+ supportsThinkingBindingControls: boolean;
670
738
  /**
671
739
  * Stream-watchdog idle-timeout fallback in ms for hosts with no keepalive
672
740
  * events; 0 disables the idle watchdog. Undefined defers to
@@ -712,6 +780,7 @@ export interface ResolvedOpenAISharedCompat {
712
780
  supportsDeveloperRole: boolean;
713
781
  supportsStrictMode: boolean;
714
782
  supportsReasoningEffort: boolean;
783
+ trustExplicitThinkingOnly?: boolean;
715
784
  reasoningEffortMap: Partial<Record<Effort, string>>;
716
785
  supportsReasoningParams: boolean;
717
786
  supportsSamplingParams: boolean;
@@ -754,6 +823,7 @@ export interface ResolvedOpenAISharedCompat {
754
823
  emptyLengthFinishIsContextError: boolean;
755
824
  usesOpenAIToolCallIdLimit: boolean;
756
825
  promptCacheSessionHeader?: OpenAICompat["promptCacheSessionHeader"];
826
+ sessionHeader?: OpenAICompat["sessionHeader"];
757
827
  /**
758
828
  * Whether this model accepts explicit OpenAI prompt-cache breakpoints.
759
829
  * Built catalog models always materialize this false-by-default value;
@@ -788,7 +858,7 @@ export interface ResolvedOpenAISharedCompat {
788
858
  * `buildModel`; request handlers read fields and never detect, resolve, or
789
859
  * allocate.
790
860
  */
791
- export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "supportsReasoningSummary" | "supportsSamplingParams" | "supportsPenaltyAndStopParams" | "thinkingFormat" | "kimiApiFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "disableReasoningWithTools" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "mistralReasoningContentParts" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "syntheticReasoningContentFallback" | "replayReasoningContent" | "qwenPreserveThinking" | "qwenTemplateReasoningEffort" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "supportsPromptCacheBreakpoints" | "promptCacheBreakpointTtl" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "clampOutputToModelMax" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "streamRevision" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "supportsConfigurationUpdate" | "supportsSteering" | "stripImageInput" | "thinkingLoopGuard" | "whenThinking">> & {
861
+ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "trustExplicitThinkingOnly" | "reasoningEffortMap" | "supportsReasoningParams" | "supportsReasoningSummary" | "statefulResponses" | "supportsSamplingParams" | "supportsPenaltyAndStopParams" | "thinkingFormat" | "kimiApiFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "disableReasoningWithTools" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "mistralReasoningContentParts" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "syntheticReasoningContentFallback" | "replayReasoningContent" | "qwenPreserveThinking" | "qwenTemplateReasoningEffort" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "sessionHeader" | "supportsPromptCacheBreakpoints" | "promptCacheBreakpointTtl" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "clampOutputToModelMax" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "streamRevision" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "supportsConfigurationUpdate" | "supportsSteering" | "stripImageInput" | "thinkingLoopGuard" | "whenThinking">> & {
792
862
  vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
793
863
  extraBody?: OpenAICompat["extraBody"];
794
864
  cacheControlFormat?: OpenAICompat["cacheControlFormat"];
@@ -818,8 +888,8 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
818
888
  /**
819
889
  * Whether a `configuration_update` input item may change `reasoning.effort`
820
890
  * mid-conversation while the request-level effort stays byte-stable for
821
- * prompt caching. Rule-owned: GPT-6 Astra only; every other model rejects
822
- * the item type with 400.
891
+ * prompt caching. Rule-owned: the GPT-6 family; earlier models do not
892
+ * support the item type.
823
893
  */
824
894
  supportsConfigurationUpdate: boolean;
825
895
  /**
@@ -835,6 +905,23 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
835
905
  * filling `"auto"`.
836
906
  */
837
907
  supportsReasoningSummary: boolean;
908
+ /** Optional chaining override; unset falls back to officialEndpoint at request time. */
909
+ statefulResponses?: boolean;
910
+ /**
911
+ * Whether the host can store Responses results server-side (`store: true`).
912
+ * Rule-owned: hosts that keep generating after a client disconnect so a
913
+ * dropped stream can resume via `GET /responses/{id}`. Storage is opt-in
914
+ * per request (`storeResponses` stream option, else
915
+ * `PI_MUSE_STORE_RESPONSES`); stored runs retain prompts and outputs on the provider.
916
+ */
917
+ storeResponses: boolean;
918
+ /**
919
+ * Whether the host binds native history items (`encrypted_content`, item
920
+ * ids) to the connection that issued them, so a new process must rebuild
921
+ * prior turns from message content until its first successful response.
922
+ * Rule-owned: GitHub Copilot.
923
+ */
924
+ connectionBoundNativeHistory: boolean;
838
925
  streamIdleTimeoutMs?: number;
839
926
  vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
840
927
  /** The model sits behind Vercel AI Gateway's Responses endpoint. */
@@ -858,15 +945,28 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
858
945
  */
859
946
  export type ResolvedOpenRouterCompat = ResolvedOpenAICompat & ResolvedOpenAIResponsesCompat;
860
947
  /** Fully-resolved anthropic-messages compat view (same contract as `ResolvedOpenAICompat`). */
861
- export type ResolvedAnthropicCompat = Required<Omit<AnthropicCompat, "streamIdleTimeoutMs" | "thinkingLoopGuard" | "bedrockMessagesApi" | "effortBeta" | "disabledThinking" | "stripThinkingHistory" | "fastMode">> & {
948
+ export type ResolvedAnthropicCompat = Required<Omit<AnthropicCompat, "streamIdleTimeoutMs" | "thinkingLoopGuard" | "bedrockMessagesApi" | "effortBeta" | "disabledThinking" | "betweenToolsEffort" | "stripThinkingHistory" | "fastMode" | "maxImageDimension" | "maxImagePayloadBytes">> & {
862
949
  /** Effort-beta override; undefined keeps the transport's legacy heuristic. */
863
950
  effortBeta?: AnthropicCompat["effortBeta"];
864
951
  /** Disabled-thinking wire form; undefined keeps the direct-provider behavior. */
865
952
  disabledThinking?: AnthropicCompat["disabledThinking"];
866
- /** Strip thinking history on non-thinking-led turns; undefined behaves as false. */
953
+ /** Effort pinned on `between_tools` turns; undefined leaves effort untouched. */
954
+ betweenToolsEffort?: AnthropicCompat["betweenToolsEffort"];
955
+ /** Strip thinking history on non-thinking-led and disabled-thinking turns; undefined behaves as false. */
867
956
  stripThinkingHistory?: AnthropicCompat["stripThinkingHistory"];
868
957
  /** Fast-mode SKU; undefined behaves as false. */
869
958
  fastMode?: AnthropicCompat["fastMode"];
959
+ /**
960
+ * Largest width or height a single image block may carry. Undefined defers
961
+ * to the canonical Anthropic API limit applied by the request builder.
962
+ */
963
+ maxImageDimension?: number;
964
+ /**
965
+ * Largest base64 image payload a single block may carry, in bytes.
966
+ * Undefined defers to the canonical Anthropic API limit applied by the
967
+ * request builder.
968
+ */
969
+ maxImagePayloadBytes?: number;
870
970
  /** Thinking-loop watchdog guard family applied to streamed reasoning. */
871
971
  thinkingLoopGuard?: AnthropicCompat["thinkingLoopGuard"];
872
972
  /**
@@ -918,9 +1018,11 @@ export interface DevinCompat {
918
1018
  modelRouter?: boolean;
919
1019
  /** Whether the upstream model supports native parallel tool calls. */
920
1020
  supportsParallelToolCalls?: boolean;
1021
+ /** See {@link BedrockCompat.supportsSamplingParams}. */
1022
+ supportsSamplingParams?: boolean;
921
1023
  }
922
1024
  /** Fully-resolved devin-agent compat view. */
923
- export type ResolvedDevinCompat = Required<DevinCompat>;
1025
+ export type ResolvedDevinCompat = Required<Omit<DevinCompat, "supportsSamplingParams">> & Pick<DevinCompat, "supportsSamplingParams">;
924
1026
  /**
925
1027
  * Compatibility settings for the Google API family (google-generative-ai,
926
1028
  * google-vertex, google-gemini-cli). Class-driven defaults come from the
@@ -955,13 +1057,16 @@ export interface GoogleCompat {
955
1057
  stripImageInput?: boolean;
956
1058
  /** Thinking-loop watchdog guard family applied to streamed reasoning. */
957
1059
  thinkingLoopGuard?: "gemini" | "deepseek" | "xai";
1060
+ /** See {@link BedrockCompat.supportsSamplingParams}. */
1061
+ supportsSamplingParams?: boolean;
958
1062
  }
959
1063
  /** Fully-resolved google-API compat view, materialized once by `buildModel`. */
960
- export type ResolvedGoogleCompat = Required<Omit<GoogleCompat, "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "thinkingLoopGuard" | "antigravityUsageLabel">> & {
1064
+ export type ResolvedGoogleCompat = Required<Omit<GoogleCompat, "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "thinkingLoopGuard" | "antigravityUsageLabel" | "supportsSamplingParams">> & {
961
1065
  streamFirstEventTimeoutMs?: number;
962
1066
  streamIdleTimeoutMs?: number;
963
1067
  thinkingLoopGuard?: GoogleCompat["thinkingLoopGuard"];
964
1068
  antigravityUsageLabel?: string;
1069
+ supportsSamplingParams?: boolean;
965
1070
  };
966
1071
  /** Sparse, user-authored compat overrides for a given API (models.json / config vocabulary). */
967
1072
  export type CompatConfigOf<TApi extends Api> = TApi extends "openai-completions" | "openrouter" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? OpenAICompat : TApi extends "anthropic-messages" ? AnthropicCompat : TApi extends "bedrock-converse-stream" ? BedrockCompat : TApi extends "devin-agent" ? DevinCompat : TApi extends "google-generative-ai" | "google-vertex" | "google-gemini-cli" ? GoogleCompat : undefined;
@@ -1065,6 +1170,12 @@ export interface Model<TApi extends Api = Api> {
1065
1170
  id: string;
1066
1171
  /** Role-specific runner capability; omitted for ordinary chat models. */
1067
1172
  kind?: ModelKind;
1173
+ /**
1174
+ * Verbatim configured kind (models.yml, `modelOverrides`, runtime
1175
+ * registrations). `buildModel` applies it over catalog `kind` rules on every
1176
+ * rebuild, so a configured runner keeps its role.
1177
+ */
1178
+ kindConfig?: ModelKind;
1068
1179
  /** Grounding transport supported by this chat model. */
1069
1180
  webSearch?: WebSearchGrounding;
1070
1181
  /** Cheaper same-provider model to run hosted web search in this model's place (model id or provider/id). */
@@ -1162,11 +1273,11 @@ export interface Model<TApi extends Api = Api> {
1162
1273
  cursorMaxModeRoutes?: Readonly<Record<string, boolean>>;
1163
1274
  /**
1164
1275
  * Per-account availability recorded by multi-account discovery: provider
1165
- * account id (Codex: ChatGPT `chatgpt_account_id`) → that account's
1166
- * entitlements on this model. An account appears only when its own catalog
1167
- * lists the model, so credential selection can route account-gated models
1168
- * (e.g. `gpt-daybreak-blue-latest`) straight to eligible accounts. Absent on
1169
- * bundled/config rows and on single-account discovery.
1276
+ * account key (Codex: ChatGPT `chatgpt_account_id`; Antigravity: login
1277
+ * email) → that account's entitlements on this model. An account appears
1278
+ * only when its own catalog lists the model, so credential selection can
1279
+ * route account-gated models (e.g. `gpt-daybreak-blue-latest`, Antigravity
1280
+ * Claude 5.5) straight to eligible accounts. Absent on bundled/config rows.
1170
1281
  */
1171
1282
  accountAccess?: Readonly<Record<string, ModelAccountAccess>>;
1172
1283
  /** Cursor `RequestedModel.parameters` for this model's default variant. */
@@ -1277,9 +1388,9 @@ export interface Model<TApi extends Api = Api> {
1277
1388
  /**
1278
1389
  * Per-service-tier cost multipliers baked from the `service-tier-cost`
1279
1390
  * catalog axis (e.g. `{ priority: 2.5 }`). Absent tiers use the API-generic
1280
- * defaults.
1391
+ * defaults, and a tier with no published price stays at 1x.
1281
1392
  */
1282
- serviceTierCost?: Readonly<Partial<Record<"flex" | "priority", number>>>;
1393
+ serviceTierCost?: Readonly<Partial<Record<"flex" | "priority" | "ultrafast", number>>>;
1283
1394
  /**
1284
1395
  * Provider-supplied one-line blurb for this model. Set only when an upstream
1285
1396
  * ships one (Devin's `GetCliModelConfigs`); never synthesized locally.
@@ -1289,7 +1400,7 @@ export interface Model<TApi extends Api = Api> {
1289
1400
  isNew?: boolean;
1290
1401
  /** Upstream marks this model as beta / preview quality. */
1291
1402
  isBeta?: boolean;
1292
- /** Authenticated provider catalog marks this as the account's default model. */
1403
+ /** Authenticated catalog marks this as the account's default; the startup pick prefers it over `default-model`. */
1293
1404
  isProviderDefault?: boolean;
1294
1405
  /** Upstream marks this model as one of its recommended picks. */
1295
1406
  isRecommended?: boolean;
@@ -6,13 +6,3 @@ export declare const CLOUDFLARE_AI_GATEWAY_ANTHROPIC_BASE_URL = "https://gateway
6
6
  export declare const CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/openai";
7
7
  /** OpenAI-compatible Workers AI endpoint. */
8
8
  export declare const CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/compat";
9
- /** Opaque API-key credential payload persisted by Cloudflare AI Gateway login. */
10
- export interface CloudflareAiGatewayCredential {
11
- token: string;
12
- accountId?: string;
13
- gatewayId?: string;
14
- }
15
- /** Parse both structured login credentials and legacy plain gateway tokens. */
16
- export declare function parseCloudflareAiGatewayCredential(value: string): CloudflareAiGatewayCredential | null;
17
- /** Serialize the gateway token with the routing identifiers collected during login. */
18
- export declare function serializeCloudflareAiGatewayCredential(token: string, accountId: string, gatewayId: string): string;
@@ -0,0 +1,10 @@
1
+ /** Cloudflare credential persisted by the AI Gateway and Workers AI logins: a bearer token plus the routing ids collected at login. */
2
+ export interface CloudflareCredential {
3
+ token: string;
4
+ accountId?: string;
5
+ gatewayId?: string;
6
+ }
7
+ /** Parses a structured login credential or a legacy plain token; null when empty or malformed. */
8
+ export declare function parseCloudflareCredential(value: string): CloudflareCredential | null;
9
+ /** Serializes a login credential, trimming fields and omitting empty optional ids. */
10
+ export declare function serializeCloudflareCredential(credential: CloudflareCredential): string;
@@ -3,7 +3,7 @@
3
3
  * native request corpus with `packages/ai/scripts/capture-factory-droid-native.ts`
4
4
  * against the matching CLI binary and make `factory-droid-native-parity.test.ts` pass.
5
5
  */
6
- export declare const FACTORY_DROID_CLIENT_VERSION = "0.230.0";
6
+ export declare const FACTORY_DROID_CLIENT_VERSION = "0.237.0";
7
7
  /** Wire protocols the Factory proxy multiplexes; `api-routes provider="factory-droid"` picks one per model. */
8
8
  export declare const FACTORY_DROID_WIRES: readonly ["openai-completions", "openai-responses", "anthropic-messages", "google-generate"];
9
9
  /** Wire protocol used by the Factory proxy for each model. */
@@ -24,7 +24,7 @@ export declare const getGeminiCliHeaders: (modelId?: string) => {
24
24
  * client the version and manifest are captured from, independent of the host
25
25
  * platform. Overrides: PI_AI_ANTIGRAVITY_VERSION / _CL / _OS / _ARCH.
26
26
  */
27
- export declare const DEFAULT_ANTIGRAVITY_VERSION = "2.8.0";
27
+ export declare const DEFAULT_ANTIGRAVITY_VERSION = "2.19.1";
28
28
  /** Current Antigravity client version: env override → manifest-discovered → pinned fallback. */
29
29
  export declare function getAntigravityVersion(): string;
30
30
  /**
@@ -35,8 +35,11 @@ export declare function parseAntigravityManifestVersion(yamlText: string): strin
35
35
  /**
36
36
  * Resolves the latest Antigravity release from the official update manifest.
37
37
  * Success is cached for the process lifetime; failures are silent (the pinned
38
- * fallback stays valid) and clear the in-flight cache so a later call retries.
39
- * Skipped entirely when PI_AI_ANTIGRAVITY_VERSION is set.
38
+ * fallback stays valid) and suppress further lookups for
39
+ * `ANTIGRAVITY_VERSION_RETRY_MS`. Skipped entirely when PI_AI_ANTIGRAVITY_VERSION is set.
40
+ *
41
+ * The lookup is shared by concurrent callers, so it is bounded only by its own
42
+ * timeout; `signal` ends this caller's wait without cancelling the lookup.
40
43
  */
41
44
  export declare function ensureAntigravityVersion(fetcher?: FetchImpl, signal?: AbortSignal): Promise<void>;
42
45
  /** Antigravity `User-Agent` header value; rebuilt when the discovered version changes. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linxiraos/pi-catalog",
3
- "version": "1.1.26",
3
+ "version": "1.2.0",
4
4
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
5
5
  "keywords": [
6
6
  "ai",
@@ -90,12 +90,12 @@
90
90
  "gen:proto": "bun scripts/generate-protocols.ts"
91
91
  },
92
92
  "dependencies": {
93
- "@linxiraos/pi-omptype": "1.1.26",
94
- "@linxiraos/pi-utils": "1.1.26"
93
+ "@linxiraos/pi-omptype": "1.2.0",
94
+ "@linxiraos/pi-utils": "1.2.0"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@bgotink/kdl": "0.4.0",
98
- "@linxiraos/pi-ai": "1.1.26",
98
+ "@linxiraos/pi-ai": "1.2.0",
99
99
  "@types/bun": "^1.3.14"
100
100
  },
101
101
  "engines": {
package/src/build.ts CHANGED
@@ -101,9 +101,11 @@ function applyCatalogAssignments<TApi extends Api>(model: Model<TApi>, catalog:
101
101
  if (serviceTierCost !== undefined) {
102
102
  const flex = numberField(serviceTierCost, "flex");
103
103
  const priorityTier = numberField(serviceTierCost, "priority");
104
+ const ultrafast = numberField(serviceTierCost, "ultrafast");
104
105
  model.serviceTierCost = {
105
106
  ...(flex !== undefined && { flex }),
106
107
  ...(priorityTier !== undefined && { priority: priorityTier }),
108
+ ...(ultrafast !== undefined && { ultrafast }),
107
109
  };
108
110
  }
109
111
  const priority = catalog.priority;
@@ -174,40 +176,6 @@ export function applyCatalogCorrections(
174
176
  model: Pick<ModelSpec<Api>, "cost" | "contextWindow" | "maxTokens" | "input">,
175
177
  catalog: Record<string, unknown>,
176
178
  ): void {
177
- const longContext = objectPayload(catalog.longContext);
178
- if (longContext !== undefined) {
179
- const inputThreshold = numberField(longContext, "inputThreshold");
180
- const inclusive = Reflect.get(longContext, "inputThresholdInclusive") === true;
181
- const multiplier = numberField(longContext, "multiplier");
182
- const input = numberField(longContext, "input");
183
- const output = numberField(longContext, "output");
184
- const cacheRead = numberField(longContext, "cacheRead");
185
- const cacheWrite = numberField(longContext, "cacheWrite");
186
- const base = model.cost;
187
- const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
188
- if (inputThreshold !== undefined && multiplier !== undefined && hasTokenPrice) {
189
- // Multiplier form: tier rates derive from the row's live list price.
190
- model.cost = {
191
- ...base,
192
- longContext: {
193
- inputThreshold,
194
- ...(inclusive && { inputThresholdInclusive: true }),
195
- input: base.input * multiplier,
196
- output: base.output * multiplier,
197
- cacheRead: base.cacheRead * multiplier,
198
- cacheWrite: base.cacheWrite * multiplier,
199
- },
200
- };
201
- } else if (
202
- inputThreshold !== undefined &&
203
- input !== undefined &&
204
- output !== undefined &&
205
- cacheRead !== undefined &&
206
- cacheWrite !== undefined
207
- ) {
208
- model.cost = { ...model.cost, longContext: { inputThreshold, input, output, cacheRead, cacheWrite } };
209
- }
210
- }
211
179
  const patch = objectPayload(catalog.costPatch);
212
180
  if (patch !== undefined) {
213
181
  model.cost = { ...model.cost };
@@ -244,6 +212,41 @@ export function applyCatalogCorrections(
244
212
  applyEffectiveFallbackRates(model.cost, Reflect.get(fallback, "effectiveRates"));
245
213
  }
246
214
  }
215
+ const longContext = objectPayload(catalog.longContext);
216
+ if (longContext !== undefined) {
217
+ const inputThreshold = numberField(longContext, "inputThreshold");
218
+ const inclusive = Reflect.get(longContext, "inputThresholdInclusive") === true;
219
+ const multiplier = numberField(longContext, "multiplier");
220
+ const input = numberField(longContext, "input");
221
+ const output = numberField(longContext, "output");
222
+ const cacheRead = numberField(longContext, "cacheRead");
223
+ const cacheWrite = numberField(longContext, "cacheWrite");
224
+ const base = model.cost;
225
+ const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
226
+ if (inputThreshold !== undefined && multiplier !== undefined && hasTokenPrice) {
227
+ // Multiplier form: tier rates derive from the row's final base card,
228
+ // after `cost-patch`/`cost-fallback` corrected the live list price.
229
+ model.cost = {
230
+ ...base,
231
+ longContext: {
232
+ inputThreshold,
233
+ ...(inclusive && { inputThresholdInclusive: true }),
234
+ input: base.input * multiplier,
235
+ output: base.output * multiplier,
236
+ cacheRead: base.cacheRead * multiplier,
237
+ cacheWrite: base.cacheWrite * multiplier,
238
+ },
239
+ };
240
+ } else if (
241
+ inputThreshold !== undefined &&
242
+ input !== undefined &&
243
+ output !== undefined &&
244
+ cacheRead !== undefined &&
245
+ cacheWrite !== undefined
246
+ ) {
247
+ model.cost = { ...model.cost, longContext: { inputThreshold, input, output, cacheRead, cacheWrite } };
248
+ }
249
+ }
247
250
  if (catalog.cacheReadAtInputRate === true) {
248
251
  const { longContext } = model.cost;
249
252
  model.cost = {
@@ -363,7 +366,8 @@ export function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi>
363
366
  };
364
367
  applyCatalogAssignments(model, policy.catalog);
365
368
  applyCatalogCorrections(model, policy.catalog);
366
- // Configured lifetimes replace catalog lifetimes rather than merging with them.
369
+ // Configured kinds and lifetimes replace catalog values rather than merging with them.
370
+ if (spec.kindConfig !== undefined) model.kind = spec.kindConfig;
367
371
  if (spec.promptCacheConfig !== undefined) model.promptCache = { ...spec.promptCacheConfig };
368
372
  return model;
369
373
  }
@@ -17,7 +17,9 @@ export type AuthProviderId =
17
17
  | "charm-hyper"
18
18
  | "cline-pass"
19
19
  | "cloudflare-ai-gateway"
20
+ | "cloudflare-workers-ai"
20
21
  | "commandcode"
22
+ | "coralbricks"
21
23
  | "coreweave"
22
24
  | "cursor"
23
25
  | "deepinfra"
@@ -72,6 +74,7 @@ export type AuthProviderId =
72
74
  | "siliconflow-cn"
73
75
  | "singularityapi-dev"
74
76
  | "singularityapi-tech"
77
+ | "snowflake"
75
78
  | "stencil"
76
79
  | "stepfun"
77
80
  | "synthetic"
@@ -108,7 +111,9 @@ export type LoginProviderId =
108
111
  | "charm-hyper"
109
112
  | "cline-pass"
110
113
  | "cloudflare-ai-gateway"
114
+ | "cloudflare-workers-ai"
111
115
  | "commandcode"
116
+ | "coralbricks"
112
117
  | "coreweave"
113
118
  | "cursor"
114
119
  | "deepinfra"
@@ -156,6 +161,7 @@ export type LoginProviderId =
156
161
  | "siliconflow-cn"
157
162
  | "singularityapi-dev"
158
163
  | "singularityapi-tech"
164
+ | "snowflake"
159
165
  | "stencil"
160
166
  | "stepfun"
161
167
  | "synthetic"