@pactor-app/skills 1.24.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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -0
  3. package/package.json +26 -0
  4. package/pactor/SKILL.md +373 -0
  5. package/pactor/references/dsl-authoring.md +448 -0
  6. package/prd-to-app/SKILL.md +75 -0
  7. package/prd-to-app/references/acceptance-checklist.md +47 -0
  8. package/prd-to-app/references/component-mapping.md +41 -0
  9. package/prd-to-app/references/mock-data-routes.md +66 -0
  10. package/prd-to-app/references/page-templates.md +274 -0
  11. package/prd-to-app/references/project-structure.md +89 -0
  12. package/prd-to-app/references/theme-and-style.md +41 -0
  13. package/prd-to-app/template/README.md +26 -0
  14. package/prd-to-app/template/app/[[...slug]]/page.tsx +7 -0
  15. package/prd-to-app/template/app/api/auth/login/route.ts +32 -0
  16. package/prd-to-app/template/app/api/auth/logout/route.ts +22 -0
  17. package/prd-to-app/template/app/api/data/[...parts]/route.ts +118 -0
  18. package/prd-to-app/template/app/api/public/pages/[id]/route.ts +40 -0
  19. package/prd-to-app/template/app/api/sitemap/route.ts +21 -0
  20. package/prd-to-app/template/app/api/users/route.ts +57 -0
  21. package/prd-to-app/template/app/favicon.ico +0 -0
  22. package/prd-to-app/template/app/globals.css +248 -0
  23. package/prd-to-app/template/app/layout.tsx +49 -0
  24. package/prd-to-app/template/app/login.css +122 -0
  25. package/prd-to-app/template/eslint.config.mjs +18 -0
  26. package/prd-to-app/template/next-env.d.ts +7 -0
  27. package/prd-to-app/template/next.config.js +32 -0
  28. package/prd-to-app/template/package.json +34 -0
  29. package/prd-to-app/template/pnpm-lock.yaml +6854 -0
  30. package/prd-to-app/template/pnpm-workspace.yaml +7 -0
  31. package/prd-to-app/template/postcss.config.mjs +7 -0
  32. package/prd-to-app/template/public/file.svg +1 -0
  33. package/prd-to-app/template/public/globe.svg +1 -0
  34. package/prd-to-app/template/public/next.svg +1 -0
  35. package/prd-to-app/template/public/skins/chenwunaifu.css +111 -0
  36. package/prd-to-app/template/public/skins/taijingshenlin.css +109 -0
  37. package/prd-to-app/template/public/skins/xuanzhimoyun.css +110 -0
  38. package/prd-to-app/template/public/vercel.svg +1 -0
  39. package/prd-to-app/template/public/window.svg +1 -0
  40. package/prd-to-app/template/scripts/build.mjs +35 -0
  41. package/prd-to-app/template/src/pactor/App.tsx +55 -0
  42. package/prd-to-app/template/src/pactor/actions.ts +438 -0
  43. package/prd-to-app/template/src/pactor/components/card-links.tsx +86 -0
  44. package/prd-to-app/template/src/pactor/components/chip-filter.tsx +89 -0
  45. package/prd-to-app/template/src/pactor/components/chip-node.tsx +46 -0
  46. package/prd-to-app/template/src/pactor/components/debug-chat.tsx +189 -0
  47. package/prd-to-app/template/src/pactor/components/index.ts +28 -0
  48. package/prd-to-app/template/src/pactor/components/log-status.tsx +64 -0
  49. package/prd-to-app/template/src/pactor/components/status-badge.tsx +46 -0
  50. package/prd-to-app/template/src/pactor/components/theme-switcher.tsx +136 -0
  51. package/prd-to-app/template/src/pactor/config.ts +28 -0
  52. package/prd-to-app/template/src/pactor/mocks/audit-mock.ts +403 -0
  53. package/prd-to-app/template/src/pactor/mocks/call-logs-mock.ts +875 -0
  54. package/prd-to-app/template/src/pactor/mocks/client-debug-mock.ts +188 -0
  55. package/prd-to-app/template/src/pactor/mocks/client-templates-mock.ts +497 -0
  56. package/prd-to-app/template/src/pactor/mocks/clients-mock.ts +483 -0
  57. package/prd-to-app/template/src/pactor/mocks/costs-mock.ts +406 -0
  58. package/prd-to-app/template/src/pactor/mocks/dashboard-mock.ts +192 -0
  59. package/prd-to-app/template/src/pactor/mocks/model-debug-mock.ts +144 -0
  60. package/prd-to-app/template/src/pactor/mocks/models-mock.ts +799 -0
  61. package/prd-to-app/template/src/pactor/mocks/ops-usage-mock.ts +806 -0
  62. package/prd-to-app/template/src/pactor/mocks/providers-mock.ts +424 -0
  63. package/prd-to-app/template/src/pactor/mocks/routes-mock.ts +604 -0
  64. package/prd-to-app/template/src/pactor/services.ts +185 -0
  65. package/prd-to-app/template/src/pactor/skin.ts +52 -0
  66. package/prd-to-app/template/src/server/accounts.ts +63 -0
  67. package/prd-to-app/template/src/server/cors.ts +34 -0
  68. package/prd-to-app/template/src/server/sitemap.ts +176 -0
  69. package/prd-to-app/template/src/server/yaml/common/dashboard.yaml +498 -0
  70. package/prd-to-app/template/src/server/yaml/common/login.yaml +84 -0
  71. package/prd-to-app/template/src/server/yaml/provider/provider-create.yaml +340 -0
  72. package/prd-to-app/template/src/server/yaml/provider/provider-detail.yaml +780 -0
  73. package/prd-to-app/template/src/server/yaml/provider/provider-edit.yaml +366 -0
  74. package/prd-to-app/template/src/server/yaml/provider/provider-list.yaml +1989 -0
  75. package/prd-to-app/template/src/server/yaml/route/route-create.yaml +511 -0
  76. package/prd-to-app/template/src/server/yaml/route/route-detail.yaml +610 -0
  77. package/prd-to-app/template/src/server/yaml/route/route-edit.yaml +809 -0
  78. package/prd-to-app/template/src/server/yaml/route/route-list.yaml +1793 -0
  79. package/prd-to-app/template/src/server/yaml/sitemap.yaml +250 -0
  80. package/prd-to-app/template/tsconfig.json +34 -0
@@ -0,0 +1,799 @@
1
+ /**
2
+ * Model 演示数据服务(MVP mock,静态页面)。
3
+ * model.list / model.detail 注册为 Pactor service;接入真实后端后替换为
4
+ * http / service 数据源,DSL 绑定路径保持不变。
5
+ * 数据形态对齐 PRD《01-Model列表页》《02-Model详情页》《03-Model新增编辑页》(§7.2、§7.3)。
6
+ */
7
+
8
+ export type ModelStatus = "enabled" | "disabled";
9
+ export type ModelType = "LLM" | "Embedding" | "Image" | "Audio";
10
+
11
+ /** 标准价格分档:upto=null 表示无上限档(∞) */
12
+ export interface ModelTier {
13
+ upto: number | null;
14
+ input: number;
15
+ output: number;
16
+ cacheRead: number | null;
17
+ cacheWrite: number | null;
18
+ }
19
+
20
+ /** 定价时段倍率 */
21
+ export interface TimeMultiplier {
22
+ days: string;
23
+ start: string;
24
+ end: string;
25
+ rate: number;
26
+ }
27
+
28
+ /** 供应商模型绑定(提供商 Tab):时段成本/计费倍率 */
29
+ export interface SupplierTimeRate {
30
+ days: string;
31
+ start: string;
32
+ end: string;
33
+ cost: number;
34
+ billing: number;
35
+ }
36
+
37
+ export interface SupplierModel {
38
+ providerCode: string;
39
+ providerName: string;
40
+ /** 继承 Provider 品牌图标(Icon 白名单图标名) */
41
+ providerIcon: string;
42
+ providerModelId: string;
43
+ weight: number;
44
+ /** 供应商成本倍率 C(相对定价 Tab 标准价) */
45
+ costRate: number;
46
+ /** 模型计费倍率 M(相对定价 Tab 标准价) */
47
+ billingRate: number;
48
+ status: ModelStatus;
49
+ /** 时段倍率;null = 未配置,使用默认 C / M */
50
+ timeRates: SupplierTimeRate[] | null;
51
+ /** 继承 Provider 密钥状态 */
52
+ keyConfigured: boolean;
53
+ lastProbe: { time: string; ok: boolean } | null;
54
+ }
55
+
56
+ /** 路由引用(路由引用 Tab) */
57
+ export interface RouteRef {
58
+ name: string;
59
+ alias: string;
60
+ type: string;
61
+ weight: number;
62
+ status: "启用" | "停用";
63
+ health: "HEALTHY" | "UNHEALTHY";
64
+ }
65
+
66
+ /** 定价版本历史 */
67
+ export interface PriceVersion {
68
+ version: string;
69
+ current: boolean;
70
+ effective: string;
71
+ summary: string;
72
+ }
73
+
74
+ /** 默认参数(默认参数 Tab + 编辑页「默认参数」区) */
75
+ export interface ModelParams {
76
+ temperature: string;
77
+ topP: string;
78
+ topK: string;
79
+ maxTokens: string;
80
+ frequencyPenalty: string;
81
+ presencePenalty: string;
82
+ reasoningEffort: string;
83
+ seed: string;
84
+ stopSequences: string;
85
+ responseFormat: string;
86
+ capabilities: string[];
87
+ }
88
+
89
+ export interface ModelRecord {
90
+ code: string;
91
+ name: string;
92
+ providerCode: string;
93
+ providerName: string;
94
+ providerIcon: string;
95
+ type: ModelType;
96
+ typeLabel: string;
97
+ releaseDate: string;
98
+ contextWindow: number;
99
+ /** 0 表示未设置(展示 —) */
100
+ maxTokens: number;
101
+ inputModalities: string[];
102
+ outputModalities: string[];
103
+ tags: string[];
104
+ description: string;
105
+ /** 元数据(JSON 文本) */
106
+ metadata: string;
107
+ status: ModelStatus;
108
+ tiers: ModelTier[];
109
+ timeMultipliers: TimeMultiplier[];
110
+ currency: string;
111
+ priceVersion: string;
112
+ priceEffective: string;
113
+ priceVersions: PriceVersion[];
114
+ suppliers: SupplierModel[];
115
+ routes: { total: number; active: number };
116
+ routeRefs: RouteRef[];
117
+ params: ModelParams;
118
+ createdAt: string;
119
+ updatedAt: string;
120
+ operator: string;
121
+ // ── 预计算摘要(表达式不适合拼接复合文案) ──
122
+ /** 规格摘要:如 `256K · 32K`(上下文 · 最大输出) */
123
+ specSummary: string;
124
+ /** 定价摘要:默认档 如 `$0.2 / $1.6 /M`(输出为 0 时展示 —) */
125
+ pricingSummary: string;
126
+ /** 多档标识:如 `4档`;单档为空串 */
127
+ tierLabel: string;
128
+ /** 路由摘要:`N 条路由 · M 条活跃` 或 `未关联路由` */
129
+ routeSummary: string;
130
+ /** 模态预览:如 `T+I+V → T` */
131
+ modalityPreview: string;
132
+ inputModalitiesText: string;
133
+ outputModalitiesText: string;
134
+ tagsText: string;
135
+ /** Provider 摘要:`阿里云百炼(主) · 共 N 个供应商模型` */
136
+ providerSummary: string;
137
+ /** 主供应商上游 Model ID(权重最高的启用实例) */
138
+ primaryUpstreamId: string;
139
+ /** 启用实例权重合计(展示文案) */
140
+ supplierWeightTotal: string;
141
+ /** 最近更新短日期(MM-DD) */
142
+ shortDate: string;
143
+ }
144
+
145
+ export interface ModelListParams {
146
+ /** all | LLM | Embedding | Image | Audio */
147
+ type?: string;
148
+ /** 厂商多选(Provider Code 列表) */
149
+ providers?: string[];
150
+ }
151
+
152
+ /** 快筛 Chip 计数(数据构成口径,不随筛选变化) */
153
+ export interface ModelCounts {
154
+ all: { enabled: number; total: number };
155
+ types: Record<ModelType, number>;
156
+ providers: Record<string, number>;
157
+ }
158
+
159
+ /** 快筛 Chip 选项(ChipFilter 组件入项;文案在接口侧预计算) */
160
+ export interface ModelChipOption {
161
+ value: string;
162
+ text: string;
163
+ dot?: string;
164
+ }
165
+
166
+ export interface ModelListResult {
167
+ items: ModelRecord[];
168
+ total: number;
169
+ counts: ModelCounts;
170
+ /** 快筛 Chip 组:type 单选(含「全部」),providers 多选(含「全部」,点击清空) */
171
+ filters: { type: ModelChipOption[]; providers: ModelChipOption[] };
172
+ }
173
+
174
+ const TYPE_LABELS: Record<ModelType, string> = {
175
+ LLM: "大语言模型 (LLM)",
176
+ Embedding: "Embedding",
177
+ Image: "文生图 (Image)",
178
+ Audio: "音频 (Audio)",
179
+ };
180
+
181
+ /** Token 数 → 短写法:256000 → 256K,1000000 → 1M,8192 → 8K */
182
+ function formatTokens(n: number): string {
183
+ if (n >= 1_000_000) {
184
+ const v = n / 1_000_000;
185
+ return `${v % 1 === 0 ? v : v.toFixed(1)}M`;
186
+ }
187
+ if (n >= 1_000) {
188
+ const v = n / 1_000;
189
+ return `${v % 1 === 0 ? v : v.toFixed(1)}K`;
190
+ }
191
+ return String(n);
192
+ }
193
+
194
+ function modalityLetter(m: string): string {
195
+ return (
196
+ { text: "T", image: "I", audio: "A", video: "V", file: "F" }[m] ??
197
+ m[0].toUpperCase()
198
+ );
199
+ }
200
+
201
+ function joinList(items: string[]): string {
202
+ return items.join(" · ");
203
+ }
204
+
205
+ /** 列表卡/详情页摘要字段派生 */
206
+ function derive(
207
+ record: Omit<
208
+ ModelRecord,
209
+ | "typeLabel"
210
+ | "specSummary"
211
+ | "pricingSummary"
212
+ | "tierLabel"
213
+ | "routeSummary"
214
+ | "modalityPreview"
215
+ | "inputModalitiesText"
216
+ | "outputModalitiesText"
217
+ | "tagsText"
218
+ | "providerSummary"
219
+ | "primaryUpstreamId"
220
+ | "supplierWeightTotal"
221
+ | "shortDate"
222
+ >,
223
+ ): ModelRecord {
224
+ const firstTier = record.tiers[0];
225
+ const enabledSuppliers = record.suppliers.filter(
226
+ (s) => s.status === "enabled",
227
+ );
228
+ const primary = enabledSuppliers[0] ?? record.suppliers[0];
229
+ return {
230
+ ...record,
231
+ typeLabel: TYPE_LABELS[record.type],
232
+ specSummary: `${formatTokens(record.contextWindow)} · ${record.maxTokens > 0 ? formatTokens(record.maxTokens) : "—"}`,
233
+ pricingSummary: firstTier
234
+ ? `$${firstTier.input} / $${firstTier.output > 0 ? firstTier.output : "—"} /M`
235
+ : "未定价",
236
+ tierLabel: record.tiers.length > 1 ? `${record.tiers.length}档` : "",
237
+ routeSummary:
238
+ record.routes.total === 0
239
+ ? "未关联路由"
240
+ : `${record.routes.total} 条路由 · ${record.routes.active} 条活跃`,
241
+ modalityPreview: `${record.inputModalities.map(modalityLetter).join("+")} → ${record.outputModalities.map(modalityLetter).join("+")}`,
242
+ inputModalitiesText: joinList(record.inputModalities),
243
+ outputModalitiesText: joinList(record.outputModalities),
244
+ tagsText: joinList(record.tags),
245
+ providerSummary: primary
246
+ ? `${primary.providerName}(主) · 共 ${record.suppliers.length} 个供应商模型`
247
+ : "未绑定供应商模型",
248
+ primaryUpstreamId: primary?.providerModelId ?? "—",
249
+ supplierWeightTotal: String(
250
+ enabledSuppliers.reduce((sum, s) => sum + s.weight, 0),
251
+ ),
252
+ shortDate: record.updatedAt.slice(5, 10),
253
+ };
254
+ }
255
+
256
+ const MODELS: ModelRecord[] = [
257
+ derive({
258
+ code: "qwen3-vl-plus",
259
+ name: "Qwen3-VL Plus",
260
+ providerCode: "dashscope",
261
+ providerName: "阿里云百炼",
262
+ providerIcon: "cloud",
263
+ type: "LLM",
264
+ releaseDate: "2025-12-19",
265
+ contextWindow: 256000,
266
+ maxTokens: 32000,
267
+ inputModalities: ["text", "image", "video"],
268
+ outputModalities: ["text"],
269
+ tags: ["free", "lite", "vision"],
270
+ description:
271
+ "A vision-language model for document, image, screen understanding and agentic visual tasks.",
272
+ metadata: '{\n "vendor_tier": "plus"\n}',
273
+ status: "enabled",
274
+ tiers: [
275
+ {
276
+ upto: 32000,
277
+ input: 0.2,
278
+ output: 1.6,
279
+ cacheRead: null,
280
+ cacheWrite: null,
281
+ },
282
+ {
283
+ upto: 128000,
284
+ input: 0.4,
285
+ output: 3.2,
286
+ cacheRead: null,
287
+ cacheWrite: null,
288
+ },
289
+ {
290
+ upto: 1000000,
291
+ input: 0.8,
292
+ output: 6.4,
293
+ cacheRead: null,
294
+ cacheWrite: null,
295
+ },
296
+ { upto: null, input: 1.2, output: 9.6, cacheRead: 0.1, cacheWrite: 0.2 },
297
+ ],
298
+ timeMultipliers: [
299
+ { days: "每天", start: "00:00", end: "08:00", rate: 0.8 },
300
+ { days: "工作日", start: "09:00", end: "18:00", rate: 1.2 },
301
+ ],
302
+ currency: "USD",
303
+ priceVersion: "3",
304
+ priceEffective: "2026-09-01",
305
+ priceVersions: [
306
+ {
307
+ version: "v3",
308
+ current: true,
309
+ effective: "2026-09-01",
310
+ summary: "4档 · 2条时段倍率",
311
+ },
312
+ {
313
+ version: "v2",
314
+ current: false,
315
+ effective: "2026-08-01",
316
+ summary: "3档 · 1条时段倍率",
317
+ },
318
+ ],
319
+ suppliers: [
320
+ {
321
+ providerCode: "dashscope",
322
+ providerName: "阿里云百炼",
323
+ providerIcon: "cloud",
324
+ providerModelId: "qwen-vl-plus-latest",
325
+ weight: 60,
326
+ costRate: 1.0,
327
+ billingRate: 1.2,
328
+ status: "enabled",
329
+ timeRates: [
330
+ {
331
+ days: "每天",
332
+ start: "00:00",
333
+ end: "08:00",
334
+ cost: 0.8,
335
+ billing: 0.9,
336
+ },
337
+ {
338
+ days: "工作日",
339
+ start: "09:00",
340
+ end: "18:00",
341
+ cost: 1.0,
342
+ billing: 1.2,
343
+ },
344
+ ],
345
+ keyConfigured: false,
346
+ lastProbe: null,
347
+ },
348
+ {
349
+ providerCode: "openai",
350
+ providerName: "OpenAI",
351
+ providerIcon: "zap",
352
+ providerModelId: "gpt-4o-2024-08-06",
353
+ weight: 40,
354
+ costRate: 1.1,
355
+ billingRate: 1.0,
356
+ status: "enabled",
357
+ timeRates: null,
358
+ keyConfigured: true,
359
+ lastProbe: { time: "2026-09-08 14:20", ok: true },
360
+ },
361
+ ],
362
+ routes: { total: 2, active: 0 },
363
+ routeRefs: [
364
+ {
365
+ name: "reasoning-default",
366
+ alias: "reasoning",
367
+ type: "多模型池",
368
+ weight: 60,
369
+ status: "启用",
370
+ health: "HEALTHY",
371
+ },
372
+ {
373
+ name: "general-chat",
374
+ alias: "general",
375
+ type: "单模型",
376
+ weight: 100,
377
+ status: "启用",
378
+ health: "HEALTHY",
379
+ },
380
+ ],
381
+ params: {
382
+ temperature: "0.7",
383
+ topP: "0.9",
384
+ topK: "40",
385
+ maxTokens: "4096",
386
+ frequencyPenalty: "0",
387
+ presencePenalty: "0",
388
+ reasoningEffort: "medium",
389
+ seed: "—",
390
+ stopSequences: "[]",
391
+ responseFormat: "text",
392
+ capabilities: ["Streaming", "Tool Calling", "Vision"],
393
+ },
394
+ createdAt: "2026-06-01 10:00",
395
+ updatedAt: "2026-09-05 14:20",
396
+ operator: "张三",
397
+ }),
398
+ derive({
399
+ code: "qwen3.5-flash",
400
+ name: "Qwen3.5 Flash",
401
+ providerCode: "dashscope",
402
+ providerName: "阿里云百炼",
403
+ providerIcon: "cloud",
404
+ type: "LLM",
405
+ releaseDate: "2026-03-10",
406
+ contextWindow: 1000000,
407
+ maxTokens: 64000,
408
+ inputModalities: ["text"],
409
+ outputModalities: ["text"],
410
+ tags: ["free", "lite"],
411
+ description: "轻量大语言模型,长上下文,低延迟,适合高频对话场景。",
412
+ metadata: '{\n "vendor_tier": "flash"\n}',
413
+ status: "enabled",
414
+ tiers: [
415
+ {
416
+ upto: 128000,
417
+ input: 0.1,
418
+ output: 0.4,
419
+ cacheRead: null,
420
+ cacheWrite: null,
421
+ },
422
+ {
423
+ upto: 512000,
424
+ input: 0.2,
425
+ output: 0.8,
426
+ cacheRead: null,
427
+ cacheWrite: null,
428
+ },
429
+ { upto: null, input: 0.3, output: 1.2, cacheRead: 0.05, cacheWrite: 0.1 },
430
+ ],
431
+ timeMultipliers: [
432
+ { days: "每天", start: "00:00", end: "08:00", rate: 0.9 },
433
+ ],
434
+ currency: "USD",
435
+ priceVersion: "2",
436
+ priceEffective: "2026-08-15",
437
+ priceVersions: [
438
+ {
439
+ version: "v2",
440
+ current: true,
441
+ effective: "2026-08-15",
442
+ summary: "3档 · 1条时段倍率",
443
+ },
444
+ {
445
+ version: "v1",
446
+ current: false,
447
+ effective: "2026-07-01",
448
+ summary: "2档 · 无时段倍率",
449
+ },
450
+ ],
451
+ suppliers: [
452
+ {
453
+ providerCode: "dashscope",
454
+ providerName: "阿里云百炼",
455
+ providerIcon: "cloud",
456
+ providerModelId: "qwen3.5-flash",
457
+ weight: 100,
458
+ costRate: 1.0,
459
+ billingRate: 1.0,
460
+ status: "enabled",
461
+ timeRates: null,
462
+ keyConfigured: false,
463
+ lastProbe: null,
464
+ },
465
+ ],
466
+ routes: { total: 1, active: 1 },
467
+ routeRefs: [
468
+ {
469
+ name: "general-chat",
470
+ alias: "general",
471
+ type: "单模型",
472
+ weight: 100,
473
+ status: "启用",
474
+ health: "HEALTHY",
475
+ },
476
+ ],
477
+ params: {
478
+ temperature: "0.6",
479
+ topP: "0.9",
480
+ topK: "40",
481
+ maxTokens: "8192",
482
+ frequencyPenalty: "0",
483
+ presencePenalty: "0",
484
+ reasoningEffort: "low",
485
+ seed: "—",
486
+ stopSequences: "[]",
487
+ responseFormat: "text",
488
+ capabilities: ["Streaming", "Tool Calling"],
489
+ },
490
+ createdAt: "2026-06-15 09:30",
491
+ updatedAt: "2026-09-08 11:05",
492
+ operator: "李四",
493
+ }),
494
+ derive({
495
+ code: "gemini-3-flash",
496
+ name: "Gemini 3 Flash",
497
+ providerCode: "gemini",
498
+ providerName: "Google Gemini",
499
+ providerIcon: "star",
500
+ type: "LLM",
501
+ releaseDate: "2026-01-22",
502
+ contextWindow: 1000000,
503
+ maxTokens: 64000,
504
+ inputModalities: ["text", "image"],
505
+ outputModalities: ["text"],
506
+ tags: ["lite", "vision"],
507
+ description: "Google Gemini 3 Flash:多模态输入,百万级上下文。",
508
+ metadata: "{}",
509
+ status: "enabled",
510
+ tiers: [
511
+ {
512
+ upto: 200000,
513
+ input: 0.15,
514
+ output: 0.6,
515
+ cacheRead: null,
516
+ cacheWrite: null,
517
+ },
518
+ {
519
+ upto: null,
520
+ input: 0.3,
521
+ output: 1.2,
522
+ cacheRead: 0.03,
523
+ cacheWrite: 0.05,
524
+ },
525
+ ],
526
+ timeMultipliers: [],
527
+ currency: "USD",
528
+ priceVersion: "1",
529
+ priceEffective: "2026-08-30",
530
+ priceVersions: [
531
+ {
532
+ version: "v1",
533
+ current: true,
534
+ effective: "2026-08-30",
535
+ summary: "2档 · 无时段倍率",
536
+ },
537
+ ],
538
+ suppliers: [
539
+ {
540
+ providerCode: "gemini",
541
+ providerName: "Google Gemini",
542
+ providerIcon: "star",
543
+ providerModelId: "gemini-3-flash",
544
+ weight: 100,
545
+ costRate: 1.0,
546
+ billingRate: 1.0,
547
+ status: "enabled",
548
+ timeRates: null,
549
+ keyConfigured: false,
550
+ lastProbe: { time: "2026-08-30 20:10", ok: false },
551
+ },
552
+ ],
553
+ routes: { total: 0, active: 0 },
554
+ routeRefs: [],
555
+ params: {
556
+ temperature: "0.7",
557
+ topP: "0.95",
558
+ topK: "64",
559
+ maxTokens: "8192",
560
+ frequencyPenalty: "0",
561
+ presencePenalty: "0",
562
+ reasoningEffort: "medium",
563
+ seed: "—",
564
+ stopSequences: "[]",
565
+ responseFormat: "text",
566
+ capabilities: ["Streaming", "Tool Calling", "Vision"],
567
+ },
568
+ createdAt: "2026-07-02 16:00",
569
+ updatedAt: "2026-08-30 20:10",
570
+ operator: "张三",
571
+ }),
572
+ derive({
573
+ code: "gpt-5",
574
+ name: "GPT-5",
575
+ providerCode: "openai",
576
+ providerName: "OpenAI",
577
+ providerIcon: "zap",
578
+ type: "LLM",
579
+ releaseDate: "2026-02-14",
580
+ contextWindow: 512000,
581
+ maxTokens: 64000,
582
+ inputModalities: ["text", "image", "audio", "file"],
583
+ outputModalities: ["text"],
584
+ tags: ["pro"],
585
+ description: "OpenAI GPT-5 旗舰模型,支持文本、图像、音频与文件输入。",
586
+ metadata: '{\n "vendor_tier": "pro"\n}',
587
+ status: "enabled",
588
+ tiers: [
589
+ { upto: null, input: 0.4, output: 1.8, cacheRead: 0.1, cacheWrite: 0.2 },
590
+ ],
591
+ timeMultipliers: [],
592
+ currency: "USD",
593
+ priceVersion: "1",
594
+ priceEffective: "2026-09-10",
595
+ priceVersions: [
596
+ {
597
+ version: "v1",
598
+ current: true,
599
+ effective: "2026-09-10",
600
+ summary: "1档 · 无时段倍率",
601
+ },
602
+ ],
603
+ suppliers: [
604
+ {
605
+ providerCode: "openai",
606
+ providerName: "OpenAI",
607
+ providerIcon: "zap",
608
+ providerModelId: "gpt-5",
609
+ weight: 100,
610
+ costRate: 1.0,
611
+ billingRate: 1.0,
612
+ status: "enabled",
613
+ timeRates: null,
614
+ keyConfigured: true,
615
+ lastProbe: { time: "2026-09-10 09:12", ok: true },
616
+ },
617
+ ],
618
+ routes: { total: 2, active: 1 },
619
+ routeRefs: [
620
+ {
621
+ name: "reasoning-default",
622
+ alias: "reasoning",
623
+ type: "多模型池",
624
+ weight: 40,
625
+ status: "启用",
626
+ health: "HEALTHY",
627
+ },
628
+ {
629
+ name: "coding-assistant",
630
+ alias: "coding",
631
+ type: "单模型",
632
+ weight: 100,
633
+ status: "启用",
634
+ health: "HEALTHY",
635
+ },
636
+ ],
637
+ params: {
638
+ temperature: "0.5",
639
+ topP: "0.9",
640
+ topK: "—",
641
+ maxTokens: "16384",
642
+ frequencyPenalty: "0",
643
+ presencePenalty: "0",
644
+ reasoningEffort: "high",
645
+ seed: "—",
646
+ stopSequences: "[]",
647
+ responseFormat: "text",
648
+ capabilities: ["Streaming", "Tool Calling", "Vision", "JSON Schema"],
649
+ },
650
+ createdAt: "2026-07-20 14:00",
651
+ updatedAt: "2026-09-10 09:12",
652
+ operator: "王五",
653
+ }),
654
+ derive({
655
+ code: "text-embedding-3-large",
656
+ name: "Text Embedding 3 Large",
657
+ providerCode: "openai",
658
+ providerName: "OpenAI",
659
+ providerIcon: "zap",
660
+ type: "Embedding",
661
+ releaseDate: "2024-03-15",
662
+ contextWindow: 8192,
663
+ maxTokens: 0,
664
+ inputModalities: ["text"],
665
+ outputModalities: ["text"],
666
+ tags: ["embedding"],
667
+ description: "OpenAI 文本向量模型,用于检索、聚类与语义相似度计算。",
668
+ metadata: "{}",
669
+ status: "disabled",
670
+ tiers: [
671
+ { upto: null, input: 0.1, output: 0, cacheRead: null, cacheWrite: null },
672
+ ],
673
+ timeMultipliers: [],
674
+ currency: "USD",
675
+ priceVersion: "1",
676
+ priceEffective: "2026-07-01",
677
+ priceVersions: [
678
+ {
679
+ version: "v1",
680
+ current: true,
681
+ effective: "2026-07-01",
682
+ summary: "1档 · 无时段倍率",
683
+ },
684
+ ],
685
+ suppliers: [
686
+ {
687
+ providerCode: "openai",
688
+ providerName: "OpenAI",
689
+ providerIcon: "zap",
690
+ providerModelId: "text-embedding-3-large",
691
+ weight: 100,
692
+ costRate: 1.0,
693
+ billingRate: 1.0,
694
+ status: "enabled",
695
+ timeRates: null,
696
+ keyConfigured: true,
697
+ lastProbe: { time: "2026-09-01 10:00", ok: true },
698
+ },
699
+ ],
700
+ routes: { total: 0, active: 0 },
701
+ routeRefs: [],
702
+ params: {
703
+ temperature: "—",
704
+ topP: "—",
705
+ topK: "—",
706
+ maxTokens: "—",
707
+ frequencyPenalty: "—",
708
+ presencePenalty: "—",
709
+ reasoningEffort: "—",
710
+ seed: "—",
711
+ stopSequences: "—",
712
+ responseFormat: "—",
713
+ capabilities: [],
714
+ },
715
+ createdAt: "2026-06-25 11:00",
716
+ updatedAt: "2026-07-22 18:40",
717
+ operator: "李四",
718
+ }),
719
+ ];
720
+
721
+ /** 快筛选项常量:类型(单选)与厂商(多选,取有模型的 Provider) */
722
+ export const MODEL_TYPE_OPTIONS: { value: string; label: string }[] = [
723
+ { value: "all", label: "全部" },
724
+ { value: "LLM", label: "大语言模型" },
725
+ { value: "Image", label: "文生图" },
726
+ { value: "Audio", label: "音频" },
727
+ { value: "Embedding", label: "Embedding" },
728
+ ];
729
+
730
+ /** 厂商快筛:providers-with-models 的展示顺序(对齐 PRD 线框图) */
731
+ export const MODEL_PROVIDER_FILTERS: { value: string; label: string }[] = [
732
+ { value: "dashscope", label: "阿里云百炼" },
733
+ { value: "gemini", label: "Google Gemini" },
734
+ { value: "openai", label: "OpenAI" },
735
+ ];
736
+
737
+ /** 快筛计数:基于全量数据(构成口径,与当前筛选无关) */
738
+ function computeCounts(): ModelCounts {
739
+ return {
740
+ all: {
741
+ enabled: MODELS.filter((m) => m.status === "enabled").length,
742
+ total: MODELS.length,
743
+ },
744
+ types: {
745
+ LLM: MODELS.filter((m) => m.type === "LLM").length,
746
+ Embedding: MODELS.filter((m) => m.type === "Embedding").length,
747
+ Image: MODELS.filter((m) => m.type === "Image").length,
748
+ Audio: MODELS.filter((m) => m.type === "Audio").length,
749
+ },
750
+ providers: MODEL_PROVIDER_FILTERS.reduce<Record<string, number>>(
751
+ (acc, p) => {
752
+ acc[p.value] = MODELS.filter((m) => m.providerCode === p.value).length;
753
+ return acc;
754
+ },
755
+ {},
756
+ ),
757
+ };
758
+ }
759
+
760
+ /** 快筛 Chip 选项:由计数派生,文案在此预计算(表达式不支持复合文案拼接) */
761
+ function computeFilters(counts: ModelCounts): ModelListResult["filters"] {
762
+ return {
763
+ type: [
764
+ { value: "all", text: `全部 ${counts.all.total}` },
765
+ ...MODEL_TYPE_OPTIONS.filter((o) => o.value !== "all").map((o) => ({
766
+ value: o.value,
767
+ text: `${o.label} ${counts.types[o.value as ModelType]}`,
768
+ })),
769
+ ],
770
+ providers: [
771
+ { value: "all", text: `全部 ${counts.all.total}` },
772
+ ...MODEL_PROVIDER_FILTERS.map((p) => ({
773
+ value: p.value,
774
+ text: `${p.label} ${counts.providers[p.value]}`,
775
+ })),
776
+ ],
777
+ };
778
+ }
779
+
780
+ /** model.list:类型单选 + 厂商多选取交集,按 Updated At 降序(「添加模型」卡置顶由页面保证) */
781
+ export function queryModels(params: ModelListParams = {}): ModelListResult {
782
+ const type = params.type ?? "all";
783
+ const providers = params.providers ?? [];
784
+ const items = MODELS.filter(
785
+ (m) =>
786
+ (type === "all" || m.type === type) &&
787
+ (providers.length === 0 || providers.includes(m.providerCode)),
788
+ ).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
789
+ const counts = computeCounts();
790
+ return { items, total: MODELS.length, counts, filters: computeFilters(counts) };
791
+ }
792
+
793
+ /** model.detail:按 Model Code 取详情;未命中返回 undefined(页面做空态) */
794
+ export function getModel(code: string): ModelRecord | undefined {
795
+ return MODELS.find((m) => m.code === code);
796
+ }
797
+
798
+ /** 全量 Model Code(静态导出 generateStaticParams 用) */
799
+ export const MODEL_CODES: string[] = MODELS.map((m) => m.code);