@prismshadow/penguin-server 0.2.15 → 0.2.17

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 (124) hide show
  1. package/README.md +1 -1
  2. package/dist/api/types.d.ts +318 -86
  3. package/dist/api/types.js +9 -3
  4. package/dist/auth-token.d.ts +1 -1
  5. package/dist/auth-token.js +2 -2
  6. package/dist/{chunk-HMTT2PX4.js → chunk-2LZDP26O.js} +8 -5
  7. package/dist/chunk-2LZDP26O.js.map +1 -0
  8. package/dist/{chunk-LPPVGHYD.js → chunk-BL4U7GYY.js} +2 -2
  9. package/dist/chunk-BL4U7GYY.js.map +1 -0
  10. package/dist/{chunk-5Z4UCHDB.js → chunk-D3JNA6ZI.js} +69 -6
  11. package/dist/chunk-D3JNA6ZI.js.map +1 -0
  12. package/dist/{chunk-TOOTEEM4.js → chunk-G7GY7PJU.js} +1 -1
  13. package/dist/chunk-G7GY7PJU.js.map +1 -0
  14. package/dist/chunk-GGIINEEK.js +3401 -0
  15. package/dist/chunk-GGIINEEK.js.map +1 -0
  16. package/dist/chunk-HDBZRVA5.js +29 -0
  17. package/dist/chunk-HDBZRVA5.js.map +1 -0
  18. package/dist/{chunk-NVWAYYRX.js → chunk-HPOHMZCH.js} +686 -531
  19. package/dist/chunk-HPOHMZCH.js.map +1 -0
  20. package/dist/{chunk-QFV3ERQO.js → chunk-OQZDL3TR.js} +2 -2
  21. package/dist/hmr/manifest.js +1 -1
  22. package/dist/index.js +9351 -5551
  23. package/dist/index.js.map +1 -1
  24. package/dist/machine-status.js +2 -2
  25. package/dist/model-catalog.d.ts +610 -0
  26. package/dist/model-catalog.js +108 -0
  27. package/dist/model-catalog.js.map +1 -0
  28. package/dist/plugin/index.d.ts +141 -78
  29. package/dist/reset-admin-password.js +3 -4
  30. package/dist/reset-admin-password.js.map +1 -1
  31. package/dist/version-report.js +2 -2
  32. package/package.json +15 -14
  33. package/web-dist/assets/{abnfDiagram-VCTEODGH-CKWh4hoA.js → abnfDiagram-VCTEODGH-DMzkb4l4.js} +1 -1
  34. package/web-dist/assets/{addon-clipboard-DxLqat7q.js → addon-clipboard-BtD2BVSi.js} +1 -1
  35. package/web-dist/assets/{addon-fit-B8oPGPkW.js → addon-fit-Dr6HWsi_.js} +1 -1
  36. package/web-dist/assets/{addon-web-links-C0W5TcK0.js → addon-web-links-VEE3YLzQ.js} +1 -1
  37. package/web-dist/assets/{arc-Dp9EkaAH.js → arc-CvMPOU_B.js} +1 -1
  38. package/web-dist/assets/{architectureDiagram-5GKGNRK7-BQ3LUcle.js → architectureDiagram-5GKGNRK7-Bk65mIBz.js} +1 -1
  39. package/web-dist/assets/{blockDiagram-I7D4REHJ-CZzyU0Jj.js → blockDiagram-I7D4REHJ-D54-XSNs.js} +1 -1
  40. package/web-dist/assets/{c4Diagram-7LVT6UL2-Qps3jeAu.js → c4Diagram-7LVT6UL2-Dm954LSt.js} +1 -1
  41. package/web-dist/assets/channel-CVHI75kz.js +1 -0
  42. package/web-dist/assets/{chunk-2Q5K7J3B-CQMntzuX.js → chunk-2Q5K7J3B-D_LJ_7Cn.js} +1 -1
  43. package/web-dist/assets/{chunk-5VM5RSS4-2H2ZJAte.js → chunk-5VM5RSS4-B8RI4tl3.js} +1 -1
  44. package/web-dist/assets/{chunk-F27PBJKO-B30xCNBv.js → chunk-F27PBJKO-aVSYH9JV.js} +1 -1
  45. package/web-dist/assets/{chunk-IMKFNOWR-Cyfx4zDs.js → chunk-IMKFNOWR-DnkdWeq2.js} +1 -1
  46. package/web-dist/assets/{chunk-JWPE2WC7-DADUytTh.js → chunk-JWPE2WC7-C2pJzKuW.js} +1 -1
  47. package/web-dist/assets/{chunk-POPQ4Y6H-9bjsAxLS.js → chunk-POPQ4Y6H-Bx7Iikzx.js} +1 -1
  48. package/web-dist/assets/{chunk-SVP7TREG-B9xO1VpN.js → chunk-SVP7TREG-qJC2SMqr.js} +1 -1
  49. package/web-dist/assets/{chunk-TICWLB2K-B6oDkrep.js → chunk-TICWLB2K-Crl_BgKI.js} +1 -1
  50. package/web-dist/assets/{chunk-XXDRQBXY-BbU8DR4B.js → chunk-XXDRQBXY-BFFemuGm.js} +1 -1
  51. package/web-dist/assets/classDiagram-ZZMXUADV-CBdzAPFu.js +1 -0
  52. package/web-dist/assets/classDiagram-v2-VYDZK3BY-CBdzAPFu.js +1 -0
  53. package/web-dist/assets/{cose-bilkent-JH36ORCC-pkbuyec-.js → cose-bilkent-JH36ORCC-Bmh2Kx7h.js} +1 -1
  54. package/web-dist/assets/{cynefin-OW5HDTMX-DU9YQQnc.js → cynefin-OW5HDTMX-BveNWnUV.js} +1 -1
  55. package/web-dist/assets/{cynefinDiagram-5FMLGOSQ-3a3XuhQq.js → cynefinDiagram-5FMLGOSQ-85itazbJ.js} +1 -1
  56. package/web-dist/assets/{dagre-GXQ25YYZ-BfZ9C5CZ.js → dagre-GXQ25YYZ-DIZT-KY_.js} +1 -1
  57. package/web-dist/assets/{diagram-S7CK7UJ4-BoGhVBMn.js → diagram-S7CK7UJ4-Dum-g63f.js} +1 -1
  58. package/web-dist/assets/{diagram-UQ7AKVKN-zE67quty.js → diagram-UQ7AKVKN-DallMKJl.js} +1 -1
  59. package/web-dist/assets/{diagram-VSXAHHWV-NihoXeXm.js → diagram-VSXAHHWV-DWELqxfN.js} +1 -1
  60. package/web-dist/assets/{diagram-VX7I27RA-1627np0S.js → diagram-VX7I27RA-BNs0gB9E.js} +1 -1
  61. package/web-dist/assets/{diagram-Z3DM3KII-Ddg_bUan.js → diagram-Z3DM3KII-C9mF9xAd.js} +1 -1
  62. package/web-dist/assets/{ebnfDiagram-PWID7BFC-CmPUOM4j.js → ebnfDiagram-PWID7BFC-D_Diy9HH.js} +1 -1
  63. package/web-dist/assets/{erDiagram-RLTQ6QDP-DiTnEK72.js → erDiagram-RLTQ6QDP-4QTS5VIh.js} +1 -1
  64. package/web-dist/assets/{flowDiagram-HODETNUW-mGQ38tRM.js → flowDiagram-HODETNUW-CliTRrtV.js} +1 -1
  65. package/web-dist/assets/{ganttDiagram-EL5Y4UJY-DU7MlzpW.js → ganttDiagram-EL5Y4UJY-DCRd-Ss4.js} +1 -1
  66. package/web-dist/assets/{gitGraphDiagram-WWUBYQGX-CRE_3vjl.js → gitGraphDiagram-WWUBYQGX-CTz13GjS.js} +1 -1
  67. package/web-dist/assets/highlighter-BScH1Ud3.js +2 -0
  68. package/web-dist/assets/{highlighter-core-B5CvXcEK.js → highlighter-core-DKz8Z6-I.js} +1 -1
  69. package/web-dist/assets/{highlighter.worker-D6D9fPma.js → highlighter.worker-CKF6ok1g.js} +1 -1
  70. package/web-dist/assets/index-BUvJ5Ctt.js +1299 -0
  71. package/web-dist/assets/index-DRj7nvPY.css +1 -0
  72. package/web-dist/assets/{infoDiagram-27XIBGKW-Cdo6Ar-a.js → infoDiagram-27XIBGKW-DNfTEPAV.js} +1 -1
  73. package/web-dist/assets/{ishikawaDiagram-5VMMS53U-C27pgect.js → ishikawaDiagram-5VMMS53U-B7aCjjG1.js} +1 -1
  74. package/web-dist/assets/{journeyDiagram-3NMN7TZE-CVxtKpLG.js → journeyDiagram-3NMN7TZE-COmDALVr.js} +1 -1
  75. package/web-dist/assets/{kanban-definition-UXKFOSKX-DWA31Da7.js → kanban-definition-UXKFOSKX-BzUfPINh.js} +1 -1
  76. package/web-dist/assets/{layout-DWKCU9PO.js → layout-BwzuPU4M.js} +1 -1
  77. package/web-dist/assets/{linear-BwCthj_k.js → linear-WPZTYjz3.js} +1 -1
  78. package/web-dist/assets/mermaid.core-zKzlwpkw.js +310 -0
  79. package/web-dist/assets/{mindmap-definition-YA3MSWOX-BLEDhbn1.js → mindmap-definition-YA3MSWOX-DCRg7eAx.js} +1 -1
  80. package/web-dist/assets/{pegDiagram-XKGWAZYB-CLEM1SDU.js → pegDiagram-XKGWAZYB-DyphzDLU.js} +1 -1
  81. package/web-dist/assets/{pieDiagram-E7YTZNPT-B__g6eF0.js → pieDiagram-E7YTZNPT-BI5DueGA.js} +1 -1
  82. package/web-dist/assets/powershell-DXrKVo3G.js +1 -0
  83. package/web-dist/assets/powershell-Dpen1YoG.js +1 -0
  84. package/web-dist/assets/{quadrantDiagram-AXDQQJYC-C7VQ2LMY.js → quadrantDiagram-AXDQQJYC-GZxSMY2Z.js} +1 -1
  85. package/web-dist/assets/{railroadDiagram-O6MQD6OU-eWNnzjwS.js → railroadDiagram-O6MQD6OU-DEFCigBf.js} +1 -1
  86. package/web-dist/assets/{requirementDiagram-BXWQKSXE-Bi5qeD4b.js → requirementDiagram-BXWQKSXE-Br0thc4j.js} +1 -1
  87. package/web-dist/assets/{sankeyDiagram-P5KCCOFB-DG1VOpXX.js → sankeyDiagram-P5KCCOFB-DYf0pY67.js} +1 -1
  88. package/web-dist/assets/{sequenceDiagram-WJ2MYXX4-Fhkw73Th.js → sequenceDiagram-WJ2MYXX4-1EFMboX4.js} +1 -1
  89. package/web-dist/assets/{sizeCapture-INFHLROL-D9E_17SF.js → sizeCapture-INFHLROL-BuOFv-5q.js} +1 -1
  90. package/web-dist/assets/{stateDiagram-D77RDMKH-Cs5Y0xhW.js → stateDiagram-D77RDMKH-Bg3H1tjX.js} +1 -1
  91. package/web-dist/assets/stateDiagram-v2-MP3YSRHH-DfaDaPAd.js +1 -0
  92. package/web-dist/assets/{swimlanes-42K2YHIH-t-EocvKZ.js → swimlanes-42K2YHIH-BuOa6Osb.js} +1 -1
  93. package/web-dist/assets/swimlanesDiagram-VR7AAH4N-BopAC7b8.js +8 -0
  94. package/web-dist/assets/{timeline-definition-24CTP7MA-CozGCxuA.js → timeline-definition-24CTP7MA-BDekfdDT.js} +1 -1
  95. package/web-dist/assets/{vennDiagram-4TSXK5OY-ewU8ycSa.js → vennDiagram-4TSXK5OY-DnC09UI4.js} +1 -1
  96. package/web-dist/assets/{wardleyDiagram-VM6X3IG4-DuAhDu-0.js → wardleyDiagram-VM6X3IG4-BXKvxuZQ.js} +1 -1
  97. package/web-dist/assets/{xterm-v5e56GC9.js → xterm-oY4DYg5s.js} +1 -1
  98. package/web-dist/assets/{xychartDiagram-S5SC5T6Z-BxGuZO23.js → xychartDiagram-S5SC5T6Z-DdDC1VLb.js} +1 -1
  99. package/web-dist/index.html +12 -6
  100. package/web-dist/{workflow-ui.css → workbench-ui.css} +72 -67
  101. package/dist/benchmark-package.d.ts +0 -39
  102. package/dist/benchmark-package.js +0 -97
  103. package/dist/benchmark-package.js.map +0 -1
  104. package/dist/chunk-54E64LWB.js +0 -63
  105. package/dist/chunk-54E64LWB.js.map +0 -1
  106. package/dist/chunk-5Z4UCHDB.js.map +0 -1
  107. package/dist/chunk-HMTT2PX4.js.map +0 -1
  108. package/dist/chunk-JKJXQTHH.js +0 -19
  109. package/dist/chunk-JKJXQTHH.js.map +0 -1
  110. package/dist/chunk-LPPVGHYD.js.map +0 -1
  111. package/dist/chunk-NVWAYYRX.js.map +0 -1
  112. package/dist/chunk-Q4ON2L6E.js +0 -52
  113. package/dist/chunk-Q4ON2L6E.js.map +0 -1
  114. package/dist/chunk-TOOTEEM4.js.map +0 -1
  115. package/web-dist/assets/channel--PblgLlC.js +0 -1
  116. package/web-dist/assets/classDiagram-ZZMXUADV-mn8tbuqa.js +0 -1
  117. package/web-dist/assets/classDiagram-v2-VYDZK3BY-mn8tbuqa.js +0 -1
  118. package/web-dist/assets/highlighter-CzfXQ6yd.js +0 -2
  119. package/web-dist/assets/index-BdG4qRyI.js +0 -1275
  120. package/web-dist/assets/index-W-xYFoIm.css +0 -1
  121. package/web-dist/assets/mermaid.core-BcTrmPOv.js +0 -310
  122. package/web-dist/assets/stateDiagram-v2-MP3YSRHH-CEM51fAf.js +0 -1
  123. package/web-dist/assets/swimlanesDiagram-VR7AAH4N-BrR66vrK.js +0 -8
  124. /package/dist/{chunk-QFV3ERQO.js.map → chunk-OQZDL3TR.js.map} +0 -0
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  MachinesRepo
3
- } from "./chunk-HMTT2PX4.js";
3
+ } from "./chunk-2LZDP26O.js";
4
4
  import {
5
5
  liveServerLock
6
6
  } from "./chunk-GOO5VUAB.js";
7
7
  import {
8
8
  openDatabaseReadOnly
9
- } from "./chunk-NVWAYYRX.js";
9
+ } from "./chunk-HPOHMZCH.js";
10
10
  import "./chunk-B5IP37ZQ.js";
11
11
 
12
12
  // src/machine-status.ts
@@ -0,0 +1,610 @@
1
+ import { ModelPricing, ModelRef, ProviderTable, ModelEntry } from '@prismshadow/penguin-core';
2
+ import { ModelCredentialShape, ProviderConnectionShape } from '@prismshadow/penguin-core/model-connection';
3
+ export { routedClientType } from '@prismshadow/mmsp/credentials';
4
+
5
+ /** Model provider info (used for web grouping/logo and the "API key blank falls back to env var" hint). */
6
+ /**
7
+ * A provider that mints API keys through an authorization page instead of a console visit.
8
+ * Present only on providers that publish such a flow; its absence is what makes the harness
9
+ * refuse to start one.
10
+ */
11
+ interface ModelProviderOAuth {
12
+ /** Authorization page the user is sent to; the flow's parameters ride on its query string. */
13
+ authorizeUrl: string;
14
+ /** Endpoint that trades an authorization code for a newly minted key. */
15
+ exchangeUrl: string;
16
+ /** Name recorded on the minted key, and the app name the authorization page displays. */
17
+ keyName: string;
18
+ }
19
+ /**
20
+ * A group whose credential the App obtains through its own authorization flow rather than by
21
+ * asking the vendor: the client registers a one-time code and device secret with an external
22
+ * bridge, sends the user to the page that bridge hands back, and polls until the bridge
23
+ * delivers the credential. Distinct from `oauth`, where the App itself speaks the vendor's
24
+ * PKCE page — here the App never reaches the vendor at all, because the bridge holds the
25
+ * client secret that conversation would need.
26
+ *
27
+ * The bridge's own address is deliberately NOT here: this file is bundled for the browser and
28
+ * cannot read configuration, so the App resolves the bridge server-side from its environment
29
+ * (PENGUIN_GO_ORIGIN / MODELSCOPE_BRIDGE_URL), keyed by the group's id.
30
+ */
31
+ interface ModelProviderBridgeAuth {
32
+ /**
33
+ * Which App-side flow serves this group — one route family and one service per value, so
34
+ * the Web App picks from the group's descriptor rather than from its id.
35
+ */
36
+ flow: "penguin-go" | "modelscope";
37
+ }
38
+ /**
39
+ * An account-balance endpoint the vendor publishes, called with the group's own API key as a
40
+ * Bearer token. The server makes that call (the key never reaches the browser); the endpoint
41
+ * is the vendor's, like the OAuth one above, so it can live in this browser-bundled file.
42
+ */
43
+ interface ModelProviderBalance {
44
+ /** GET endpoint answering the balance of the account the key belongs to. */
45
+ url: string;
46
+ /**
47
+ * How to read the answer, one reader per published response shape:
48
+ * - `tokendance`: `{ balance: { credits, credits_used, balance } }`, integers in micro-yuan
49
+ * (1 CNY = 1,000,000);
50
+ * - `deepseek`: `{ is_available, balance_infos: [{ currency, total_balance, … }] }`, one entry
51
+ * per currency the account holds.
52
+ * - `penguin-go`: `{ balance: { units, currency } }`, a CNY ledger integer in 10^-12 yuan.
53
+ */
54
+ format: "tokendance" | "deepseek" | "penguin-go";
55
+ }
56
+ interface ModelProviderInfo {
57
+ id: string;
58
+ /** Display name (brand name, shared by Chinese and English UI). */
59
+ label: string;
60
+ /**
61
+ * API key env var name: the variable MMSP's client for this group's rows reads when handed no
62
+ * key, which it does only for its own default endpoint (PRN-021, MMSP's rule). A gateway group
63
+ * records OPENAI_* because that is what its generic client reads, and its rows carry the
64
+ * gateway's base URL, so that client never reads it for them.
65
+ */
66
+ envKey: string;
67
+ /** base URL env var name. */
68
+ envBaseUrlKey: string;
69
+ /** Console URL for obtaining an API key (frontend links it beside the API key field of the group key dialog and the model dialog); none for custom. */
70
+ apiKeyUrl?: string;
71
+ /** Vendor's model list / docs page URL (frontend's "add model" dialog links this as "get model id"); none for custom. */
72
+ modelsUrl?: string;
73
+ /**
74
+ * Gateway's OpenAI-compatible endpoint (openrouter / siliconflow / qwen-token-plan / …): what
75
+ * a new Project writes as the group's `[providers.<id>]` base URL (catalogGroupConnection),
76
+ * so every row of the group — a model added by hand included — follows it without storing
77
+ * the address itself. A reference value: nothing reads it when a request is built. Left
78
+ * blank for direct vendors, custom and vLLM (whose rows name the local server's address).
79
+ */
80
+ gatewayBaseUrl?: string;
81
+ /**
82
+ * Authorization flow that mints a key for the user (see ModelProviderOAuth); absent for
83
+ * every provider whose keys are only obtainable from its console.
84
+ */
85
+ oauth?: ModelProviderOAuth;
86
+ /**
87
+ * The App-side authorization flow that obtains this group's credential (see
88
+ * ModelProviderBridgeAuth); absent for every group whose credential comes from a console or
89
+ * from the vendor's own page. Declaring it is what puts the "authorize a key" action on the
90
+ * group in the Web App.
91
+ */
92
+ bridgeAuth?: ModelProviderBridgeAuth;
93
+ /**
94
+ * The vendor's account-balance endpoint (see ModelProviderBalance); absent for every group
95
+ * whose vendor publishes none. Declaring it is what puts the balance in the group's header.
96
+ */
97
+ balance?: ModelProviderBalance;
98
+ /**
99
+ * The group takes models the user adds by hand: `custom` and vLLM, whose rows point at an
100
+ * endpoint the catalog cannot know, and the four gateways whose catalogs list a fraction of
101
+ * what they serve — OpenRouter, TokenDance, SiliconFlow and Atlas Cloud — where an added
102
+ * model follows the group's connection (its endpoint, key and protocol) exactly as the
103
+ * presets do. Every other built-in group carries its catalog presets and the rows it already
104
+ * stores, and nothing else. Read it through isAddableGroup, which also answers for
105
+ * user-defined groups.
106
+ */
107
+ addable?: boolean;
108
+ /**
109
+ * The MMSP protocol EVERY entry in this group speaks, models the user adds included.
110
+ *
111
+ * Set it where the group itself decides the answer for a row the catalog does not list:
112
+ * every group that takes hand-added models and speaks one protocol (vLLM, OpenRouter,
113
+ * TokenDance, SiliconFlow, Atlas Cloud). The other gateways hold catalog rows only, each
114
+ * carrying its own pin, and `custom` / user-defined groups deliberately declare nothing —
115
+ * their whole point is that the protocol is detected from the endpoint or picked by hand,
116
+ * and a pin here would take that choice away.
117
+ *
118
+ * Where it IS set, a new Project writes it as the group's `[providers.<id>]` protocol
119
+ * (catalogGroupConnection), and the rows — models added by hand included — follow that
120
+ * table. A reference value like gatewayBaseUrl: what the app reads at runtime is the file's
121
+ * table. Read it through providerClientType rather than reaching for the field.
122
+ */
123
+ clientType?: string;
124
+ /**
125
+ * The group the product recommends, captioned as such on the models page. It marks the
126
+ * GROUP, not a position: a user who drags the group elsewhere keeps the caption with it,
127
+ * and the default sequence below is what places it first for everyone else.
128
+ */
129
+ recommended?: boolean;
130
+ }
131
+ /** A single built-in model's catalog entry (`modelId` is the upstream id; paired with `provider` it forms the catalog's unique key). */
132
+ interface ModelCatalogEntry {
133
+ modelId: string;
134
+ displayName: string;
135
+ /** Provider id (one of MODEL_PROVIDERS). */
136
+ provider: string;
137
+ contextWindow?: number;
138
+ pricing?: ModelPricing;
139
+ /**
140
+ * Fraction off the list price the seller is currently running (0.5 = 50% off), applied to
141
+ * every bucket. `pricing` stays the LIST price whatever promotion is live, so a lapsed
142
+ * promotion is one field to delete rather than three numbers to reconstruct;
143
+ * effectivePricing is the rate actually billed. A Project stores the list price too: the
144
+ * fraction is seeded beside it as a promotion (presetPromotions), which the cost center
145
+ * applies when it prices usage, so it charges what the seller charges.
146
+ */
147
+ discount?: number;
148
+ /**
149
+ * A discount that is only live outside a weekly set of peak windows — a vendor billing
150
+ * cheaper off-hours. `pricing` holds the PEAK price, the one billed inside the windows, and
151
+ * the rate applies everywhere else.
152
+ *
153
+ * Like `discount`, this one is never baked into a Project, and here there is no choice: it
154
+ * changes twice a day. `presetModelEntries` writes the peak price and the rate is applied
155
+ * when a price is read.
156
+ * A number on disk that silently meant something different at 09:00 than at 08:00 would be
157
+ * unreadable, and re-syncing presets would rewrite prices by the clock. A seller that also
158
+ * takes something off on top of the schedule, in both tiers, declares it in `discount`: it is
159
+ * seeded like any promotion, and the two multiply, as a Project's promotion and schedule do
160
+ * wherever a price is read.
161
+ */
162
+ offPeakDiscount?: OffPeakDiscount;
163
+ /** Whether image input (vision modality) is supported. */
164
+ supportsVision: boolean;
165
+ /** MMSP client type: required when an id cannot be auto-routed or a shared protocol must be pinned. */
166
+ clientType?: string;
167
+ /**
168
+ * Preset base URL, so only an API key is required. A new Project stores it once: on the
169
+ * group's `[providers.<id>]` table when it is the group's endpoint (catalogGroupConnection),
170
+ * else on the row itself (catalogModelEntry). Never read when a request is built.
171
+ */
172
+ baseUrl?: string;
173
+ /**
174
+ * No longer a preset (superseded or withdrawn), but saved Projects still carry it: a
175
+ * row a Project has is never deleted by "Add new models", and several of these were the
176
+ * default model of new Projects. A retired row is not a preset — `presetModelEntries` and
177
+ * `presetPromotions` skip it, so a new Project never gets it or a promotion for it, a sync
178
+ * never adds it, and "Restore defaults" deletes it with every other row that is not a preset —
179
+ * but it is still in `catalogModelEntries`, and lookups by `(provider, modelId)` still find
180
+ * it. Projects carrying it keep its display name and vision flag, and their usage on it is
181
+ * priced on its off-peak schedule whenever the row stores the catalog's price: the tier only
182
+ * applies to that price. The schedule is the part that matters: cost is priced when it is
183
+ * read, so deleting a scheduled row would reprice every off-peak record already on those
184
+ * Projects at the peak rate.
185
+ *
186
+ * Compatibility, not catalog data: remove a retired row only after its seller has stopped
187
+ * accepting the id AND the release notes have told users that usage recorded on it will be
188
+ * priced without its schedule from then on. Whoever does the catalog refresh that finds the
189
+ * id rejected makes that call.
190
+ */
191
+ retired?: true;
192
+ /**
193
+ * This row is, or once was, the default model of new Projects (PRESET_DEFAULT_MODEL). Usage
194
+ * recorded on it stays priced after a Project stops storing the row — "Restore defaults"
195
+ * deletes every row that is not a preset, retired ones included, and a former default is
196
+ * often most of an older Project's history: retainedCatalogPricing gives the cost path this
197
+ * row's `pricing` for it. Moving the default sets this on the new row and leaves it on the
198
+ * old one, which also keeps the old row in the catalog (retired once it stops being a preset)
199
+ * for as long as anyone may have recorded usage on it.
200
+ */
201
+ wasDefault?: true;
202
+ }
203
+ declare const PENGUIN_GO_BASE_URL = "https://go.penguin.ooo/api/v1";
204
+ /** Provider id for the preconfigured Penguin Go relay group. */
205
+ declare const PENGUIN_GO_PROVIDER_ID = "penguin-go";
206
+ /**
207
+ * The protocol a group is fixed to, or undefined where the group's protocol is the user's to
208
+ * choose. Penguin Go's platform endpoint speaks MMSP alone, so neither its group nor its rows
209
+ * offer a protocol: the Web App shows MMSP without a picker, and the server's model writes and
210
+ * the CLI refuse any other value (fixedClientTypeRefuses).
211
+ */
212
+ declare function fixedClientType(providerId: string): string | undefined;
213
+ /**
214
+ * Whether writing `next` as the protocol of a group (`target: "group"`) or of one of its rows
215
+ * (`"row"`) is refused because the group's protocol is fixed (fixedClientType). `next` is the
216
+ * value written, blank or absent for none; `stored` is what that group, or that same row in that
217
+ * same group, stores now.
218
+ *
219
+ * The fixed protocol is always accepted, and so is `stored` written back unchanged: a row a user
220
+ * pointed at their own proxy on another protocol before the protocol was fixed (left alone by
221
+ * migratePenguinGoRoutes) keeps it, and a whole-table save carrying it is not refused. A row
222
+ * with no protocol of its own follows its group, so clearing a row's is accepted; clearing the
223
+ * group's would leave its rows routed by model id, and is refused.
224
+ */
225
+ declare function fixedClientTypeRefuses(providerId: string, target: "group" | "row", next: string | null | undefined, stored: string | undefined): boolean;
226
+ /** Provider id for the ModelScope group. */
227
+ declare const MODELSCOPE_PROVIDER_ID = "modelscope";
228
+ /**
229
+ * Provider list (web model page groups in this order BY DEFAULT — a user's dragged
230
+ * arrangement is stored per Project and wins over this sequence; see the web's
231
+ * model-group-order.ts). The sequence is a hand-curated display order: TokenDance leads as
232
+ * the recommended group, Penguin Go follows, then OpenCode Go, then DeepSeek as the default
233
+ * model's provider, and custom
234
+ * (custom OpenAI-protocol models) is always last; in between, gateways and first-party
235
+ * vendors are interleaved by expected use rather than sorted by kind. Only this default
236
+ * moves when the curation changes: a Project that has ever reordered its groups has every
237
+ * key stored already, so it keeps the arrangement its user built.
238
+ *
239
+ * The eight gateway groups — OpenRouter, Fireworks AI, SiliconFlow, Atlas Cloud, TokenDance,
240
+ * OpenCode Go, Qwen Pay-As-You-Go and Qwen Token Plan — reach their models through MMSP's generic
241
+ * protocol clients (`openai-responses` for OpenRouter, `openai-chat` for the rest, and all
242
+ * three generic clients within OpenCode Go). Those clients read the vendor variables
243
+ * (**OPENAI_API_KEY / OPENAI_BASE_URL**, and ANTHROPIC_* for OpenCode Go's `ant-messages`
244
+ * rows) when the credential is blank, not the gateway's own variable names, so every gateway
245
+ * group records the OPENAI_* pair as the fact it is. A new Project writes each gateway's base
246
+ * URL on its group, so MMSP refuses a keyless gateway row rather than reading a variable: the
247
+ * variable holds the user's OpenAI (or Anthropic) key, and a gateway is neither. ModelScope
248
+ * also records the OPENAI_* pair; its group credential is an api-inference access token taken
249
+ * from the config alone.
250
+ */
251
+ declare const MODEL_PROVIDERS: ModelProviderInfo[];
252
+ /**
253
+ * A weekly peak/off-peak billing schedule, written in a fixed-offset zone.
254
+ *
255
+ * Only fixed offsets are expressible, which is the whole of what the catalog needs: the vendors
256
+ * that bill this way publish their windows in a single national zone that does not observe DST
257
+ * (Beijing is UTC+8 year round). A vendor on a DST zone would need a real tz database, and the
258
+ * honest move then is to add one rather than to approximate.
259
+ */
260
+ interface OffPeakDiscount {
261
+ /** Fraction off the peak price outside the windows below (0.5 = half price). */
262
+ rate: number;
263
+ /** Minutes east of UTC the windows are written in (Beijing = 480). */
264
+ utcOffsetMinutes: number;
265
+ /** Days the windows apply to, ISO numbering: 1 = Monday … 7 = Sunday. Days not listed are off-peak all day. */
266
+ peakDays: readonly number[];
267
+ /** Peak windows as [startHour, endHour) in the zone's local hours — end-exclusive, so 12:00 is already off-peak. */
268
+ peakHours: readonly (readonly [number, number])[];
269
+ }
270
+ /**
271
+ * Whether `now` falls outside every peak window, i.e. whether the discount is live.
272
+ *
273
+ * Computed in UTC arithmetic rather than through the host's local time: the schedule belongs to
274
+ * the vendor's zone, and a server in Los Angeles must reach the same answer as one in Shanghai.
275
+ */
276
+ declare function offPeakAt(schedule: OffPeakDiscount, now: Date): boolean;
277
+ /** DeepSeek's official off-peak tier: half price outside Beijing weekday 09:00–12:00 and 14:00–18:00. */
278
+ declare const DEEPSEEK_OFF_PEAK: OffPeakDiscount;
279
+ /**
280
+ * Qwen's off-peak tier on the time-banded models it sells (www.qianwenai.com/models/<id>, read
281
+ * 2026-09-16): half price from 22:00 to 08:00 Beijing time, every day of the week, and the peak
282
+ * price at every other hour. Each model page shows the two tiers as separate price tabs, and
283
+ * every bucket's off-peak figure is exactly half its peak one.
284
+ */
285
+ declare const QWEN_OFF_PEAK: OffPeakDiscount;
286
+ /**
287
+ * The catalog's time-based schedules, each with the references that carry it.
288
+ *
289
+ * The cost center needs this to split an aggregation by tier before it prices anything: the
290
+ * rate a request ran at is a fact about when it ran, and only the catalog knows which rows have
291
+ * two rates at all. Grouped by schedule so a second vendor's windows cost one entry, not a
292
+ * second query.
293
+ */
294
+ declare function offPeakScheduledRefs(): Array<{
295
+ schedule: OffPeakDiscount;
296
+ refs: Array<{
297
+ provider: string;
298
+ modelId: string;
299
+ }>;
300
+ }>;
301
+ /**
302
+ * What the seller actually bills for an entry at `now`: its list `pricing` less any running
303
+ * `discount` and any live off-peak tier, the two multiplied, on every bucket. Rounded to the six
304
+ * decimals cny() already stores at, so a promotional rate reads as a price rather than as a
305
+ * float artifact. An entry with nothing off (or no pricing at all) is returned untouched.
306
+ *
307
+ * Nothing writes this rate into a Project: `presetModelEntries` writes the list price (a
308
+ * scheduled row's peak price), a flat promotion is stored beside it as a fraction, and which
309
+ * tier a request ran in is decided from that request's own timestamp when the usage is
310
+ * aggregated.
311
+ */
312
+ declare function effectivePricing(entry: ModelCatalogEntry, now?: Date): ModelPricing | undefined;
313
+ /**
314
+ * Built-in model catalog, clustered by provider. Within each provider, entries are in
315
+ * dictionary order by model id, except that newer versions of the same series come first
316
+ * (e.g. gpt-5.6-* before gpt-5.5, claude-opus-4.8 before 4.7, glm-5.2 before glm-5). The
317
+ * order is precomputed by hand right here — no runtime sorting anywhere.
318
+ *
319
+ * The clusters run in their own sequence, which is the row order a new Project's
320
+ * `[[models]]` table is written in. It is not MODEL_PROVIDERS' display order and does not
321
+ * have to track it: nothing renders a catalog row outside its provider group, and the page
322
+ * takes the group sequence from MODEL_PROVIDERS.
323
+ */
324
+ declare const MODEL_CATALOG: ModelCatalogEntry[];
325
+ /** Looks up a catalog entry by (provider, upstream id) pair (**the sole catalog-matching entry point**); returns undefined if not in the catalog. */
326
+ declare function catalogEntryFor(provider: string, upstreamId: string): ModelCatalogEntry | undefined;
327
+ /** Looks up provider info by provider id; returns undefined for an unknown id. */
328
+ declare function providerInfo(providerId: string): ModelProviderInfo | undefined;
329
+ /**
330
+ * The protocol a group pins on every one of its entries (ModelProviderInfo.clientType), or
331
+ * undefined when the group pins none — an unknown id (a user-defined group) included.
332
+ *
333
+ * Five groups pin: vLLM, whose models are served by the user's own vLLM adapter,
334
+ * OpenRouter, whose models all speak the Responses API OpenRouter serves at its preset base
335
+ * URL, and TokenDance, SiliconFlow and Atlas Cloud, whose models all speak Chat Completions.
336
+ *
337
+ * A reference value, read when a file is written from the catalog (catalogGroupConnection:
338
+ * a new Project, "Add new models" for a group new to the file, "Restore defaults") and by
339
+ * nothing that builds or judges a request: at runtime a group's protocol is its
340
+ * `[providers.<id>]` table's.
341
+ */
342
+ declare function providerClientType(providerId: string): string | undefined;
343
+ /**
344
+ * A first-party vendor group: one this catalog knows, that is not `custom`, carries no
345
+ * gateway endpoint and pins no protocol of its own — DeepSeek, Google, OpenAI, Anthropic,
346
+ * Z.AI, Moonshot, MiniMax, and the Penguin Go relay.
347
+ *
348
+ * What distinguishes it is that nothing in it decides a protocol: its entries persist no
349
+ * `client_type`, so MMSP places every one of them by the spelling of the upstream model
350
+ * id alone — the vendor family it begins with. An id of no known family cannot be started at
351
+ * all, whatever else is configured on the entry (the Penguin Go rows pin their protocol
352
+ * instead: the relay serves Gemini through generateContent, not the API a `gemini-` id routes
353
+ * to). Every
354
+ * surface that has to answer "is this one routable?" reads the group's shape through this one
355
+ * predicate rather than re-deriving it: the models page's cards and its config dialog, the
356
+ * models PUT, and the CLI's `config model add`. Whether a model may be added to the group at
357
+ * all is a separate, wider rule: isAddableGroup.
358
+ *
359
+ * Every other group answers the protocol question by itself and therefore routes any id the
360
+ * endpoint serves: `custom` and user-defined groups detect or pick it, and a gateway's or
361
+ * vLLM's rows speak the protocol their group's `[providers.<id>]` table or the row itself
362
+ * stores (a new Project writes it there).
363
+ */
364
+ declare function isVendorGroup(providerId: string): boolean;
365
+ /**
366
+ * Whether this entry would be written into a vendor group with an id MMSP cannot place —
367
+ * the configuration that produces `No client for model "<id>": its family is not known` on
368
+ * the first request, and nothing before it.
369
+ *
370
+ * MMSP's `routedClientType` is the authority: AutoLLMClient routes through it, and it returns
371
+ * null on exactly the entries that client rejects. A blank id is not a routing failure — the
372
+ * entry is still being typed, and the required-field validation is what has something to say
373
+ * about it.
374
+ */
375
+ declare function unroutableVendorModel(provider: string, modelId: string, clientType?: string): boolean;
376
+ /**
377
+ * The official MMSP client a first-party vendor group's unpinned rows route to: the vendor's
378
+ * own, the official client that reads the variable the group records (`envKey`; MMSP's
379
+ * credentials module). Undefined for every other group, whose protocol its table or its rows
380
+ * decide.
381
+ */
382
+ declare function vendorClientType(providerId: string): string | undefined;
383
+ /**
384
+ * Whether models may be added to this group by hand: `custom`, vLLM, OpenRouter, TokenDance,
385
+ * SiliconFlow, Atlas Cloud (ModelProviderInfo.addable) and every user-defined group, i.e. an
386
+ * id this catalog does not know. Every other built-in group — the first-party vendors and the
387
+ * other gateways — carries its catalog presets and the rows it already stores: the models page
388
+ * offers no add-model entry point there, and the models PUT and the CLI's `config model add`
389
+ * refuse a new row that is not a preset (unaddableModel).
390
+ */
391
+ declare function isAddableGroup(providerId: string): boolean;
392
+ /**
393
+ * Whether writing this pair as a NEW row of its group would add a model by hand where the group
394
+ * takes none: a group isAddableGroup refuses, and a `(provider, model_id)` pair that is not one
395
+ * of the catalog's rows for it. A preset passes, so "Sync presets" can put a deleted one back;
396
+ * a row the table already stores is not a new one, and the callers never ask about it.
397
+ */
398
+ declare function unaddableModel(provider: string, modelId: string): boolean;
399
+ /**
400
+ * The price usage on a model is costed at when the Project no longer stores the model's row:
401
+ * the catalog's list `pricing` of a row that is or was the default of new Projects
402
+ * (ModelCatalogEntry.wasDefault), and undefined for every other pair — a row the Project does
403
+ * store is priced from the file, never from here. No promotion applies: a Project's promotion
404
+ * goes with its row. An off-peak schedule still does, since this is the catalog's own peak price.
405
+ */
406
+ declare function retainedCatalogPricing(provider: string, modelId: string): ModelPricing | undefined;
407
+ /**
408
+ * The model's own homepage/detail page for the frontend's model-card link. Gateway groups
409
+ * have a stable per-model URL pattern (works for user-added ids in those groups too);
410
+ * direct-vendor models link to the vendor's model list/docs page; custom and user-defined
411
+ * groups have no page to vouch for.
412
+ */
413
+ declare function modelHomepageUrl(provider: string, modelId: string): string | undefined;
414
+
415
+ /**
416
+ * The wire protocol that carries MMSP's `fast_mode` on a client: `"openai"` for the clients
417
+ * that send `service_tier: "priority"` (the OpenAI protocols, and Google's Interactions API
418
+ * and MiniMax alike), `"anthropic"` for those that send `speed: "fast"` plus the
419
+ * `fast-mode-2026-02-01` beta header. The two differ in what the user must be warned about,
420
+ * not just in wire shape.
421
+ */
422
+ type FastModeProtocol = "openai" | "anthropic";
423
+ /**
424
+ * What the UI shows about each MMSP client, which MMSP exports nothing for: the path it appends
425
+ * to its base URL (the models page's endpoint hint) and the protocol that carries `fast_mode`
426
+ * (absent = the client rejects it, or the harness cannot tell what it does with it). Keyed by
427
+ * the canonical client type MMSP's routedClientType returns; the catalog test holds it to the
428
+ * client types MMSP's credentials module knows.
429
+ */
430
+ declare const CLIENT_PROTOCOLS: Readonly<Record<string, {
431
+ path: string;
432
+ fastMode?: FastModeProtocol;
433
+ }>>;
434
+ /**
435
+ * Whether a model can carry fast mode at all, and on which protocol - `undefined` means no.
436
+ *
437
+ * The fast tier is a property of the **client MMSP routes to** (MMSP's routedClientType), never of
438
+ * the catalog row: the registry carries no fast-tier capability flag, but the routing is
439
+ * deterministic, so the answer is too. This reports what the selected client does with the
440
+ * parameter:
441
+ *
442
+ * - maps it -> the protocol, and the toggle may be offered;
443
+ * - raises UnsupportedParameterError (the Z.AI, Moonshot, DeepSeek, google-genai and
444
+ * embedding clients, and anthropic-official on Bedrock or for the generations that reject
445
+ * the `speed` parameter) -> `undefined`;
446
+ * - forwards it to an MMSP server, whose upstream client decides what it does with it (mmsp)
447
+ * -> `undefined`: the harness cannot say on which protocol, or whether at all;
448
+ * - routes nowhere (AutoLLMClient throws for an id it cannot place) -> `undefined` as well,
449
+ * since a model that cannot run has no fast tier either.
450
+ *
451
+ * A rule rather than a per-model list on purpose: catalog rows added later inherit the right
452
+ * answer without anyone remembering to update a table.
453
+ *
454
+ * `"anthropic"` is reported for every Claude the client serves, including ids outside the
455
+ * research preview's Opus allowlist: Anthropic answers those with a 429 at request time, which
456
+ * is something to warn about before enabling, not grounds to hide the setting.
457
+ *
458
+ * Two runtime inputs stay invisible to a pure function of the config and can still flip the
459
+ * answer: the server's `CLIENT_TYPE` env var names the client for an entry that pins none, and
460
+ * `ANTHROPIC_BASE_URL` supplies the base URL when the entry leaves it blank (so a `bedrock://`
461
+ * there sends Claude to Bedrock, which has no fast tier). Third-party OpenAI-compatible
462
+ * endpoints are a third: they accept `service_tier` and may quietly serve the standard tier.
463
+ * That residue is why llm/generative-model.ts still handles the rejection at runtime.
464
+ */
465
+ declare function fastModeProtocol(modelId: string, clientType?: string, baseUrl?: string): FastModeProtocol | undefined;
466
+
467
+ /**
468
+ * The variable MMSP's client of this type reads its key from when handed none at this base URL
469
+ * (environmentCredential), or undefined: the client refuses that URL, calls it keyless, or is
470
+ * not one MMSP has. With no base URL it is always the client's own `*_API_KEY`.
471
+ */
472
+ declare function clientEnvKey(clientType: string, baseUrl: string | undefined): string | undefined;
473
+ /** The variables MMSP's routed client reads for a row as configured (see modelEnvironment). */
474
+ interface ModelEnvironment {
475
+ /** The key's variable: only for a row with no key in the file. */
476
+ apiKeyEnv?: string;
477
+ /** The endpoint's variable: only for a row with no base URL in the file. */
478
+ baseUrlEnv?: string;
479
+ /**
480
+ * Where that row's requests go while `baseUrlEnv` is unset: the routed client's default
481
+ * endpoint, as MMSP's credentials table records it. Present exactly when `baseUrlEnv` is.
482
+ */
483
+ defaultBaseUrl?: string;
484
+ }
485
+ /**
486
+ * What a row takes from the environment, as MMSP decides it (PRN-021). The row's effective
487
+ * connection (core's effectiveConnection) picks the client MMSP routes it to (`routedClientType`)
488
+ * and the base URL that client is handed; `environmentCredential` then says what the client
489
+ * reads. With no key in the file it reads its `*_API_KEY` only for no base URL or its own default
490
+ * endpoint, and with no base URL in the file it goes where its `*_BASE_URL` points, key or not.
491
+ * A row MMSP refuses (no key and another base URL), an open MMSP server and a row nothing routes
492
+ * read nothing. With no base URL in the file the row also names the endpoint its requests go to
493
+ * while that variable is unset (`defaultBaseUrl`). `entry` is the row's OWN values, key
494
+ * included, and `group` its `[providers.<id>]` table.
495
+ */
496
+ declare function modelEnvironment(entry: ModelCredentialShape & {
497
+ apiKey?: string | undefined;
498
+ }, group: ProviderConnectionShape | undefined): ModelEnvironment;
499
+ /**
500
+ * The variable a row with no key in the file authenticates with, or undefined: modelEnvironment's
501
+ * `apiKeyEnv`. The server's `GET /models` preview, the web dialog's hint and the CLI's list read
502
+ * this, so none of them can disagree with what a Session does.
503
+ */
504
+ declare function modelEnvPreviewKey(entry: ModelCredentialShape & {
505
+ apiKey?: string | undefined;
506
+ }, group: ProviderConnectionShape | undefined): string | undefined;
507
+ /**
508
+ * The variable a group's settings may present as covering a blank group key, or undefined —
509
+ * the group dialog's hint: what MMSP's client for the group (groupClientType) reads when handed
510
+ * no key at the group's base URL (clientEnvKey). A group with no one client names nothing.
511
+ */
512
+ declare function providerEnvFallbackKey(providerId: string, group: Pick<ProviderConnectionShape, "baseUrl" | "clientType"> | undefined): string | undefined;
513
+ /**
514
+ * Whether a group with no key, and its client's variable unset, has its rows called without a
515
+ * key — the group dialog's "send no key" hint: MMSP's client for the group (groupClientType) at
516
+ * the group's base URL calls it keyless (calledKeyless). A group with no one client, and one
517
+ * keyed by a sign-in flow, answers no.
518
+ */
519
+ declare function providerCalledKeyless(providerId: string, group: Pick<ProviderConnectionShape, "baseUrl" | "clientType"> | undefined): boolean;
520
+ /**
521
+ * Whether a row with no key of its own or its group's, and its client's variable unset, is
522
+ * called without a key — the model dialog's "send no key" hint: its routed client at its
523
+ * effective base URL calls it keyless (calledKeyless). A row of a sign-in-keyed group, and one
524
+ * nothing routes, answers no. `entry` is the row's OWN values, and `group` its table.
525
+ */
526
+ declare function modelCalledKeyless(entry: ModelCredentialShape & {
527
+ apiKey?: string | undefined;
528
+ }, group: ProviderConnectionShape | undefined): boolean;
529
+
530
+ /**
531
+ * The catalog as a Project config seeds it: each built-in group's `[providers.<id>]` table, the
532
+ * preset rows (storing a protocol or endpoint only where it differs from the table beside it),
533
+ * the default model and the flat promotions — what the server writes when a Project is created,
534
+ * on "Add new models" and on "Restore defaults". Reference values: nothing reads them when a
535
+ * request is built.
536
+ */
537
+
538
+ /**
539
+ * The connection the catalog gives a built-in group when a file is written from it — a new
540
+ * Project, "Add new models" for a group new to the file, "Restore defaults": its gateway
541
+ * endpoint (`gatewayBaseUrl`, else the one base URL every catalog row of the group carries)
542
+ * and its one protocol (the group's pin, providerClientType, else the one pin every catalog
543
+ * row of the group carries; canonical spelling). Retired rows count: the Projects that still
544
+ * carry one store its difference from the same table.
545
+ *
546
+ * Undefined for `custom` (it holds the user's own endpoints), for an id the catalog does not
547
+ * know, and for a group with neither — the first-party vendors, whose rows go to the
548
+ * client's defaults, so their keyless rows are handed no key and MMSP's client reads the
549
+ * vendor's environment variable (PRN-021). A reference value: nothing reads it when a request
550
+ * is built.
551
+ */
552
+ declare function catalogGroupConnection(providerId: string): {
553
+ base_url?: string;
554
+ client_type?: string;
555
+ } | undefined;
556
+ /**
557
+ * The default model of a new Project: DeepSeek V4.1 Flash, which the vendor serves under the
558
+ * bare name `deepseek-flash` — the current generation of the Flash series, at the same price
559
+ * and schedule as the V4 rows it replaces, and it reads images, so a new Project can take a
560
+ * pasted screenshot without anyone having to notice why it could not. The bare id begins with
561
+ * the `deepseek-` family, so MMSP routes it to DeepSeek's official client without a pin. A
562
+ * Project's default is copied in at creation (the server's seed, and "Restore defaults") and
563
+ * owned by it from then on, so this reaches new Projects alone; an existing one keeps whatever
564
+ * it stored, and "Add new models" never touches the stored default. Its catalog row carries
565
+ * `wasDefault`, as every former default's does.
566
+ */
567
+ declare const PRESET_DEFAULT_MODEL: Readonly<ModelRef>;
568
+ /**
569
+ * `[providers.<id>]` for every built-in group with a catalogGroupConnection, in the catalog's
570
+ * group order — what a new Project's file stores beside presetModelEntries' rows. A fresh
571
+ * object on every call, so a caller may change it.
572
+ */
573
+ declare function presetProviderTable(): ProviderTable;
574
+ /**
575
+ * Catalog -> preset ModelEntry list (what the server seeds a new Project with and what
576
+ * "Add new models" and "Restore defaults" write, avoiding duplicate hand-written copies). `provider` and `model_id` are persisted as
577
+ * separate fields (`model_id` is the plain upstream id). The facts a row stores are the
578
+ * context window, the price and `vision = false`, plus the row's protocol and endpoint where
579
+ * they differ from its group's table in `groups` (catalogModelEntry): beside those tables, the
580
+ * file alone says where every request goes, and nothing is left for a resolver to fill from
581
+ * the catalog. `groups` is the `[providers]` table the rows will sit beside — a new Project's
582
+ * (presetProviderTable, the default), or the file's own when "Add new models" adds rows to an
583
+ * existing Project, so each added row resolves to its catalog connection whatever the user
584
+ * has set on its group. No secrets are included, so only an API key is needed.
585
+ *
586
+ * Pricing is written as the LIST price the catalog records (a scheduled row's PEAK price),
587
+ * never a discounted number. What is on disk then stays true whatever promotion is live and
588
+ * whatever hour the Project is created or re-synced in: a flat promotion is stored beside the
589
+ * file as a per-Project fraction (presetPromotions), and both it and an off-peak tier are
590
+ * applied when the price is read, by the models page and by the cost center alike.
591
+ */
592
+ declare function presetModelEntries(groups?: ProviderTable): ModelEntry[];
593
+ /**
594
+ * Every catalog row as a ModelEntry, retired rows included, in the shape presetModelEntries
595
+ * writes: what a Project carrying a retired row stores for it beside a new Project's group
596
+ * tables (see ModelCatalogEntry.retired). `groups` as in presetModelEntries.
597
+ */
598
+ declare function catalogModelEntries(groups?: ProviderTable): ModelEntry[];
599
+ /**
600
+ * The catalog's flat promotions, as a new Project is seeded with them: every row whose `discount`
601
+ * is a fraction in (0, 1). A retired row is skipped like it is in presetModelEntries: a new
602
+ * Project never carries it, so there is nothing for its promotion to apply to.
603
+ */
604
+ declare function presetPromotions(): Array<{
605
+ provider: string;
606
+ modelId: string;
607
+ discount: number;
608
+ }>;
609
+
610
+ export { CLIENT_PROTOCOLS, DEEPSEEK_OFF_PEAK, type FastModeProtocol, MODELSCOPE_PROVIDER_ID, MODEL_CATALOG, MODEL_PROVIDERS, type ModelCatalogEntry, type ModelEnvironment, type ModelProviderBalance, type ModelProviderBridgeAuth, type ModelProviderInfo, type ModelProviderOAuth, type OffPeakDiscount, PENGUIN_GO_BASE_URL, PENGUIN_GO_PROVIDER_ID, PRESET_DEFAULT_MODEL, QWEN_OFF_PEAK, catalogEntryFor, catalogGroupConnection, catalogModelEntries, clientEnvKey, effectivePricing, fastModeProtocol, fixedClientType, fixedClientTypeRefuses, isAddableGroup, isVendorGroup, modelCalledKeyless, modelEnvPreviewKey, modelEnvironment, modelHomepageUrl, offPeakAt, offPeakScheduledRefs, presetModelEntries, presetPromotions, presetProviderTable, providerCalledKeyless, providerClientType, providerEnvFallbackKey, providerInfo, retainedCatalogPricing, unaddableModel, unroutableVendorModel, vendorClientType };