@ryanfw/prompt-orchestration-pipeline 1.2.6 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/config/__tests__/models.test.ts +51 -11
- package/src/config/models.ts +195 -100
- package/src/core/__tests__/config.test.ts +79 -0
- package/src/core/__tests__/lifecycle-policy.test.ts +78 -0
- package/src/core/__tests__/pipeline-runner.test.ts +628 -0
- package/src/core/__tests__/task-runner.test.ts +2 -3
- package/src/core/config.ts +17 -0
- package/src/core/pipeline-runner.ts +67 -9
- package/src/core/status-writer.ts +4 -0
- package/src/core/task-runner.ts +2 -5
- package/src/providers/__tests__/base.test.ts +2 -2
- package/src/providers/__tests__/openai.test.ts +1 -1
- package/src/ui/client/__tests__/job-adapter.test.ts +12 -0
- package/src/ui/client/adapters/job-adapter.ts +1 -0
- package/src/ui/client/types.ts +1 -0
- package/src/ui/components/DAGGrid.tsx +11 -1
- package/src/ui/components/JobDetail.tsx +2 -1
- package/src/ui/components/__tests__/DAGGrid.test.tsx +92 -0
- package/src/ui/components/__tests__/JobDetail.test.tsx +62 -0
- package/src/ui/components/types.ts +2 -0
- package/src/ui/dist/assets/{index-CeAgP91B.js → index-CNlnQmK4.js} +144 -64
- package/src/ui/dist/assets/{index-CeAgP91B.js.map → index-CNlnQmK4.js.map} +1 -1
- package/src/ui/dist/assets/style-DNbNL3Yg.css +2 -0
- package/src/ui/dist/index.html +2 -2
- package/src/ui/embedded-assets.js +6 -6
- package/src/ui/server/__tests__/job-control-endpoints.test.ts +474 -2
- package/src/ui/server/endpoints/job-control-endpoints.ts +136 -22
- package/src/ui/state/transformers/__tests__/status-transformer.test.ts +15 -0
- package/src/ui/state/transformers/status-transformer.ts +1 -0
- package/src/ui/state/types.ts +1 -0
- package/src/utils/__tests__/dag.test.ts +35 -0
- package/src/utils/dag.ts +1 -0
- package/src/ui/dist/assets/style-DA1Ma4YS.css +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryanfw/prompt-orchestration-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"description": "A Prompt-orchestration pipeline (POP) is a framework for building, running, and experimenting with complex chains of LLM tasks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/ui/server/index.ts",
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "../models";
|
|
16
16
|
import type { ModelConfigEntry } from "../models";
|
|
17
17
|
|
|
18
|
-
const MODEL_COUNT =
|
|
18
|
+
const MODEL_COUNT = 50;
|
|
19
19
|
const PROVIDER_COUNT = 8;
|
|
20
20
|
|
|
21
21
|
describe("ModelAlias", () => {
|
|
@@ -110,8 +110,8 @@ describe("DEFAULT_MODEL_BY_PROVIDER", () => {
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
describe("aliasToFunctionName", () => {
|
|
113
|
-
it('converts "openai:gpt-5.
|
|
114
|
-
expect(aliasToFunctionName("openai:gpt-5.
|
|
113
|
+
it('converts "openai:gpt-5.4" to "gpt54"', () => {
|
|
114
|
+
expect(aliasToFunctionName("openai:gpt-5.4")).toBe("gpt54");
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
it('converts "gemini:flash-2.5-lite" to "flash25Lite"', () => {
|
|
@@ -137,8 +137,8 @@ describe("aliasToFunctionName", () => {
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
describe("getProviderFromAlias", () => {
|
|
140
|
-
it('returns "openai" for "openai:gpt-5.
|
|
141
|
-
expect(getProviderFromAlias("openai:gpt-5.
|
|
140
|
+
it('returns "openai" for "openai:gpt-5.4"', () => {
|
|
141
|
+
expect(getProviderFromAlias("openai:gpt-5.4")).toBe("openai");
|
|
142
142
|
});
|
|
143
143
|
|
|
144
144
|
it("throws for non-string input", () => {
|
|
@@ -152,8 +152,8 @@ describe("getProviderFromAlias", () => {
|
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
describe("getModelFromAlias", () => {
|
|
155
|
-
it('returns "gpt-5.
|
|
156
|
-
expect(getModelFromAlias("openai:gpt-5.
|
|
155
|
+
it('returns "gpt-5.4" for "openai:gpt-5.4"', () => {
|
|
156
|
+
expect(getModelFromAlias("openai:gpt-5.4")).toBe("gpt-5.4");
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
it("handles multiple colons by rejoining segments after first", () => {
|
|
@@ -171,12 +171,27 @@ describe("getModelFromAlias", () => {
|
|
|
171
171
|
});
|
|
172
172
|
|
|
173
173
|
describe("getModelConfig", () => {
|
|
174
|
-
it('returns config for "openai:gpt-5.
|
|
175
|
-
const config = getModelConfig("openai:gpt-5.
|
|
174
|
+
it('returns config for "openai:gpt-5.4" with provider "openai"', () => {
|
|
175
|
+
const config = getModelConfig("openai:gpt-5.4");
|
|
176
176
|
expect(config).not.toBeNull();
|
|
177
177
|
expect(config!.provider).toBe("openai");
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
+
it("returns configs for Alibaba Qwen 3.6 models", () => {
|
|
181
|
+
expect(getModelConfig("alibaba:qwen3.6-flash")).toMatchObject({
|
|
182
|
+
provider: "alibaba",
|
|
183
|
+
model: "qwen3.6-flash",
|
|
184
|
+
});
|
|
185
|
+
expect(getModelConfig("alibaba:qwen3.6-plus")).toMatchObject({
|
|
186
|
+
provider: "alibaba",
|
|
187
|
+
model: "qwen3.6-plus",
|
|
188
|
+
});
|
|
189
|
+
expect(getModelConfig("alibaba:qwen3.6-max-preview")).toMatchObject({
|
|
190
|
+
provider: "alibaba",
|
|
191
|
+
model: "qwen3.6-max-preview",
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
180
195
|
it("returns null for unknown aliases", () => {
|
|
181
196
|
expect(getModelConfig("nonexistent:model")).toBeNull();
|
|
182
197
|
expect(getModelConfig("invalid")).toBeNull();
|
|
@@ -184,10 +199,20 @@ describe("getModelConfig", () => {
|
|
|
184
199
|
|
|
185
200
|
it("returns null for removed aliases", () => {
|
|
186
201
|
expect(getModelConfig("openai:gpt-4")).toBeNull();
|
|
202
|
+
expect(getModelConfig("openai:gpt-4o")).toBeNull();
|
|
203
|
+
expect(getModelConfig("openai:gpt-4o-mini")).toBeNull();
|
|
204
|
+
expect(getModelConfig("openai:gpt-5.2")).toBeNull();
|
|
205
|
+
expect(getModelConfig("openai:gpt-5.2-pro")).toBeNull();
|
|
206
|
+
expect(getModelConfig("openai:o3-mini")).toBeNull();
|
|
207
|
+
expect(getModelConfig("anthropic:haiku-4-6")).toBeNull();
|
|
208
|
+
expect(getModelConfig("deepseek:deepseek-chat")).toBeNull();
|
|
209
|
+
expect(getModelConfig("deepseek:deepseek-reasoner")).toBeNull();
|
|
187
210
|
expect(getModelConfig("deepseek:r1")).toBeNull();
|
|
211
|
+
expect(getModelConfig("moonshot:kimi-k1.5")).toBeNull();
|
|
188
212
|
expect(getModelConfig("moonshot:kimi-moonshot-v1-128k")).toBeNull();
|
|
189
213
|
expect(getModelConfig("gemini:flash-3")).toBeNull();
|
|
190
214
|
expect(getModelConfig("gemini:pro-3")).toBeNull();
|
|
215
|
+
expect(getModelConfig("zai:glm-5-code")).toBeNull();
|
|
191
216
|
expect(getModelConfig("zai:glm-4-plus")).toBeNull();
|
|
192
217
|
});
|
|
193
218
|
});
|
|
@@ -201,13 +226,21 @@ describe("FUNCTION_NAME_BY_ALIAS", () => {
|
|
|
201
226
|
expect(Object.isFrozen(FUNCTION_NAME_BY_ALIAS)).toBe(true);
|
|
202
227
|
});
|
|
203
228
|
|
|
204
|
-
it("has correct value for openai:gpt-5.
|
|
205
|
-
expect(FUNCTION_NAME_BY_ALIAS["openai:gpt-5.
|
|
229
|
+
it("has correct value for openai:gpt-5.4", () => {
|
|
230
|
+
expect(FUNCTION_NAME_BY_ALIAS["openai:gpt-5.4"]).toBe("gpt54");
|
|
206
231
|
});
|
|
207
232
|
|
|
208
233
|
it("has correct value for gemini:flash-2.5-lite", () => {
|
|
209
234
|
expect(FUNCTION_NAME_BY_ALIAS["gemini:flash-2.5-lite"]).toBe("flash25Lite");
|
|
210
235
|
});
|
|
236
|
+
|
|
237
|
+
it("has correct values for Alibaba Qwen 3.6 models", () => {
|
|
238
|
+
expect(FUNCTION_NAME_BY_ALIAS["alibaba:qwen3.6-flash"]).toBe("qwen36Flash");
|
|
239
|
+
expect(FUNCTION_NAME_BY_ALIAS["alibaba:qwen3.6-plus"]).toBe("qwen36Plus");
|
|
240
|
+
expect(FUNCTION_NAME_BY_ALIAS["alibaba:qwen3.6-max-preview"]).toBe(
|
|
241
|
+
"qwen36MaxPreview",
|
|
242
|
+
);
|
|
243
|
+
});
|
|
211
244
|
});
|
|
212
245
|
|
|
213
246
|
describe("PROVIDER_FUNCTIONS", () => {
|
|
@@ -238,6 +271,13 @@ describe("PROVIDER_FUNCTIONS", () => {
|
|
|
238
271
|
}
|
|
239
272
|
});
|
|
240
273
|
|
|
274
|
+
it("includes callable paths for Alibaba Qwen 3.6 models", () => {
|
|
275
|
+
const alibabaPaths = PROVIDER_FUNCTIONS.alibaba.map((entry) => entry.fullPath);
|
|
276
|
+
expect(alibabaPaths).toContain("llm.alibaba.qwen36Flash");
|
|
277
|
+
expect(alibabaPaths).toContain("llm.alibaba.qwen36Plus");
|
|
278
|
+
expect(alibabaPaths).toContain("llm.alibaba.qwen36MaxPreview");
|
|
279
|
+
});
|
|
280
|
+
|
|
241
281
|
it("is frozen (top-level)", () => {
|
|
242
282
|
expect(Object.isFrozen(PROVIDER_FUNCTIONS)).toBe(true);
|
|
243
283
|
});
|
package/src/config/models.ts
CHANGED
|
@@ -27,7 +27,11 @@ function deepFreeze<T>(obj: T): T {
|
|
|
27
27
|
if (obj === null || typeof obj !== "object") return obj;
|
|
28
28
|
Object.freeze(obj);
|
|
29
29
|
for (const value of Object.values(obj as object)) {
|
|
30
|
-
if (
|
|
30
|
+
if (
|
|
31
|
+
value !== null &&
|
|
32
|
+
typeof value === "object" &&
|
|
33
|
+
!Object.isFrozen(value)
|
|
34
|
+
) {
|
|
31
35
|
deepFreeze(value);
|
|
32
36
|
}
|
|
33
37
|
}
|
|
@@ -41,12 +45,12 @@ export const ModelAlias = Object.freeze({
|
|
|
41
45
|
OPENAI_GPT_4_1: "openai:gpt-4-1",
|
|
42
46
|
OPENAI_GPT_4_1_MINI: "openai:gpt-4-1-mini",
|
|
43
47
|
OPENAI_GPT_4_1_NANO: "openai:gpt-4-1-nano",
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
OPENAI_GPT_5_4: "openai:gpt-5.4",
|
|
49
|
+
OPENAI_GPT_5_4_MINI: "openai:gpt-5.4-mini",
|
|
50
|
+
OPENAI_GPT_5_4_NANO: "openai:gpt-5.4-nano",
|
|
51
|
+
OPENAI_GPT_5_5: "openai:gpt-5.5",
|
|
52
|
+
OPENAI_GPT_5_5_PRO: "openai:gpt-5.5-pro",
|
|
48
53
|
OPENAI_O3: "openai:o3",
|
|
49
|
-
OPENAI_O3_MINI: "openai:o3-mini",
|
|
50
54
|
OPENAI_O4_MINI: "openai:o4-mini",
|
|
51
55
|
// Anthropic
|
|
52
56
|
ANTHROPIC_OPUS_4_5: "anthropic:opus-4-5",
|
|
@@ -54,33 +58,42 @@ export const ModelAlias = Object.freeze({
|
|
|
54
58
|
ANTHROPIC_HAIKU_4_5: "anthropic:haiku-4-5",
|
|
55
59
|
ANTHROPIC_OPUS_4_6: "anthropic:opus-4-6",
|
|
56
60
|
ANTHROPIC_SONNET_4_6: "anthropic:sonnet-4-6",
|
|
57
|
-
|
|
61
|
+
ANTHROPIC_OPUS_4_7: "anthropic:opus-4-7",
|
|
58
62
|
// Gemini
|
|
59
63
|
GEMINI_FLASH_2_5: "gemini:flash-2.5",
|
|
60
64
|
GEMINI_FLASH_2_5_LITE: "gemini:flash-2.5-lite",
|
|
61
65
|
GEMINI_PRO_2_5: "gemini:pro-2.5",
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
GEMINI_PRO_3_1_PREVIEW: "gemini:pro-3.1-preview",
|
|
67
|
+
GEMINI_FLASH_3_PREVIEW: "gemini:flash-3-preview",
|
|
68
|
+
GEMINI_FLASH_3_1_LITE_PREVIEW: "gemini:flash-3.1-lite-preview",
|
|
69
|
+
// DeepSeek
|
|
70
|
+
DEEPSEEK_V4_FLASH: "deepseek:v4-flash",
|
|
71
|
+
DEEPSEEK_V4_PRO: "deepseek:v4-pro",
|
|
65
72
|
// Moonshot / Kimi
|
|
66
73
|
MOONSHOT_KIMI_K2_5: "moonshot:kimi-k2.5",
|
|
67
|
-
|
|
74
|
+
MOONSHOT_KIMI_K2_6: "moonshot:kimi-k2.6",
|
|
68
75
|
// Claude Code — subscription-based, zero token cost
|
|
69
76
|
CLAUDE_CODE_SONNET: "claude-code:sonnet",
|
|
70
77
|
CLAUDE_CODE_OPUS: "claude-code:opus",
|
|
71
78
|
CLAUDE_CODE_HAIKU: "claude-code:haiku",
|
|
72
79
|
// Z.ai
|
|
80
|
+
ZAI_GLM_5_1: "zai:glm-5-1",
|
|
73
81
|
ZAI_GLM_5: "zai:glm-5",
|
|
74
|
-
|
|
82
|
+
ZAI_GLM_5_TURBO: "zai:glm-5-turbo",
|
|
75
83
|
ZAI_GLM_4_7: "zai:glm-4-7",
|
|
76
84
|
ZAI_GLM_4_7_FLASH_X: "zai:glm-4-7-flash-x",
|
|
77
85
|
ZAI_GLM_4_6: "zai:glm-4-6",
|
|
78
86
|
ZAI_GLM_4_5: "zai:glm-4-5",
|
|
87
|
+
ZAI_GLM_4_5_X: "zai:glm-4-5-x",
|
|
79
88
|
ZAI_GLM_4_5_AIR: "zai:glm-4-5-air",
|
|
80
89
|
ZAI_GLM_4_5_AIR_X: "zai:glm-4-5-air-x",
|
|
81
|
-
// Alibaba (Qwen via DashScope)
|
|
90
|
+
// Alibaba (Qwen via DashScope, international/Singapore deployment)
|
|
91
|
+
ALIBABA_QWEN3_6_MAX_PREVIEW: "alibaba:qwen3.6-max-preview",
|
|
92
|
+
ALIBABA_QWEN3_6_PLUS: "alibaba:qwen3.6-plus",
|
|
93
|
+
ALIBABA_QWEN3_6_FLASH: "alibaba:qwen3.6-flash",
|
|
82
94
|
ALIBABA_QWEN3_MAX: "alibaba:qwen3-max",
|
|
83
95
|
ALIBABA_QWEN3_5_PLUS: "alibaba:qwen3.5-plus",
|
|
96
|
+
ALIBABA_QWEN3_5_FLASH: "alibaba:qwen3.5-flash",
|
|
84
97
|
ALIBABA_QWEN_PLUS: "alibaba:qwen-plus",
|
|
85
98
|
ALIBABA_QWEN_FLASH: "alibaba:qwen-flash",
|
|
86
99
|
ALIBABA_QWQ_PLUS: "alibaba:qwq-plus",
|
|
@@ -112,41 +125,41 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
112
125
|
tokenCostInPerMillion: 0.1,
|
|
113
126
|
tokenCostOutPerMillion: 0.4,
|
|
114
127
|
},
|
|
115
|
-
"openai:gpt-
|
|
128
|
+
"openai:gpt-5.4": {
|
|
116
129
|
provider: "openai",
|
|
117
|
-
model: "gpt-
|
|
130
|
+
model: "gpt-5.4",
|
|
118
131
|
tokenCostInPerMillion: 2.5,
|
|
119
|
-
tokenCostOutPerMillion:
|
|
132
|
+
tokenCostOutPerMillion: 15,
|
|
120
133
|
},
|
|
121
|
-
"openai:gpt-
|
|
134
|
+
"openai:gpt-5.4-mini": {
|
|
122
135
|
provider: "openai",
|
|
123
|
-
model: "gpt-
|
|
124
|
-
tokenCostInPerMillion: 0.
|
|
125
|
-
tokenCostOutPerMillion:
|
|
136
|
+
model: "gpt-5.4-mini",
|
|
137
|
+
tokenCostInPerMillion: 0.75,
|
|
138
|
+
tokenCostOutPerMillion: 4.5,
|
|
126
139
|
},
|
|
127
|
-
"openai:gpt-5.
|
|
140
|
+
"openai:gpt-5.4-nano": {
|
|
128
141
|
provider: "openai",
|
|
129
|
-
model: "gpt-5.
|
|
130
|
-
tokenCostInPerMillion: 2,
|
|
131
|
-
tokenCostOutPerMillion:
|
|
142
|
+
model: "gpt-5.4-nano",
|
|
143
|
+
tokenCostInPerMillion: 0.2,
|
|
144
|
+
tokenCostOutPerMillion: 1.25,
|
|
132
145
|
},
|
|
133
|
-
"openai:gpt-5.
|
|
146
|
+
"openai:gpt-5.5": {
|
|
134
147
|
provider: "openai",
|
|
135
|
-
model: "gpt-5.
|
|
136
|
-
tokenCostInPerMillion:
|
|
137
|
-
tokenCostOutPerMillion:
|
|
148
|
+
model: "gpt-5.5",
|
|
149
|
+
tokenCostInPerMillion: 5,
|
|
150
|
+
tokenCostOutPerMillion: 30,
|
|
138
151
|
},
|
|
139
|
-
"openai:
|
|
152
|
+
"openai:gpt-5.5-pro": {
|
|
140
153
|
provider: "openai",
|
|
141
|
-
model: "
|
|
142
|
-
tokenCostInPerMillion:
|
|
143
|
-
tokenCostOutPerMillion:
|
|
154
|
+
model: "gpt-5.5-pro",
|
|
155
|
+
tokenCostInPerMillion: 30,
|
|
156
|
+
tokenCostOutPerMillion: 180,
|
|
144
157
|
},
|
|
145
|
-
"openai:o3
|
|
158
|
+
"openai:o3": {
|
|
146
159
|
provider: "openai",
|
|
147
|
-
model: "o3
|
|
148
|
-
tokenCostInPerMillion:
|
|
149
|
-
tokenCostOutPerMillion:
|
|
160
|
+
model: "o3",
|
|
161
|
+
tokenCostInPerMillion: 2,
|
|
162
|
+
tokenCostOutPerMillion: 8,
|
|
150
163
|
},
|
|
151
164
|
"openai:o4-mini": {
|
|
152
165
|
provider: "openai",
|
|
@@ -185,13 +198,13 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
185
198
|
tokenCostInPerMillion: 3,
|
|
186
199
|
tokenCostOutPerMillion: 15,
|
|
187
200
|
},
|
|
188
|
-
"anthropic:
|
|
201
|
+
"anthropic:opus-4-7": {
|
|
189
202
|
provider: "anthropic",
|
|
190
|
-
model: "claude-
|
|
191
|
-
tokenCostInPerMillion:
|
|
192
|
-
tokenCostOutPerMillion:
|
|
203
|
+
model: "claude-opus-4-7",
|
|
204
|
+
tokenCostInPerMillion: 5,
|
|
205
|
+
tokenCostOutPerMillion: 25,
|
|
193
206
|
},
|
|
194
|
-
// Gemini
|
|
207
|
+
// Gemini — base (≤200k context) pricing for tiered models
|
|
195
208
|
"gemini:flash-2.5": {
|
|
196
209
|
provider: "gemini",
|
|
197
210
|
model: "gemini-2.5-flash",
|
|
@@ -210,31 +223,49 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
210
223
|
tokenCostInPerMillion: 1.25,
|
|
211
224
|
tokenCostOutPerMillion: 10,
|
|
212
225
|
},
|
|
226
|
+
"gemini:pro-3.1-preview": {
|
|
227
|
+
provider: "gemini",
|
|
228
|
+
model: "gemini-3.1-pro-preview",
|
|
229
|
+
tokenCostInPerMillion: 2,
|
|
230
|
+
tokenCostOutPerMillion: 12,
|
|
231
|
+
},
|
|
232
|
+
"gemini:flash-3-preview": {
|
|
233
|
+
provider: "gemini",
|
|
234
|
+
model: "gemini-3-flash-preview",
|
|
235
|
+
tokenCostInPerMillion: 0.5,
|
|
236
|
+
tokenCostOutPerMillion: 3,
|
|
237
|
+
},
|
|
238
|
+
"gemini:flash-3.1-lite-preview": {
|
|
239
|
+
provider: "gemini",
|
|
240
|
+
model: "gemini-3.1-flash-lite-preview",
|
|
241
|
+
tokenCostInPerMillion: 0.25,
|
|
242
|
+
tokenCostOutPerMillion: 1.5,
|
|
243
|
+
},
|
|
213
244
|
// DeepSeek — cache miss prices
|
|
214
|
-
"deepseek:
|
|
245
|
+
"deepseek:v4-flash": {
|
|
215
246
|
provider: "deepseek",
|
|
216
|
-
model: "deepseek-
|
|
217
|
-
tokenCostInPerMillion: 0.
|
|
218
|
-
tokenCostOutPerMillion: 0.
|
|
247
|
+
model: "deepseek-v4-flash",
|
|
248
|
+
tokenCostInPerMillion: 0.14,
|
|
249
|
+
tokenCostOutPerMillion: 0.28,
|
|
219
250
|
},
|
|
220
|
-
"deepseek:
|
|
251
|
+
"deepseek:v4-pro": {
|
|
221
252
|
provider: "deepseek",
|
|
222
|
-
model: "deepseek-
|
|
223
|
-
tokenCostInPerMillion:
|
|
224
|
-
tokenCostOutPerMillion:
|
|
253
|
+
model: "deepseek-v4-pro",
|
|
254
|
+
tokenCostInPerMillion: 1.74,
|
|
255
|
+
tokenCostOutPerMillion: 3.48,
|
|
225
256
|
},
|
|
226
|
-
// Moonshot / Kimi
|
|
257
|
+
// Moonshot / Kimi — cache miss prices
|
|
227
258
|
"moonshot:kimi-k2.5": {
|
|
228
259
|
provider: "moonshot",
|
|
229
260
|
model: "kimi-k2.5",
|
|
230
|
-
tokenCostInPerMillion: 0.
|
|
261
|
+
tokenCostInPerMillion: 0.6,
|
|
231
262
|
tokenCostOutPerMillion: 2.5,
|
|
232
263
|
},
|
|
233
|
-
"moonshot:kimi-
|
|
264
|
+
"moonshot:kimi-k2.6": {
|
|
234
265
|
provider: "moonshot",
|
|
235
|
-
model: "kimi-
|
|
236
|
-
tokenCostInPerMillion: 0.
|
|
237
|
-
tokenCostOutPerMillion:
|
|
266
|
+
model: "kimi-k2.6",
|
|
267
|
+
tokenCostInPerMillion: 0.95,
|
|
268
|
+
tokenCostOutPerMillion: 4,
|
|
238
269
|
},
|
|
239
270
|
// Claude Code — subscription-based, zero token cost
|
|
240
271
|
"claude-code:sonnet": {
|
|
@@ -256,17 +287,23 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
256
287
|
tokenCostOutPerMillion: 0,
|
|
257
288
|
},
|
|
258
289
|
// Z.ai
|
|
290
|
+
"zai:glm-5-1": {
|
|
291
|
+
provider: "zai",
|
|
292
|
+
model: "glm-5.1",
|
|
293
|
+
tokenCostInPerMillion: 1.4,
|
|
294
|
+
tokenCostOutPerMillion: 4.4,
|
|
295
|
+
},
|
|
259
296
|
"zai:glm-5": {
|
|
260
297
|
provider: "zai",
|
|
261
298
|
model: "glm-5",
|
|
262
299
|
tokenCostInPerMillion: 1,
|
|
263
300
|
tokenCostOutPerMillion: 3.2,
|
|
264
301
|
},
|
|
265
|
-
"zai:glm-5-
|
|
302
|
+
"zai:glm-5-turbo": {
|
|
266
303
|
provider: "zai",
|
|
267
|
-
model: "glm-5-
|
|
304
|
+
model: "glm-5-turbo",
|
|
268
305
|
tokenCostInPerMillion: 1.2,
|
|
269
|
-
tokenCostOutPerMillion:
|
|
306
|
+
tokenCostOutPerMillion: 4,
|
|
270
307
|
},
|
|
271
308
|
"zai:glm-4-7": {
|
|
272
309
|
provider: "zai",
|
|
@@ -292,6 +329,12 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
292
329
|
tokenCostInPerMillion: 0.6,
|
|
293
330
|
tokenCostOutPerMillion: 2.2,
|
|
294
331
|
},
|
|
332
|
+
"zai:glm-4-5-x": {
|
|
333
|
+
provider: "zai",
|
|
334
|
+
model: "glm-4.5-x",
|
|
335
|
+
tokenCostInPerMillion: 2.2,
|
|
336
|
+
tokenCostOutPerMillion: 8.9,
|
|
337
|
+
},
|
|
295
338
|
"zai:glm-4-5-air": {
|
|
296
339
|
provider: "zai",
|
|
297
340
|
model: "glm-4.5-air",
|
|
@@ -304,30 +347,54 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
304
347
|
tokenCostInPerMillion: 1.1,
|
|
305
348
|
tokenCostOutPerMillion: 4.5,
|
|
306
349
|
},
|
|
307
|
-
// Alibaba (Qwen via DashScope)
|
|
350
|
+
// Alibaba (Qwen via DashScope, international/Singapore deployment, base tier)
|
|
351
|
+
"alibaba:qwen3.6-max-preview": {
|
|
352
|
+
provider: "alibaba",
|
|
353
|
+
model: "qwen3.6-max-preview",
|
|
354
|
+
tokenCostInPerMillion: 1.3,
|
|
355
|
+
tokenCostOutPerMillion: 7.8,
|
|
356
|
+
},
|
|
357
|
+
"alibaba:qwen3.6-plus": {
|
|
358
|
+
provider: "alibaba",
|
|
359
|
+
model: "qwen3.6-plus",
|
|
360
|
+
tokenCostInPerMillion: 0.276,
|
|
361
|
+
tokenCostOutPerMillion: 1.651,
|
|
362
|
+
},
|
|
363
|
+
"alibaba:qwen3.6-flash": {
|
|
364
|
+
provider: "alibaba",
|
|
365
|
+
model: "qwen3.6-flash",
|
|
366
|
+
tokenCostInPerMillion: 0.025,
|
|
367
|
+
tokenCostOutPerMillion: 1.5,
|
|
368
|
+
},
|
|
308
369
|
"alibaba:qwen3-max": {
|
|
309
370
|
provider: "alibaba",
|
|
310
371
|
model: "qwen3-max",
|
|
311
|
-
tokenCostInPerMillion:
|
|
312
|
-
tokenCostOutPerMillion:
|
|
372
|
+
tokenCostInPerMillion: 1.2,
|
|
373
|
+
tokenCostOutPerMillion: 6,
|
|
313
374
|
},
|
|
314
375
|
"alibaba:qwen3.5-plus": {
|
|
315
376
|
provider: "alibaba",
|
|
316
377
|
model: "qwen3.5-plus",
|
|
317
|
-
tokenCostInPerMillion: 0.
|
|
318
|
-
tokenCostOutPerMillion:
|
|
378
|
+
tokenCostInPerMillion: 0.4,
|
|
379
|
+
tokenCostOutPerMillion: 2.4,
|
|
380
|
+
},
|
|
381
|
+
"alibaba:qwen3.5-flash": {
|
|
382
|
+
provider: "alibaba",
|
|
383
|
+
model: "qwen3.5-flash",
|
|
384
|
+
tokenCostInPerMillion: 0.1,
|
|
385
|
+
tokenCostOutPerMillion: 0.4,
|
|
319
386
|
},
|
|
320
387
|
"alibaba:qwen-plus": {
|
|
321
388
|
provider: "alibaba",
|
|
322
389
|
model: "qwen-plus",
|
|
323
|
-
tokenCostInPerMillion: 0.
|
|
324
|
-
tokenCostOutPerMillion:
|
|
390
|
+
tokenCostInPerMillion: 0.4,
|
|
391
|
+
tokenCostOutPerMillion: 1.2,
|
|
325
392
|
},
|
|
326
393
|
"alibaba:qwen-flash": {
|
|
327
394
|
provider: "alibaba",
|
|
328
395
|
model: "qwen-flash",
|
|
329
|
-
tokenCostInPerMillion: 0.
|
|
330
|
-
tokenCostOutPerMillion: 0.
|
|
396
|
+
tokenCostInPerMillion: 0.05,
|
|
397
|
+
tokenCostOutPerMillion: 0.4,
|
|
331
398
|
},
|
|
332
399
|
"alibaba:qwq-plus": {
|
|
333
400
|
provider: "alibaba",
|
|
@@ -338,19 +405,21 @@ const MODEL_CONFIG_RAW: Record<ModelAliasKey, ModelConfigEntry> = {
|
|
|
338
405
|
"alibaba:qwen3-coder-plus": {
|
|
339
406
|
provider: "alibaba",
|
|
340
407
|
model: "qwen3-coder-plus",
|
|
341
|
-
tokenCostInPerMillion:
|
|
342
|
-
tokenCostOutPerMillion:
|
|
408
|
+
tokenCostInPerMillion: 1,
|
|
409
|
+
tokenCostOutPerMillion: 5,
|
|
343
410
|
},
|
|
344
411
|
"alibaba:qwen3-coder-flash": {
|
|
345
412
|
provider: "alibaba",
|
|
346
413
|
model: "qwen3-coder-flash",
|
|
347
|
-
tokenCostInPerMillion: 0.
|
|
348
|
-
tokenCostOutPerMillion:
|
|
414
|
+
tokenCostInPerMillion: 0.3,
|
|
415
|
+
tokenCostOutPerMillion: 1.5,
|
|
349
416
|
},
|
|
350
417
|
};
|
|
351
418
|
|
|
352
419
|
export const MODEL_CONFIG: Readonly<Record<ModelAliasKey, ModelConfigEntry>> =
|
|
353
|
-
deepFreeze(MODEL_CONFIG_RAW) as Readonly<
|
|
420
|
+
deepFreeze(MODEL_CONFIG_RAW) as Readonly<
|
|
421
|
+
Record<ModelAliasKey, ModelConfigEntry>
|
|
422
|
+
>;
|
|
354
423
|
|
|
355
424
|
export const VALID_MODEL_ALIASES: ReadonlySet<ModelAliasKey> = new Set(
|
|
356
425
|
Object.keys(MODEL_CONFIG) as ModelAliasKey[],
|
|
@@ -360,18 +429,24 @@ export const VALID_MODEL_ALIASES: ReadonlySet<ModelAliasKey> = new Set(
|
|
|
360
429
|
|
|
361
430
|
export function aliasToFunctionName(alias: string): string {
|
|
362
431
|
if (typeof alias !== "string") {
|
|
363
|
-
throw new Error(
|
|
432
|
+
throw new Error(
|
|
433
|
+
`Invalid model alias: expected string, got ${typeof alias}`,
|
|
434
|
+
);
|
|
364
435
|
}
|
|
365
436
|
if (!alias.includes(":")) {
|
|
366
437
|
throw new Error(`Invalid model alias: "${alias}" does not contain a colon`);
|
|
367
438
|
}
|
|
368
439
|
const model = alias.split(":").slice(1).join(":");
|
|
369
|
-
return model.replace(/[-.]([a-z0-9])/gi, (_, char: string) =>
|
|
440
|
+
return model.replace(/[-.]([a-z0-9])/gi, (_, char: string) =>
|
|
441
|
+
char.toUpperCase(),
|
|
442
|
+
);
|
|
370
443
|
}
|
|
371
444
|
|
|
372
445
|
export function getProviderFromAlias(alias: string): ProviderName {
|
|
373
446
|
if (typeof alias !== "string") {
|
|
374
|
-
throw new Error(
|
|
447
|
+
throw new Error(
|
|
448
|
+
`Invalid model alias: expected string, got ${typeof alias}`,
|
|
449
|
+
);
|
|
375
450
|
}
|
|
376
451
|
if (!alias.includes(":")) {
|
|
377
452
|
throw new Error(`Invalid model alias: "${alias}" does not contain a colon`);
|
|
@@ -381,7 +456,9 @@ export function getProviderFromAlias(alias: string): ProviderName {
|
|
|
381
456
|
|
|
382
457
|
export function getModelFromAlias(alias: string): string {
|
|
383
458
|
if (typeof alias !== "string") {
|
|
384
|
-
throw new Error(
|
|
459
|
+
throw new Error(
|
|
460
|
+
`Invalid model alias: expected string, got ${typeof alias}`,
|
|
461
|
+
);
|
|
385
462
|
}
|
|
386
463
|
if (!alias.includes(":")) {
|
|
387
464
|
throw new Error(`Invalid model alias: "${alias}" does not contain a colon`);
|
|
@@ -390,33 +467,38 @@ export function getModelFromAlias(alias: string): string {
|
|
|
390
467
|
}
|
|
391
468
|
|
|
392
469
|
export function getModelConfig(alias: string): ModelConfigEntry | null {
|
|
393
|
-
return (
|
|
470
|
+
return (
|
|
471
|
+
(MODEL_CONFIG as Record<string, ModelConfigEntry | undefined>)[alias] ??
|
|
472
|
+
null
|
|
473
|
+
);
|
|
394
474
|
}
|
|
395
475
|
|
|
396
476
|
// ─── Default Model By Provider ───────────────────────────────────────────────
|
|
397
477
|
|
|
398
|
-
export const DEFAULT_MODEL_BY_PROVIDER: Readonly<
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
478
|
+
export const DEFAULT_MODEL_BY_PROVIDER: Readonly<
|
|
479
|
+
Record<ProviderName, ModelAliasKey>
|
|
480
|
+
> = Object.freeze({
|
|
481
|
+
openai: "openai:gpt-5.4",
|
|
482
|
+
anthropic: "anthropic:sonnet-4-6",
|
|
483
|
+
gemini: "gemini:flash-2.5",
|
|
484
|
+
deepseek: "deepseek:v4-flash",
|
|
485
|
+
moonshot: "moonshot:kimi-k2.6",
|
|
486
|
+
"claude-code": "claude-code:sonnet",
|
|
487
|
+
zai: "zai:glm-5-1",
|
|
488
|
+
alibaba: "alibaba:qwen3-max",
|
|
489
|
+
} as const);
|
|
409
490
|
|
|
410
491
|
// ─── Function Name Derived Index ─────────────────────────────────────────────
|
|
411
492
|
|
|
412
|
-
export const FUNCTION_NAME_BY_ALIAS: Readonly<Record<ModelAliasKey, string>> =
|
|
413
|
-
Object.
|
|
414
|
-
|
|
415
|
-
alias
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
)
|
|
493
|
+
export const FUNCTION_NAME_BY_ALIAS: Readonly<Record<ModelAliasKey, string>> =
|
|
494
|
+
Object.freeze(
|
|
495
|
+
Object.fromEntries(
|
|
496
|
+
(Object.keys(MODEL_CONFIG) as ModelAliasKey[]).map((alias) => [
|
|
497
|
+
alias,
|
|
498
|
+
aliasToFunctionName(alias),
|
|
499
|
+
]),
|
|
500
|
+
) as Record<ModelAliasKey, string>,
|
|
501
|
+
);
|
|
420
502
|
|
|
421
503
|
// ─── Provider Functions Index ────────────────────────────────────────────────
|
|
422
504
|
|
|
@@ -438,7 +520,13 @@ export function buildProviderFunctionsIndex(): ProviderFunctionsIndex {
|
|
|
438
520
|
index[provider] = [];
|
|
439
521
|
}
|
|
440
522
|
index[provider]!.push(
|
|
441
|
-
Object.freeze({
|
|
523
|
+
Object.freeze({
|
|
524
|
+
alias,
|
|
525
|
+
provider,
|
|
526
|
+
model,
|
|
527
|
+
functionName,
|
|
528
|
+
fullPath,
|
|
529
|
+
}) as ProviderFunctionEntry,
|
|
442
530
|
);
|
|
443
531
|
}
|
|
444
532
|
|
|
@@ -450,7 +538,8 @@ export function buildProviderFunctionsIndex(): ProviderFunctionsIndex {
|
|
|
450
538
|
return Object.freeze(index) as ProviderFunctionsIndex;
|
|
451
539
|
}
|
|
452
540
|
|
|
453
|
-
export const PROVIDER_FUNCTIONS: ProviderFunctionsIndex =
|
|
541
|
+
export const PROVIDER_FUNCTIONS: ProviderFunctionsIndex =
|
|
542
|
+
buildProviderFunctionsIndex();
|
|
454
543
|
|
|
455
544
|
// ─── Module-Load Invariant Validation ────────────────────────────────────────
|
|
456
545
|
|
|
@@ -497,13 +586,19 @@ export function validateModelRegistry(
|
|
|
497
586
|
}
|
|
498
587
|
|
|
499
588
|
// Check non-negative token costs
|
|
500
|
-
if (
|
|
589
|
+
if (
|
|
590
|
+
typeof entry.tokenCostInPerMillion !== "number" ||
|
|
591
|
+
entry.tokenCostInPerMillion < 0
|
|
592
|
+
) {
|
|
501
593
|
throw new Error(
|
|
502
594
|
`Model config invariant violation: alias "${alias}" has invalid tokenCostInPerMillion: ` +
|
|
503
595
|
`${entry.tokenCostInPerMillion}`,
|
|
504
596
|
);
|
|
505
597
|
}
|
|
506
|
-
if (
|
|
598
|
+
if (
|
|
599
|
+
typeof entry.tokenCostOutPerMillion !== "number" ||
|
|
600
|
+
entry.tokenCostOutPerMillion < 0
|
|
601
|
+
) {
|
|
507
602
|
throw new Error(
|
|
508
603
|
`Model config invariant violation: alias "${alias}" has invalid tokenCostOutPerMillion: ` +
|
|
509
604
|
`${entry.tokenCostOutPerMillion}`,
|