@linxiraos/pi-catalog 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +88 -6
  2. package/package.json +98 -99
  3. package/src/build.ts +3 -3
  4. package/src/compat/openai.ts +0 -6
  5. package/src/discovery/antigravity.ts +5 -1
  6. package/src/discovery/openai-compatible.ts +21 -4
  7. package/src/identity/classify.ts +32 -9
  8. package/src/identity/family.ts +18 -4
  9. package/src/model-manager.ts +13 -2
  10. package/src/model-thinking.ts +15 -7
  11. package/src/models.json +7999 -2099
  12. package/src/models.ts +28 -14
  13. package/src/provider-models/bundled-references.ts +4 -2
  14. package/src/provider-models/openai-compat.ts +379 -301
  15. package/src/types.ts +24 -16
  16. package/src/variant-collapse.ts +34 -17
  17. package/src/wire/gemini-headers.ts +79 -18
  18. package/dist/types/build.d.ts +0 -14
  19. package/dist/types/compat/anthropic.d.ts +0 -18
  20. package/dist/types/compat/apply.d.ts +0 -7
  21. package/dist/types/compat/bedrock.d.ts +0 -3
  22. package/dist/types/compat/devin.d.ts +0 -9
  23. package/dist/types/compat/openai.d.ts +0 -26
  24. package/dist/types/discovery/antigravity.d.ts +0 -70
  25. package/dist/types/discovery/codex.d.ts +0 -36
  26. package/dist/types/discovery/cursor-gen/agent_pb.d.ts +0 -16769
  27. package/dist/types/discovery/cursor.d.ts +0 -23
  28. package/dist/types/discovery/devin-gen/buf/validate/validate_pb.d.ts +0 -1715
  29. package/dist/types/discovery/devin-gen/exa/analytics_pb/analytics_pb.d.ts +0 -693
  30. package/dist/types/discovery/devin-gen/exa/api_server_pb/api_server_pb.d.ts +0 -9158
  31. package/dist/types/discovery/devin-gen/exa/auth_pb/auth_pb.d.ts +0 -52
  32. package/dist/types/discovery/devin-gen/exa/auto_cascade_common_pb/auto_cascade_common_pb.d.ts +0 -276
  33. package/dist/types/discovery/devin-gen/exa/bug_checker_pb/bug_checker_pb.d.ts +0 -78
  34. package/dist/types/discovery/devin-gen/exa/cascade_plugins_pb/cascade_plugins_pb.d.ts +0 -999
  35. package/dist/types/discovery/devin-gen/exa/chat_pb/chat_pb.d.ts +0 -1704
  36. package/dist/types/discovery/devin-gen/exa/code_edit/code_edit_pb/code_edit_pb.d.ts +0 -656
  37. package/dist/types/discovery/devin-gen/exa/codeium_common_pb/codeium_common_pb.d.ts +0 -15014
  38. package/dist/types/discovery/devin-gen/exa/context_module_pb/context_module_pb.d.ts +0 -607
  39. package/dist/types/discovery/devin-gen/exa/cortex_pb/cortex_pb.d.ts +0 -11830
  40. package/dist/types/discovery/devin-gen/exa/diff_action_pb/diff_action_pb.d.ts +0 -248
  41. package/dist/types/discovery/devin-gen/exa/index_pb/index_pb.d.ts +0 -1747
  42. package/dist/types/discovery/devin-gen/exa/knowledge_base_pb/knowledge_base_pb.d.ts +0 -509
  43. package/dist/types/discovery/devin-gen/exa/language_server_pb/language_server_pb.d.ts +0 -9048
  44. package/dist/types/discovery/devin-gen/exa/opensearch_clients_pb/opensearch_clients_pb.d.ts +0 -1760
  45. package/dist/types/discovery/devin-gen/exa/prompt_pb/prompt_pb.d.ts +0 -286
  46. package/dist/types/discovery/devin-gen/exa/reactive_component_pb/reactive_component_pb.d.ts +0 -405
  47. package/dist/types/discovery/devin-gen/exa/trust_pb/trust_pb.d.ts +0 -582
  48. package/dist/types/discovery/devin.d.ts +0 -24
  49. package/dist/types/discovery/gemini.d.ts +0 -25
  50. package/dist/types/discovery/gitlab-duo-workflow.d.ts +0 -30
  51. package/dist/types/discovery/index.d.ts +0 -5
  52. package/dist/types/discovery/openai-compatible.d.ts +0 -74
  53. package/dist/types/effort.d.ts +0 -10
  54. package/dist/types/fireworks-model-id.d.ts +0 -23
  55. package/dist/types/hosts.d.ts +0 -164
  56. package/dist/types/identity/bundled.d.ts +0 -3
  57. package/dist/types/identity/classify.d.ts +0 -69
  58. package/dist/types/identity/dialect.d.ts +0 -3
  59. package/dist/types/identity/family.d.ts +0 -181
  60. package/dist/types/identity/id.d.ts +0 -12
  61. package/dist/types/identity/index.d.ts +0 -8
  62. package/dist/types/identity/markers.d.ts +0 -4
  63. package/dist/types/identity/priority.d.ts +0 -1
  64. package/dist/types/identity/reference.d.ts +0 -29
  65. package/dist/types/index.d.ts +0 -17
  66. package/dist/types/model-cache.d.ts +0 -23
  67. package/dist/types/model-manager.d.ts +0 -77
  68. package/dist/types/model-thinking.d.ts +0 -66
  69. package/dist/types/models.d.ts +0 -12
  70. package/dist/types/provider-models/bundled-references.d.ts +0 -13
  71. package/dist/types/provider-models/cache-provider-id.d.ts +0 -9
  72. package/dist/types/provider-models/descriptor-types.d.ts +0 -76
  73. package/dist/types/provider-models/descriptors.d.ts +0 -504
  74. package/dist/types/provider-models/google.d.ts +0 -27
  75. package/dist/types/provider-models/index.d.ts +0 -7
  76. package/dist/types/provider-models/ollama.d.ts +0 -22
  77. package/dist/types/provider-models/openai-compat.d.ts +0 -599
  78. package/dist/types/provider-models/special.d.ts +0 -53
  79. package/dist/types/types.d.ts +0 -811
  80. package/dist/types/utils.d.ts +0 -20
  81. package/dist/types/variant-collapse.d.ts +0 -133
  82. package/dist/types/wire/alibaba-token-plan.d.ts +0 -22
  83. package/dist/types/wire/codex.d.ts +0 -42
  84. package/dist/types/wire/coreweave.d.ts +0 -12
  85. package/dist/types/wire/gemini-headers.d.ts +0 -37
  86. package/dist/types/wire/github-copilot.d.ts +0 -39
package/CHANGELOG.md CHANGED
@@ -2,9 +2,81 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.0.2] - 2026-08-15
6
+
7
+ ## [17.3.2] - 2026-08-13
8
+
9
+ ### Added
10
+
11
+ - Added support for the `deepseek-v4-pro:preview` model
12
+ - Added support for the `gemini-3.7-flash` model
13
+ - Added dynamic Antigravity client-version discovery from the official update manifest (darwin/arm64 channel), so version-gated models appear without a code change; `PI_AI_ANTIGRAVITY_VERSION` remains available as an override.
14
+
15
+ ### Fixed
16
+
17
+ - Fixed Antigravity discovery missing Gemini 3.7 Flash: Cloud Code Assist gates newer models on the client version in the `User-Agent`, and the pinned `antigravity/hub/2.1.4` was too old. The user-agent now matches the captured 2.8.0 client format (`antigravity/hub/2.8.0 (aidev_client; os_type=darwin; arch=arm64; cl=963137146)`); os_type/arch stay pinned to the darwin/arm64 reference client. Overridable via `PI_AI_ANTIGRAVITY_VERSION` / `PI_AI_ANTIGRAVITY_CL` / `PI_AI_ANTIGRAVITY_OS` / `PI_AI_ANTIGRAVITY_ARCH`.
18
+
19
+ ### Removed
20
+
21
+ - Removed `ANTIGRAVITY_SYSTEM_INSTRUCTION` from `wire/gemini-headers`; the Antigravity transport and web search no longer inject a fake identity prompt.
22
+
23
+ ## [17.3.1] - 2026-08-13
24
+
25
+ ### Added
26
+
27
+ - Added dynamic Antigravity and Gemini CLI discovery support for Gemini 3.7 Flash, with low/medium/high thinking-level routing.
28
+
5
29
  ### Changed
6
30
 
7
- - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@oh-my-pi` version lineage.
31
+ - Updated model metadata, context windows, pricing, and configurations in the catalog
32
+
33
+ ## [17.3.0] - 2026-08-13
34
+
35
+ ### Breaking Changes
36
+
37
+ - Removed `OpenAICompat.enableGeminiThinkingLoopGuard`; thinking-loop eligibility is derived solely from the `model.id` family.
38
+
39
+ ### Added
40
+
41
+ - Added first-party OpenAI Daybreak Blue, Daybreak Red, and GPT-5.6 Cyber models with full support for their documented API pricing (including long-context rates above 272K input), token limits, tools, and reasoning effort controls (off/low/medium/high/xhigh/max).
42
+ - Added calculateUncachedInputCost() to calculate prompt pricing against active context-length tiers without prompt caching.
43
+
44
+ ### Fixed
45
+
46
+ - Fixed Anthropic cache-write pricing to correctly honor mixed 5-minute and 1-hour TTL usage instead of incorrectly charging all writes at the 5-minute rate.
47
+ - Fixed Ollama Cloud DeepSeek V4 Flash and older reasoners to correctly apply the DeepSeek effort contract (e.g., low/high/max) instead of the generic effort ladder.
48
+ - Added a default request timeout to OpenAI-compatible model discovery to prevent stalled provider endpoints from hanging startup indefinitely.
49
+ - Fixed Anthropic cache-write pricing to honor mixed 5-minute and 1-hour TTL usage instead of charging every write at the 5-minute rate.
50
+ - Fixed Ollama Cloud DeepSeek V4 Flash (including dated/preview tags like `deepseek-v4-flash:0731`) exposing the generic `minimal`/`low`/`medium`/`high`/`xhigh` effort ladder without `max`; the `ollama-chat` transport now applies the DeepSeek effort contract (Flash → `low`/`high`/`max`, older reasoners → `high`/`max`), matching the direct API and every other host ([#8334](https://github.com/can1357/oh-my-pi/issues/8334)).
51
+ - Exposed the `low` reasoning-effort tier for DeepSeek V4 Pro on the direct API and faithful aggregator routes, matching DeepSeek's updated API contract advertising `reasoning_effort` `low`/`high`/`max` for both V4 SKUs; OpenRouter's non-Flash route still exposes only `high`, and the older V3.x/R1 reasoners remain `high`/`max` ([#8405](https://github.com/can1357/oh-my-pi/issues/8405)).
52
+ - Bounded OpenAI-compatible model discovery with a default request timeout so a stalled provider `/models` endpoint can no longer hang startup indefinitely in `resolveModelDiscoveryFallback` ([#8315](https://github.com/can1357/oh-my-pi/issues/8315)).
53
+ - Fixed Codex-discovered `gpt-daybreak-*` aliases being treated as unknown models, restoring the GPT-5.6 `low`/`medium`/`high`/`xhigh`/`max` effort ladder and its 372K fallback only when the Codex registry omits `context_window`.
54
+ - Fixed first-party OpenAI GPT-5.6 aliases to preserve wire-level `off` through generated pro aliases and to price requests above 272K input at each SKU's documented long-context rates.
55
+
56
+ ## [17.2.15] - 2026-08-12
57
+
58
+ ### Fixed
59
+
60
+ - Fixed classification of model IDs with large minor versions (e.g., `claude-opus-5-11`) or three-part versions, ensuring they no longer fall back to stale default configurations.
61
+
62
+ ## [17.2.13] - 2026-08-11
63
+
64
+ ### Changed
65
+
66
+ - Standardized catalog discovery User-Agent headers on `omp/<version>` via the shared `USER_AGENT` utility.
67
+
68
+ ### Fixed
69
+
70
+ - Marked `meta/muse-spark-1.2` and `muse-spark-1.2-contributor` as image-capable (`input: ["text", "image"]`) with the same Responses reasoning, thinking, and cost metadata as `muse-spark-1.1` (contributor uses its discounted 0.1/0.2 pricing), so `omp models` no longer lists them as text-only.
71
+ - Fixed GLM-5.2 thinking levels across Baseten, CoreWeave, HuggingFace, and other uppercase-ID resellers, which were getting the generic `xhigh` effort ladder instead of the GLM-5.2-specific tiers. Also added Baseten `zai-org/GLM-5.2-Fast` and Fireworks `glm-5.2-fast` as reasoning models ([#8200](https://github.com/can1357/oh-my-pi/pull/8200) by [@jcfrancisco](https://github.com/jcfrancisco)).
72
+
73
+ ## [17.2.12] - 2026-08-08
74
+
75
+ ### Fixed
76
+
77
+ - Fixed dynamically discovered `alibaba-token-plan/qwen3.8-max` metadata so thinking controls and image input are available ([#8019](https://github.com/can1357/oh-my-pi/issues/8019)).
78
+ - Routed `opencode-go/deepseek-v4-flash` through the OpenAI responses API — the OpenCode Go gateway does not serve this model at `/zen/go/v1/chat/completions`, only at `/zen/go/v1/responses` (`deepseek-v4-pro` keeps chat completions).
79
+
8
80
  ## [17.2.11] - 2026-08-07
9
81
 
10
82
  ### Fixed
@@ -816,8 +888,8 @@
816
888
 
817
889
  ### Added
818
890
 
819
- - Added the `ToolCallSyntax` union and `FALLBACK_TOOL_SYNTAX` constant to `@oh-my-pi/pi-catalog/identity` (re-exported from `@oh-my-pi/pi-ai/grammar`).
820
- - Added `preferredToolSyntax(modelId)` to `@oh-my-pi/pi-catalog/identity`, resolving a model's native tool-call syntax affinity from its family token (Claude→`anthropic`, GLM→`glm`, Kimi→`kimi`, Qwen→`qwen3`, DeepSeek→`deepseek`, OpenAI/gpt-oss→`harmony`, else the `xml` fallback).
891
+ - Added the `ToolCallSyntax` union and `FALLBACK_TOOL_SYNTAX` constant to `@linxiraos/pi-catalog/identity` (re-exported from `@linxiraos/pi-ai/grammar`).
892
+ - Added `preferredToolSyntax(modelId)` to `@linxiraos/pi-catalog/identity`, resolving a model's native tool-call syntax affinity from its family token (Claude→`anthropic`, GLM→`glm`, Kimi→`kimi`, Qwen→`qwen3`, DeepSeek→`deepseek`, OpenAI/gpt-oss→`harmony`, else the `xml` fallback).
821
893
  - Added `flux-1-schnell-fp8` to the Fireworks serverless model catalog
822
894
  - Added `gpt-oss-20b` to the Fireworks model catalog
823
895
  - Added `qwen3-embedding-8b` to the Fireworks model catalog
@@ -835,7 +907,7 @@
835
907
 
836
908
  ### Added
837
909
 
838
- - Added `modelFamilyToken(modelId)` to `@oh-my-pi/pi-catalog/identity`: a coarse vendor-lineage token (`anthropic`/`openai`/`gemini`/`kimi`/…) for "are two models the same family?" comparisons, backed by `parseKnownModel` canonical-id normalization. Opaque and comparison-only; kind/variant collapsed onto the vendor token ([#2406](https://github.com/can1357/oh-my-pi/issues/2406))
910
+ - Added `modelFamilyToken(modelId)` to `@linxiraos/pi-catalog/identity`: a coarse vendor-lineage token (`anthropic`/`openai`/`gemini`/`kimi`/…) for "are two models the same family?" comparisons, backed by `parseKnownModel` canonical-id normalization. Opaque and comparison-only; kind/variant collapsed onto the vendor token ([#2406](https://github.com/can1357/oh-my-pi/issues/2406))
839
911
 
840
912
  ### Changed
841
913
 
@@ -971,7 +1043,7 @@
971
1043
  - `buildModel(spec)` (`build.ts`) is now the single Model constructor: it materializes the fully-resolved compat record and canonical thinking metadata exactly once (compat first, thinking derived from identity + resolved compat), so `Model.compat` is a required, complete `CompatOf<TApi>` (`ResolvedOpenAICompat`/`ResolvedOpenAIResponsesCompat`/`ResolvedAnthropicCompat`) and request-path code reads fields with zero URL parsing and zero per-request allocation. Sparse user/config overrides live on the new `ModelSpec<TApi>` input shape and survive on `Model.compatConfig` for introspection.
972
1044
  - Added `ResolvedAnthropicCompat.supportsSamplingParams` (Opus 4.7+/Fable/Mythos reject `temperature`/`top_p`/`top_k` with a 400), baked at build time from model identity so the request path stops re-parsing model ids.
973
1045
  - Compat detection gained model-time flags so handlers stop sniffing baseUrl: completions `supportsReasoningParams`, `alwaysSendMaxTokens`, `isOpenRouterHost`, `isVercelGatewayHost`, `streamIdleTimeoutMs`, and a precomputed `whenThinking` alternate view (OpenCode `reasoning_content` gating, #1071/#1484); responses `strictResponsesPairing`, `supportsLongPromptCacheRetention`, `supportsReasoningEffort`; anthropic `officialEndpoint`, `requiresToolResultId`, `replayUnsignedThinking`.
974
- - New `@oh-my-pi/pi-catalog` package: the model catalog extracted from `@oh-my-pi/pi-ai`. Owns the bundled `models.json` and its generation pipeline (`scripts/generate-models.ts`), the core model data types (`Model`, `Api`, `ThinkingConfig`, `Effort`, `Usage`, compat interfaces), thinking metadata enrichment and generated policies (`model-thinking.ts`), the SQLite model cache and model manager, per-provider discovery factories (`provider-models/`), the discovery protocol clients (`discovery/`), and the new `CATALOG_PROVIDERS` table — the single source of truth for provider ids, default models, and discovery wiring (`KnownProvider`, `PROVIDER_DESCRIPTORS`, and `DEFAULT_MODEL_PER_PROVIDER` are derived from it).
1046
+ - New `@linxiraos/pi-catalog` package: the model catalog extracted from `@linxiraos/pi-ai`. Owns the bundled `models.json` and its generation pipeline (`scripts/generate-models.ts`), the core model data types (`Model`, `Api`, `ThinkingConfig`, `Effort`, `Usage`, compat interfaces), thinking metadata enrichment and generated policies (`model-thinking.ts`), the SQLite model cache and model manager, per-provider discovery factories (`provider-models/`), the discovery protocol clients (`discovery/`), and the new `CATALOG_PROVIDERS` table — the single source of truth for provider ids, default models, and discovery wiring (`KnownProvider`, `PROVIDER_DESCRIPTORS`, and `DEFAULT_MODEL_PER_PROVIDER` are derived from it).
975
1047
  - New `identity/` module centralizing model-identity concerns that were previously duplicated across packages: family classification and version parsing (`identity/classify.ts`, extracted from pi-ai's `model-thinking` internals), canonical model equivalence with injected reference data (`identity/equivalence.ts`, from coding-agent's `model-equivalence`), proxy/reseller reference lookup (`identity/reference.ts`, from coding-agent's `model-registry`), bracket-affix and id-segment helpers (`identity/id.ts`), a single trailing-marker vocabulary with canonical vs reference flavors (`identity/markers.ts` — `search` stays reference-only so Perplexity's `sonar-pro-search` remains canonical-distinct), and provider priority ordering (`identity/priority.ts`).
976
1048
  - Memoized bundled-reference accessors (`getBundledCanonicalReferenceData` / `getBundledModelReferenceIndex` in `identity/bundled.ts`): one lazy walk of the bundled catalog feeds both canonical equivalence and proxy-reference lookup, so consumers no longer hand-roll the glue.
977
1049
  - `identity/selection.ts`: pure canonical-variant selection (`resolveCanonicalVariant`, `buildCanonicalModelOrder`, `CanonicalVariantPreferences`) extracted from the coding-agent registry — provider rank, then exact-id match, variant source, id length, and candidate order.
@@ -990,10 +1062,20 @@
990
1062
 
991
1063
  - Fixed Anthropic official-endpoint detection to require strict HTTPS hostname matching so non-official or lookalike URLs are no longer treated as official Anthropic hosts
992
1064
  - Fixed Ollama Cloud dynamic discovery so same-id matches from other providers no longer supply context-window or max-output-token limits for discovered models.
993
- - Wired `@oh-my-pi/pi-catalog` into the release publish package list, tarball install smoke test, and root `bun generate-models` script.
1065
+ - Wired `@linxiraos/pi-catalog` into the release publish package list, tarball install smoke test, and root `bun generate-models` script.
994
1066
  - Fixed `supportsAdaptiveThinkingDisplay` only matching dash-form version ids: dotted ids (`claude-opus-4.7`) now classify through `identity/classify` like every other anthropic predicate, so six bundled dotted Opus 4.7/4.8 entries (github-copilot, vercel-ai-gateway, zenmux) regain adaptive `display` support; bare dated ids (`claude-opus-4-20250514` = Opus 4.0) stay excluded.
995
1067
  - Fixed the OpenRouter anthropic adaptive-effort map misclassifying bare dated Opus ids (`claude-opus-4-20250514` parsed as version 4.20 → wrongly adaptive); the map now derives from the shared classifier and the shared 4-/5-tier tables.
996
1068
 
997
1069
  ### Removed
998
1070
 
999
1071
  - Removed the runtime enrichment layer: `enrichModelThinking` (and its non-enumerable memo-slot cache), `refreshModelThinking`, `modelOmitsReasoningEffort`, and the `model-thinking` re-exports of generator-only policies. Thinking metadata is resolved exactly once inside `buildModel`; runtime helpers (`getSupportedEfforts`, `clampThinkingLevelForModel`, `requireSupportedEffort`, the effort mappers) are pure field reads.
1072
+
1073
+ ## [1.0.1] - 2026-08-14
1074
+
1075
+ - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@oh-my-pi` version lineage.
1076
+
1077
+ ## [1.0.0] - 2026-08-13
1078
+
1079
+ ### Changed
1080
+
1081
+ - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@oh-my-pi` version lineage.
package/package.json CHANGED
@@ -1,101 +1,100 @@
1
1
  {
2
- "type": "module",
3
- "name": "@linxiraos/pi-catalog",
4
- "version": "1.0.0",
5
- "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
- "homepage": "https://linxira-os.github.io",
7
- "author": "Can Boluk",
8
- "license": "MIT",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/Linxira-OS/linxira-zeta.git",
12
- "directory": "packages/catalog"
13
- },
14
- "bugs": {
15
- "url": "https://github.com/can1357/oh-my-pi/issues"
16
- },
17
- "keywords": [
18
- "ai",
19
- "llm",
20
- "models",
21
- "catalog",
22
- "discovery"
23
- ],
24
- "main": "./src/index.ts",
25
- "types": "./dist/types/index.d.ts",
26
- "scripts": {
27
- "check": "biome check . && bun run check:types",
28
- "check:types": "tsgo -p tsconfig.json --noEmit",
29
- "lint": "biome lint .",
30
- "test": "bun test --parallel",
31
- "fix": "biome check --write --unsafe .",
32
- "fmt": "biome format --write .",
33
- "gen:models": "bun scripts/generate-models.ts",
34
- "gen:cursor-proto": "protoc --plugin=protoc-gen-es=../../node_modules/.bin/protoc-gen-es --es_out=src/discovery/cursor-gen --es_opt=target=ts -I ../ai/src/providers/cursor/proto ../ai/src/providers/cursor/proto/agent.proto"
35
- },
36
- "dependencies": {
37
- "@bufbuild/protobuf": "^2.12.1",
38
- "@linxiraos/pi-omptype": "1.0.0",
39
- "@linxiraos/pi-utils": "1.0.0"
40
- },
41
- "devDependencies": {
42
- "@types/bun": "^1.3.14",
43
- "@linxiraos/pi-ai": "1.0.0"
44
- },
45
- "engines": {
46
- "bun": ">=1.3.14"
47
- },
48
- "files": [
49
- "src",
50
- "README.md",
51
- "CHANGELOG.md",
52
- "dist/types"
53
- ],
54
- "exports": {
55
- ".": {
56
- "types": "./dist/types/index.d.ts",
57
- "import": "./src/index.ts"
58
- },
59
- "./models.json": {
60
- "types": "./dist/types/models.json.d.d.ts",
61
- "import": "./src/models.json"
62
- },
63
- "./provider-models": {
64
- "types": "./dist/types/provider-models/index.d.ts",
65
- "import": "./src/provider-models/index.ts"
66
- },
67
- "./provider-models/*": {
68
- "types": "./dist/types/provider-models/*.d.ts",
69
- "import": "./src/provider-models/*.ts"
70
- },
71
- "./discovery": {
72
- "types": "./dist/types/discovery/index.d.ts",
73
- "import": "./src/discovery/index.ts"
74
- },
75
- "./discovery/*": {
76
- "types": "./dist/types/discovery/*.d.ts",
77
- "import": "./src/discovery/*.ts"
78
- },
79
- "./identity": {
80
- "types": "./dist/types/identity/index.d.ts",
81
- "import": "./src/identity/index.ts"
82
- },
83
- "./identity/*": {
84
- "types": "./dist/types/identity/*.d.ts",
85
- "import": "./src/identity/*.ts"
86
- },
87
- "./wire/*": {
88
- "types": "./dist/types/wire/*.d.ts",
89
- "import": "./src/wire/*.ts"
90
- },
91
- "./compat/*": {
92
- "types": "./dist/types/compat/*.d.ts",
93
- "import": "./src/compat/*.ts"
94
- },
95
- "./*": {
96
- "types": "./dist/types/*.d.ts",
97
- "import": "./src/*.ts"
98
- },
99
- "./*.js": "./src/*.ts"
100
- }
2
+ "type": "module",
3
+ "name": "@linxiraos/pi-catalog",
4
+ "version": "1.0.2",
5
+ "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
+ "homepage": "https://linxira-os.github.io",
7
+ "author": "Can Boluk",
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/Linxira-OS/linxira-zeta.git",
12
+ "directory": "packages/catalog"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/can1357/oh-my-pi/issues"
16
+ },
17
+ "keywords": [
18
+ "ai",
19
+ "llm",
20
+ "models",
21
+ "catalog",
22
+ "discovery"
23
+ ],
24
+ "main": "./src/index.ts",
25
+ "types": "./src/index.ts",
26
+ "scripts": {
27
+ "check": "biome check . && bun run check:types",
28
+ "check:types": "tsgo -p tsconfig.json --noEmit",
29
+ "lint": "biome lint .",
30
+ "test": "bun test --parallel",
31
+ "fix": "biome check --write --unsafe .",
32
+ "fmt": "biome format --write .",
33
+ "gen:models": "bun scripts/generate-models.ts",
34
+ "gen:cursor-proto": "protoc --plugin=protoc-gen-es=../../node_modules/.bin/protoc-gen-es --es_out=src/discovery/cursor-gen --es_opt=target=ts -I ../ai/src/providers/cursor/proto ../ai/src/providers/cursor/proto/agent.proto"
35
+ },
36
+ "dependencies": {
37
+ "@bufbuild/protobuf": "catalog:",
38
+ "@linxiraos/pi-omptype": "catalog:",
39
+ "@linxiraos/pi-utils": "catalog:"
40
+ },
41
+ "devDependencies": {
42
+ "@linxiraos/pi-ai": "catalog:",
43
+ "@types/bun": "catalog:"
44
+ },
45
+ "engines": {
46
+ "bun": ">=1.3.14"
47
+ },
48
+ "files": [
49
+ "src",
50
+ "README.md",
51
+ "CHANGELOG.md"
52
+ ],
53
+ "exports": {
54
+ ".": {
55
+ "types": "./src/index.ts",
56
+ "import": "./src/index.ts"
57
+ },
58
+ "./models.json": {
59
+ "types": "./src/models.json.d.ts",
60
+ "import": "./src/models.json"
61
+ },
62
+ "./provider-models": {
63
+ "types": "./src/provider-models/index.ts",
64
+ "import": "./src/provider-models/index.ts"
65
+ },
66
+ "./provider-models/*": {
67
+ "types": "./src/provider-models/*.ts",
68
+ "import": "./src/provider-models/*.ts"
69
+ },
70
+ "./discovery": {
71
+ "types": "./src/discovery/index.ts",
72
+ "import": "./src/discovery/index.ts"
73
+ },
74
+ "./discovery/*": {
75
+ "types": "./src/discovery/*.ts",
76
+ "import": "./src/discovery/*.ts"
77
+ },
78
+ "./identity": {
79
+ "types": "./src/identity/index.ts",
80
+ "import": "./src/identity/index.ts"
81
+ },
82
+ "./identity/*": {
83
+ "types": "./src/identity/*.ts",
84
+ "import": "./src/identity/*.ts"
85
+ },
86
+ "./wire/*": {
87
+ "types": "./src/wire/*.ts",
88
+ "import": "./src/wire/*.ts"
89
+ },
90
+ "./compat/*": {
91
+ "types": "./src/compat/*.ts",
92
+ "import": "./src/compat/*.ts"
93
+ },
94
+ "./*": {
95
+ "types": "./src/*.ts",
96
+ "import": "./src/*.ts"
97
+ },
98
+ "./*.js": "./src/*.ts"
99
+ }
101
100
  }
package/src/build.ts CHANGED
@@ -14,12 +14,11 @@ import { buildAnthropicCompat } from "./compat/anthropic";
14
14
  import { buildBedrockCompat } from "./compat/bedrock";
15
15
  import { buildDevinCompat } from "./compat/devin";
16
16
  import { buildOpenAICompat, buildOpenAIResponsesCompat, buildOpenRouterCompat } from "./compat/openai";
17
+ import { bareModelId, parseOpenAIModel, semverGte } from "./identity/classify";
17
18
  import { resolveModelThinking } from "./model-thinking";
18
19
  import type { Api, CompatOf, Model, ModelSpec } from "./types";
19
20
  import { cleanModelName } from "./utils";
20
21
 
21
- const OPENAI_GA_COMPUTER_MODEL_RE = /^gpt-5\.(?:[4-9]|[1-9]\d)(?:[.-]|$)/i;
22
-
23
22
  function isDirectOpenAIResponsesEndpoint(spec: ModelSpec<Api>): boolean {
24
23
  if (spec.api === "openai-responses") {
25
24
  if (spec.provider !== "openai") return false;
@@ -55,7 +54,8 @@ function explicitComputerUseConfig(spec: ModelSpec<Api>): boolean | undefined {
55
54
  function supportsOpenAIGAComputerUse(spec: ModelSpec<Api>, explicitSupport: boolean | undefined): boolean {
56
55
  if (explicitSupport !== undefined) return explicitSupport;
57
56
  if (!isDirectOpenAIResponsesEndpoint(spec)) return false;
58
- return OPENAI_GA_COMPUTER_MODEL_RE.test(spec.requestModelId ?? spec.id);
57
+ const parsed = parseOpenAIModel(bareModelId(spec.requestModelId ?? spec.id));
58
+ return parsed !== null && semverGte(parsed.version, "5.4");
59
59
  }
60
60
 
61
61
  export function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi> {
@@ -22,7 +22,6 @@ import {
22
22
  isMimoModelIdOrName,
23
23
  isOpenAISamplingRestrictedModelId,
24
24
  isQwenModelId,
25
- modelFamilyToken,
26
25
  } from "../identity/family";
27
26
  import type {
28
27
  ModelSpec,
@@ -474,10 +473,6 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
474
473
  supportsSamplingParams: !isOpenAISamplingRestrictedModelId(spec.id),
475
474
  reasoningEffortMap: {},
476
475
  supportsUsageInStreaming: !isCerebras,
477
- // pi-ai's thinking-loop guard is gemini-only; default the flag from the
478
- // family classifier so OpenAI-compat proxies serving Gemini are covered.
479
- // An opaque alias can opt in via `compat.enableGeminiThinkingLoopGuard`.
480
- enableGeminiThinkingLoopGuard: modelFamilyToken(spec.id) === "gemini",
481
476
  // Kimi (including via OpenRouter and Fireworks router-form IDs such as
482
477
  // `accounts/fireworks/routers/kimi-*`) calculates TPM rate limits based on
483
478
  // max_tokens, not actual output. The official Kimi K2 model guidance
@@ -749,7 +744,6 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
749
744
  // lands on Moonshot's MFJS validator.
750
745
  toolSchemaFlavor: isKimiModel ? "moonshot-mfjs" : undefined,
751
746
  alwaysSendMaxTokens: spec.id ? isKimiModelId(spec.id) : false,
752
- enableGeminiThinkingLoopGuard: modelFamilyToken(spec.id ?? "") === "gemini",
753
747
  supportsObfuscationOptOut: isOpenAIUrl || spec.provider === "openai",
754
748
  stripDeepseekSpecialTokens:
755
749
  Boolean(id) && isDeepseekModelIdOrName(id) && (spec.provider === "nvidia" || spec.provider === "deepseek"),
@@ -6,7 +6,7 @@ import {
6
6
  collapseEffortVariants,
7
7
  type VariantCollapseTable,
8
8
  } from "../variant-collapse";
9
- import { getAntigravityUserAgent } from "../wire/gemini-headers";
9
+ import { ensureAntigravityVersion, getAntigravityUserAgent } from "../wire/gemini-headers";
10
10
 
11
11
  export const ANTIGRAVITY_PRIMARY_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
12
12
  export const ANTIGRAVITY_SANDBOX_ENDPOINT = "https://daily-cloudcode-pa.sandbox.googleapis.com";
@@ -161,6 +161,10 @@ export interface FetchAntigravityDiscoveryModelsOptions {
161
161
  export async function fetchAntigravityDiscoveryModels(
162
162
  options: FetchAntigravityDiscoveryModelsOptions,
163
163
  ): Promise<ModelSpec<"google-gemini-cli">[] | null> {
164
+ if (options.userAgent === undefined) {
165
+ await ensureAntigravityVersion(options.fetcher ?? fetch, options.signal);
166
+ }
167
+
164
168
  const fetcher = discoveryFetch(options.fetcher);
165
169
  const endpoints = options.endpoint
166
170
  ? [trimTrailingSlashes(options.endpoint)]
@@ -4,6 +4,18 @@ import { discoveryFetch } from "../utils";
4
4
 
5
5
  const MODELS_PATH = "/models";
6
6
 
7
+ /**
8
+ * Default hard deadline applied to an OpenAI-compatible `/models` probe when
9
+ * the caller supplies neither an `AbortSignal` nor an explicit `timeoutMs`.
10
+ *
11
+ * Built-in provider model managers (openrouter, xAI, DeepSeek, …) call
12
+ * {@link fetchOpenAICompatibleModels} with no timeout, so without this bound a
13
+ * stalled endpoint left the request pending forever and blocked startup's
14
+ * awaited `resolveModelDiscoveryFallback` discovery pass indefinitely
15
+ * (issue #8315). 10s matches the coding-agent's remote-discovery budget.
16
+ */
17
+ export const DEFAULT_OPENAI_COMPATIBLE_DISCOVERY_TIMEOUT_MS = 10_000;
18
+
7
19
  /**
8
20
  * Uses a cancellable timer rather than the native abort-timeout helper so
9
21
  * successful fast discovery requests do not leave armed timeout signals for
@@ -96,7 +108,11 @@ export interface FetchOpenAICompatibleModelsOptions<TApi extends Api> {
96
108
  headers?: Record<string, string>;
97
109
  /** Optional AbortSignal for request cancellation; caller owns its lifecycle. */
98
110
  signal?: AbortSignal;
99
- /** Optional cancellable request timeout used when `signal` is omitted. */
111
+ /**
112
+ * Optional cancellable request timeout used when `signal` is omitted.
113
+ * Defaults to {@link DEFAULT_OPENAI_COMPATIBLE_DISCOVERY_TIMEOUT_MS} so a
114
+ * stalled endpoint can never hang discovery indefinitely.
115
+ */
100
116
  timeoutMs?: number;
101
117
  /** Optional fetch implementation override for testing/custom runtimes. */
102
118
  fetch?: FetchImpl;
@@ -164,9 +180,10 @@ export async function fetchOpenAICompatibleModels<TApi extends Api>(
164
180
  const payload =
165
181
  options.signal !== undefined
166
182
  ? await fetchPayload(options.signal)
167
- : options.timeoutMs !== undefined
168
- ? await withOpenAICompatibleDiscoveryTimeout(options.timeoutMs, fetchPayload)
169
- : await fetchPayload();
183
+ : await withOpenAICompatibleDiscoveryTimeout(
184
+ options.timeoutMs ?? DEFAULT_OPENAI_COMPATIBLE_DISCOVERY_TIMEOUT_MS,
185
+ fetchPayload,
186
+ );
170
187
  if (payload === null) {
171
188
  return null;
172
189
  }
@@ -122,16 +122,31 @@ export const parseAnthropicModel = parser((modelId): AnthropicModel | null => {
122
122
  return { family: "anthropic", kind: kind as AnthropicKind, version };
123
123
  });
124
124
 
125
+ /**
126
+ * Rolling OpenAI aliases inherit wire capabilities from their current default
127
+ * snapshots. Keep this map aligned with the model docs when an alias advances.
128
+ */
129
+ const OPENAI_ALIAS_VERSIONS: Readonly<Record<string, string>> = {
130
+ "daybreak-blue-latest": "5.6",
131
+ "gpt-daybreak-blue-latest": "5.6",
132
+ "daybreak-red-latest": "5.6",
133
+ "gpt-daybreak-red-latest": "5.6",
134
+ };
135
+
125
136
  export const parseOpenAIModel = parser((modelId): OpenAIModel | null => {
126
- const match = /gpt-(\d+(?:\.\d+){0,2})(?:-(codex-spark|codex-mini|codex-max|codex|mini|max|nano))?\b/.exec(modelId);
127
- if (!match) {
137
+ const aliasVersion = OPENAI_ALIAS_VERSIONS[modelId];
138
+ const match = aliasVersion
139
+ ? null
140
+ : /gpt-(\d+(?:\.\d+){0,2})(?:-(codex-spark|codex-mini|codex-max|codex|mini|max|nano))?\b/.exec(modelId);
141
+ const versionInput = aliasVersion ?? match?.[1];
142
+ if (!versionInput) {
128
143
  return null;
129
144
  }
130
- const version = parseSemVer(match[1]);
145
+ const version = parseSemVer(versionInput);
131
146
  if (!version) {
132
147
  return null;
133
148
  }
134
- return { family: "openai", variant: (match[2] as OpenAIVariant | undefined) ?? "base", version };
149
+ return { family: "openai", variant: (match?.[2] as OpenAIVariant | undefined) ?? "base", version };
135
150
  });
136
151
 
137
152
  /**
@@ -143,7 +158,7 @@ export const parseOpenAIModel = parser((modelId): OpenAIModel | null => {
143
158
  * `parseKnownModel`.
144
159
  */
145
160
  export const parseGlmModel = parser((modelId): GlmModel | null => {
146
- const match = /glm-(\d{1,2}(?:\.\d+)?)(v)?(?:-(air|turbo|flashx|flash|preview))?\b/.exec(modelId);
161
+ const match = /glm-(\d{1,2}(?:\.\d+)?)(v)?(?:-(air|turbo|flashx|flash|preview))?\b/i.exec(modelId);
147
162
  if (!match) {
148
163
  return null;
149
164
  }
@@ -153,8 +168,8 @@ export const parseGlmModel = parser((modelId): GlmModel | null => {
153
168
  }
154
169
  return {
155
170
  family: "glm",
156
- variant: (match[3] as GlmVariant | undefined) ?? "base",
157
- vision: match[2] === "v",
171
+ variant: (match[3]?.toLowerCase() as GlmVariant | undefined) ?? "base",
172
+ vision: match[2]?.toLowerCase() === "v",
158
173
  version,
159
174
  };
160
175
  });
@@ -181,7 +196,9 @@ function createSemVer(major: number, minor: number, patch = 0): SemVer {
181
196
  return { major, minor, patch };
182
197
  }
183
198
 
184
- // extend this table if we need anything more than 9.10
199
+ // Fast path for the common 1–2 component versions; anything the table misses
200
+ // (large minors, 3-part versions) parses dynamically below so no future
201
+ // version ever classifies as unknown (the failure class #8256 fixed).
185
202
  const precomputeTable: Record<string, SemVer> = {};
186
203
  for (let major = 0; major <= 9; major++) {
187
204
  for (let minor = 0; minor <= 10; minor++) {
@@ -192,8 +209,14 @@ for (let major = 0; major <= 9; major++) {
192
209
  precomputeTable[`${major}`] = createSemVer(major, 0, 0);
193
210
  }
194
211
 
212
+ const SEMVER_PATTERN = /^(\d{1,2})(?:[.-](\d{1,2}))?(?:[.-](\d{1,2}))?$/;
213
+
195
214
  export function parseSemVer(version: string): SemVer | null {
196
- return precomputeTable[version] ?? null;
215
+ const hit = precomputeTable[version];
216
+ if (hit) return hit;
217
+ const match = SEMVER_PATTERN.exec(version);
218
+ if (!match) return null;
219
+ return createSemVer(Number(match[1]), Number(match[2] ?? 0), Number(match[3] ?? 0));
197
220
  }
198
221
 
199
222
  export function semverGte(left: SemVer | string, right: SemVer | string): boolean {
@@ -85,9 +85,11 @@ export const isDeepseekModelIdOrName = memo((value: string): boolean => {
85
85
 
86
86
  /**
87
87
  * DeepSeek V4 Flash SKU in any host/namespace form (`deepseek-v4-flash`, dated
88
- * `deepseek-v4-flash-0731`, `deepseek-ai/DeepSeek-V4-Flash`). Flash is the only
89
- * V4 model whose `reasoning_effort` accepts the `low` tier; V4 Pro tops out at
90
- * `high`/`max`. See https://api-docs.deepseek.com/api/create-chat-completion.
88
+ * `deepseek-v4-flash-0731`, `deepseek-ai/DeepSeek-V4-Flash`). Both V4 SKUs
89
+ * (Flash and Pro) accept the `low` reasoning_effort tier; this predicate keeps
90
+ * Flash distinguishable from Pro where a host quirk splits them (e.g.
91
+ * OpenRouter exposes `low` on Flash but only `high` on non-Flash V4).
92
+ * See https://api-docs.deepseek.com/api/create-chat-completion.
91
93
  */
92
94
  export const isDeepseekV4FlashModelId = memo((modelId: string): boolean => {
93
95
  return bareModelId(modelId).toLowerCase().includes("deepseek-v4-flash");
@@ -98,6 +100,16 @@ export const isMimoModelIdOrName = memo((value: string): boolean => {
98
100
  return value.toLowerCase().includes("mimo");
99
101
  });
100
102
 
103
+ /** Gemini family ids in any namespace form (`gemini-*`, `google/gemini-*`, `openrouter/google/gemini-…`). */
104
+ export const isGeminiModelId = memo((modelId: string): boolean => {
105
+ return /(^|\/)gemini[-.]?/i.test(modelId);
106
+ });
107
+
108
+ /** Grok family ids across namespace and delimiter forms (`grok-*`, `cursor-grok-*`, `xai/grok-*`). */
109
+ export const isGrokModelId = memo((modelId: string): boolean => {
110
+ return /(?:^|[./_-])grok(?:[-.]|$)/i.test(modelId);
111
+ });
112
+
101
113
  const GROK_EFFORT_CAPABLE_PREFIXES = ["grok-3-mini", "grok-4.20-multi-agent", "grok-4.3", "grok-4.5"] as const;
102
114
 
103
115
  /**
@@ -259,12 +271,14 @@ export const modelFamilyToken = memo((modelId: string): string => {
259
271
  const parsed = parseKnownModel(modelId);
260
272
  if (parsed.family !== "unknown") return parsed.family;
261
273
  if (isClaudeModelId(modelId) || isAnthropicNamespacedModelId(modelId)) return "anthropic";
274
+ if (isGeminiModelId(modelId)) return "gemini";
275
+ if (isGrokModelId(modelId)) return "grok";
276
+ if (isDeepseekModelIdOrName(modelId)) return "deepseek";
262
277
  if (isOpenAIModelId(modelId)) return "openai";
263
278
  if (isKimiModelId(modelId)) return "kimi";
264
279
  if (isQwenModelId(modelId)) return "qwen";
265
280
  if (isMinimaxM2FamilyModelId(modelId) || isMinimaxM3FamilyModelId(modelId)) return "minimax";
266
281
  if (isOpenAIGptOssModelId(modelId)) return "gpt-oss";
267
- if (isDeepseekModelIdOrName(modelId)) return "deepseek";
268
282
  if (isMimoModelIdOrName(modelId)) return "mimo";
269
283
  if (isGemmaModelId(modelId)) return "gemma";
270
284
  if (parseGlmModel(bareModelId(modelId))) return "glm";
@@ -1,7 +1,7 @@
1
1
  import { buildModel } from "./build";
2
2
  import { readModelCache, writeModelCache } from "./model-cache";
3
3
  import { type GeneratedProvider, getBundledModels } from "./models";
4
- import type { Api, Model, ModelSpec, Provider } from "./types";
4
+ import type { Api, Model, ModelCost, ModelSpec, Provider, TokenCost } from "./types";
5
5
  import { isRecord } from "./utils";
6
6
  import { collapseBuiltModelVariants } from "./variant-collapse";
7
7
 
@@ -510,6 +510,7 @@ function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamic
510
510
  const reasoning = dynamicReasoningAuthoritative
511
511
  ? dynamicModel.reasoning
512
512
  : existingModel.reasoning || dynamicModel.reasoning;
513
+ const longContextCost = dynamicModel.cost.longContext ?? existingModel.cost.longContext;
513
514
  // Re-build from spec stage: sparse compat comes from `compatConfig` (the
514
515
  // verbatim override vocabulary), never the resolved `compat` record.
515
516
  return buildModel({
@@ -523,6 +524,7 @@ function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamic
523
524
  output: preferDiscoveryCost(dynamicModel.cost.output, existingModel.cost.output),
524
525
  cacheRead: preferDiscoveryCost(dynamicModel.cost.cacheRead, existingModel.cost.cacheRead),
525
526
  cacheWrite: preferDiscoveryCost(dynamicModel.cost.cacheWrite, existingModel.cost.cacheWrite),
527
+ ...(longContextCost ? { longContext: longContextCost } : {}),
526
528
  },
527
529
  contextWindow: preferDiscoveryLimit(dynamicModel.contextWindow, existingModel.contextWindow),
528
530
  maxTokens: preferDiscoveryLimit(dynamicModel.maxTokens, existingModel.maxTokens),
@@ -640,7 +642,7 @@ function isModelInputArray(value: unknown): value is ("text" | "image")[] {
640
642
  return true;
641
643
  }
642
644
 
643
- function isModelCost(value: unknown): value is Model<Api>["cost"] {
645
+ function isTokenCost(value: unknown): value is TokenCost {
644
646
  if (!isRecord(value)) {
645
647
  return false;
646
648
  }
@@ -670,3 +672,12 @@ function isModelCost(value: unknown): value is Model<Api>["cost"] {
670
672
  }
671
673
  return true;
672
674
  }
675
+
676
+ function isModelCost(value: unknown): value is ModelCost {
677
+ if (!isTokenCost(value)) return false;
678
+ const longContext = (value as TokenCost & { longContext?: unknown }).longContext;
679
+ if (longContext === undefined) return true;
680
+ if (!isTokenCost(longContext) || !isRecord(longContext)) return false;
681
+ const threshold = longContext.inputThreshold;
682
+ return typeof threshold === "number" && threshold > 0 && threshold < Infinity;
683
+ }