@lingjingai/scriptctl 0.63.1 → 0.63.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ # 0.63.2
2
+
3
+ - Gemini 视频请求固定使用配置的模型与服务,在当前路由内有限重试,失败时直接返回原因。
4
+ - 修复内置 Mastra 审核的 Google API 地址拼接,服务根地址和 /v1beta 地址均可正确请求。
package/dist/bin.js CHANGED
@@ -265,23 +265,6 @@ function contextOf(failure) {
265
265
  ...failure.details !== void 0 ? { details: failure.details } : {}
266
266
  };
267
267
  }
268
- function aggregateFailures(failures, message2) {
269
- if (failures.length === 0) {
270
- return createOperationalFailure(
271
- { failure_type: "unknown", failure_code: "unknown" },
272
- { retryable: false, message: message2 }
273
- );
274
- }
275
- const first = failures[0];
276
- const sameClassification = failures.every(
277
- (failure) => failure.failure_type === first.failure_type && failure.failure_code === first.failure_code
278
- );
279
- const classification = sameClassification ? classificationOf(first) : { failure_type: "provider", failure_code: "attempts_exhausted" };
280
- return createOperationalFailure(classification, {
281
- retryable: failures.some((failure) => failure.retryable),
282
- message: message2
283
- });
284
- }
285
268
  function formatFailure(failure) {
286
269
  const route = failure.provider || failure.model ? `${failure.provider ?? "provider"}/${failure.model ?? "model"} ` : "";
287
270
  const reason = failure.provider_reason ? ` provider_reason=${failure.provider_reason}` : "";
@@ -7794,10 +7777,6 @@ var OpenAiCompatibleModel = class {
7794
7777
  };
7795
7778
 
7796
7779
  // src/llm/router.ts
7797
- var VIDEO_FALLBACK_MODELS = ["gemini-3.7-flash"];
7798
- var PROXY_GEMINI_MODELS = [];
7799
- var PROXY_GEMINI_API_KEY_ENVS = ["GEMINI_PROXY_API_KEY", "REDRAW_GEMINI_PROXY_API_KEY"];
7800
- var PROXY_GEMINI_BASE_URL_ENVS = ["GEMINI_PROXY_BASE_URL", "REDRAW_GEMINI_PROXY_BASE_URL"];
7801
7780
  var DOUBAO_FALLBACK = {
7802
7781
  model: "ep-20260721150136-98dj9",
7803
7782
  modelEnv: "ARK_MODEL",
@@ -7837,26 +7816,6 @@ function credentialError(provider) {
7837
7816
  data: { expected: ["credential environment variable referenced by the selected provider"], actual: [`provider: ${provider}`, "credential: missing"] }
7838
7817
  });
7839
7818
  }
7840
- function routedFailure(error, route) {
7841
- if (error instanceof LlmTransportError) {
7842
- return createOperationalFailure(classificationOf(error.failure), {
7843
- ...contextOf(error.failure),
7844
- provider: route.provider,
7845
- model: route.model,
7846
- retryable: error.failure.retryable,
7847
- message: error.failure.message
7848
- });
7849
- }
7850
- return createOperationalFailure(
7851
- { failure_type: "unknown", failure_code: "unknown" },
7852
- {
7853
- provider: route.provider,
7854
- model: route.model,
7855
- retryable: false,
7856
- message: error instanceof Error ? error.message : String(error)
7857
- }
7858
- );
7859
- }
7860
7819
  var ModelRouter = class {
7861
7820
  constructor(config, options = {}) {
7862
7821
  this.config = config;
@@ -8027,52 +7986,6 @@ var ModelRouter = class {
8027
7986
  throw error;
8028
7987
  }
8029
7988
  }
8030
- videoRoute(route, model) {
8031
- const modelConfig = model === route.info.model ? route.modelConfig : { ...route.modelConfig, model };
8032
- return {
8033
- ...route.info,
8034
- model,
8035
- fingerprint: routeFingerprint(route.info.task, route.providerConfig, modelConfig)
8036
- };
8037
- }
8038
- resolvedVideoRoute(route, model) {
8039
- const modelConfig = model === route.info.model ? route.modelConfig : { ...route.modelConfig, model };
8040
- return {
8041
- info: this.videoRoute(route, model),
8042
- providerConfig: route.providerConfig,
8043
- modelConfig
8044
- };
8045
- }
8046
- proxyVideoRoutes(task) {
8047
- if (this.options.videoProvider) return [];
8048
- const apiKeyEnv = PROXY_GEMINI_API_KEY_ENVS.find((name) => (process.env[name] ?? "").trim());
8049
- const baseUrlEnv = PROXY_GEMINI_BASE_URL_ENVS.find((name) => (process.env[name] ?? "").trim());
8050
- if (!apiKeyEnv || !baseUrlEnv) return [];
8051
- const baseUrl = normalizeProviderBaseUrl(process.env[baseUrlEnv], baseUrlEnv);
8052
- return PROXY_GEMINI_MODELS.map((model, index) => {
8053
- const providerConfig = {
8054
- protocol: "google-gemini",
8055
- baseUrl,
8056
- apiKeyEnv,
8057
- timeoutMs: 9e4,
8058
- maxAttempts: index < 2 ? 2 : 1
8059
- };
8060
- const modelConfig = { provider: "gemini-proxy", model };
8061
- return {
8062
- info: {
8063
- task,
8064
- profile: "gemini-proxy",
8065
- provider: "gemini-proxy",
8066
- protocol: "google-gemini",
8067
- baseUrl,
8068
- model,
8069
- fingerprint: routeFingerprint(task, providerConfig, modelConfig)
8070
- },
8071
- providerConfig,
8072
- modelConfig
8073
- };
8074
- });
8075
- }
8076
7989
  resolveDoubao(task, explicit) {
8077
7990
  const overrides = explicit ? this.options.videoProvider : void 0;
8078
7991
  const modelName = explicit ? (overrides?.model ?? process.env["ARK_MODEL"] ?? "").trim() : this.doubaoModel();
@@ -8114,9 +8027,7 @@ var ModelRouter = class {
8114
8027
  this.adapters.set(key, adapter);
8115
8028
  return adapter;
8116
8029
  }
8117
- // model defaults to the route's model; pass an override to build a peer adapter
8118
- // that shares the provider/credential but targets a fallback model.
8119
- videoAdapter(route, model) {
8030
+ videoAdapter(route) {
8120
8031
  if (route.providerConfig.protocol !== "google-gemini") {
8121
8032
  throw configRuntimeError(
8122
8033
  "Video tasks require a google-gemini provider.",
@@ -8124,14 +8035,13 @@ var ModelRouter = class {
8124
8035
  [`provider: ${route.info.provider}`, `protocol: ${route.providerConfig.protocol}`]
8125
8036
  );
8126
8037
  }
8127
- const modelName = model ?? route.info.model;
8038
+ const modelName = route.info.model;
8128
8039
  const key = `${route.info.provider} ${route.providerConfig.baseUrl ?? "official"} ${modelName}`;
8129
8040
  const cached2 = this.videoAdapters.get(key);
8130
8041
  if (cached2) return cached2;
8131
8042
  const apiKey = this.videoCredential(route);
8132
8043
  if (!apiKey) throw credentialError(route.info.provider);
8133
- const modelConfig = model ? { ...route.modelConfig, model } : route.modelConfig;
8134
- const adapter = new GeminiVideoModel(route.providerConfig, modelConfig, apiKey);
8044
+ const adapter = new GeminiVideoModel(route.providerConfig, route.modelConfig, apiKey);
8135
8045
  this.videoAdapters.set(key, adapter);
8136
8046
  return adapter;
8137
8047
  }
@@ -8146,8 +8056,8 @@ var ModelRouter = class {
8146
8056
  if (spec2.mode !== "video") throw configRuntimeError("The task does not support video generation.", ["video task"], [`task: ${task}`]);
8147
8057
  const route = this.resolve(task);
8148
8058
  if (this.options.videoProvider?.provider === "doubao") {
8149
- const adapter = this.doubaoAdapter(route);
8150
- if (!adapter) throw credentialError("doubao");
8059
+ const adapter2 = this.doubaoAdapter(route);
8060
+ if (!adapter2) throw credentialError("doubao");
8151
8061
  return {
8152
8062
  prepare: async (localPath, mimeType, mode, signal) => {
8153
8063
  if (mode !== "file-api") {
@@ -8162,7 +8072,7 @@ var ModelRouter = class {
8162
8072
  }
8163
8073
  request2.signal?.throwIfAborted();
8164
8074
  const { path: localPath, mimeType: localMime } = request2.media;
8165
- return this.tracked(route.info, () => adapter.run({
8075
+ return this.tracked(route.info, () => adapter2.run({
8166
8076
  localPath,
8167
8077
  localMime,
8168
8078
  user: request2.user,
@@ -8184,88 +8094,17 @@ var ModelRouter = class {
8184
8094
  [`provider: ${route.info.provider}`, `protocol: ${route.providerConfig.protocol}`]
8185
8095
  );
8186
8096
  }
8187
- const officialRoutes = (this.options.videoProvider ? [route.info.model] : [route.info.model, ...VIDEO_FALLBACK_MODELS.filter((m) => m !== route.info.model)]).map((model) => this.resolvedVideoRoute(route, model));
8188
- const proxyRoutes = this.proxyVideoRoutes(task);
8189
- if (this.options.videoProvider || proxyRoutes.length === 0) void this.videoAdapter(route);
8097
+ const adapter = this.videoAdapter(route);
8190
8098
  return {
8191
- prepare: async (localPath, mimeType, mode, signal) => {
8192
- const prepareRoute = mode === "base64" && proxyRoutes.length > 0 ? proxyRoutes[0] : route;
8193
- try {
8194
- return await this.videoAdapter(prepareRoute).prepare(localPath, mimeType, mode, signal);
8195
- } catch (error) {
8196
- if (signal?.aborted || mode !== "file-api" || this.options.videoProvider || !this.doubaoAdapter()) throw error;
8197
- const failure = routedFailure(error, route.info);
8198
- process.stderr.write(`\u21AA\uFE0F Gemini \u6587\u4EF6\u4E0A\u4F20\u5931\u8D25,\u6539\u7531\u8C46\u5305\u8BFB\u53D6\u672C\u5730\u89C6\u9891 (${formatFailure(failure)})
8199
- `);
8200
- return { kind: "local-fallback", path: localPath, mimeType, primaryFailure: failure };
8201
- }
8202
- },
8203
- release: (media, signal) => media.kind === "base64" || media.kind === "local-fallback" ? Promise.resolve() : this.videoAdapter(route).release(media, signal),
8204
- generate: async (request2) => {
8205
- const failures = request2.media.kind === "local-fallback" ? [request2.media.primaryFailure] : [];
8206
- const skipped = [];
8207
- const geminiChain = request2.media.kind === "local-fallback" ? [] : request2.media.kind === "base64" ? [...proxyRoutes, ...officialRoutes] : officialRoutes;
8208
- for (const [index, attemptRoute] of geminiChain.entries()) {
8209
- try {
8210
- const response = await this.tracked(
8211
- attemptRoute.info,
8212
- () => this.videoAdapter(attemptRoute).generate({ ...request2, maxOutputTokens: spec2.maxOutputTokens })
8213
- );
8214
- if (index > 0) process.stderr.write(`\u21AA\uFE0F \u5DF2\u5207\u6362\u5230\u5907\u7528\u6A21\u578B ${attemptRoute.info.model}
8215
- `);
8216
- return response;
8217
- } catch (error) {
8218
- if (request2.signal?.aborted) throw error;
8219
- const failure = routedFailure(error, attemptRoute.info);
8220
- failures.push(failure);
8221
- const detail = formatFailure(failure);
8222
- if (index < geminiChain.length - 1) {
8223
- process.stderr.write(`\u21AA\uFE0F ${attemptRoute.info.model} \u5F53\u524D\u4E0D\u53EF\u7528\uFF0C\u5207\u6362\u4E0B\u4E00\u7EBF\u8DEF (${detail})
8224
- `);
8225
- }
8226
- }
8227
- }
8228
- const doubao = this.options.videoProvider ? null : this.doubaoAdapter();
8229
- const localPath = request2.media.kind === "local-fallback" ? request2.media.path : request2.localPath;
8230
- if (doubao && localPath) {
8231
- const attemptRoute = this.doubaoRoute(task);
8232
- try {
8233
- process.stderr.write(`\u21AA\uFE0F Gemini \u5168\u90E8\u5931\u8D25,\u56DE\u9000\u5230\u8C46\u5305 ${this.doubaoModel()}
8234
- `);
8235
- const response = await this.tracked(attemptRoute, () => doubao.run({
8236
- localPath,
8237
- localMime: request2.media.kind === "local-fallback" ? request2.media.mimeType : request2.localMime ?? "video/mp4",
8238
- user: request2.user,
8239
- fps: request2.fps,
8240
- maxOutputTokens: spec2.maxOutputTokens,
8241
- ...request2.system ? { system: request2.system } : {},
8242
- ...request2.responseJsonSchema ? { responseJsonSchema: request2.responseJsonSchema } : {},
8243
- ...request2.signal ? { signal: request2.signal } : {}
8244
- }));
8245
- return response;
8246
- } catch (error) {
8247
- if (request2.signal?.aborted) throw error;
8248
- failures.push(routedFailure(error, attemptRoute));
8249
- }
8250
- } else if (!doubao) {
8251
- if (!this.options.videoProvider) {
8252
- skipped.push("doubao: skipped (ARK_API_KEY not set)");
8253
- }
8254
- } else {
8255
- skipped.push("doubao: skipped (no local file to re-upload)");
8256
- }
8257
- const aggregate = aggregateFailures(failures, "All configured video model attempts failed.");
8258
- throw new LlmTransportError("request_failed", aggregate.message, {
8259
- retryable: aggregate.retryable,
8260
- classification: classificationOf(aggregate),
8261
- context: contextOf(aggregate),
8262
- modelFailures: failures,
8263
- details: [...failures.map(formatFailure), ...skipped]
8264
- });
8265
- }
8099
+ prepare: (localPath, mimeType, mode, signal) => adapter.prepare(localPath, mimeType, mode, signal),
8100
+ release: (media, signal) => adapter.release(media, signal),
8101
+ generate: (request2) => this.tracked(route.info, () => adapter.generate({
8102
+ ...request2,
8103
+ maxOutputTokens: spec2.maxOutputTokens
8104
+ }))
8266
8105
  };
8267
8106
  }
8268
- // Resolve an explicit Doubao route or the default fallback; absent fallback credentials skip it.
8107
+ // Resolve explicitly selected Doubao video.
8269
8108
  // Overridable in tests to inject a fake Ark client.
8270
8109
  doubaoAdapter(route) {
8271
8110
  return this.arkAdapter(route);