@acosmi/sdk-ts 2.19.4 → 2.19.5

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.
@@ -150,6 +150,14 @@ var init_types = __esm({
150
150
  });
151
151
 
152
152
  // src/shared/errors.ts
153
+ function finiteNonNegative(value) {
154
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
155
+ }
156
+ function isStreamError(err) {
157
+ if (err == null || typeof err !== "object") return false;
158
+ const e = err;
159
+ return e.name === "StreamError" && typeof e.errorCode === "string";
160
+ }
153
161
  function nullableID(value) {
154
162
  return value === null || typeof value === "string";
155
163
  }
@@ -359,8 +367,23 @@ var init_errors = __esm({
359
367
  userMessage;
360
368
  /** gateway 原始 error 字符串 */
361
369
  rawError;
362
- /** 客户端是否值得重试 */
370
+ /** 客户端是否值得重试 (= 服务端 `retryable` **且** `requestDisposition === 'not_accepted'`) */
363
371
  retryable;
372
+ /**
373
+ * 服务端在帧上声明的 `retryable` **原值** (2.19.5 起) —— 不与 requestDisposition 合取,
374
+ * 缺席即 undefined。
375
+ *
376
+ * 为什么要并列存一份: 上面的 `retryable` 是两个判据的合取, 网关的流内错误帧并不总是
377
+ * 下发 `requestDisposition`, 于是"服务端明说可重试"会被合取成 false —— 两端各自正确,
378
+ * 合起来恒否。消费方要区分**「服务端明说不可重试」**(false, 一票否决) 与**「服务端没说」**
379
+ * (undefined, 回落到自己的本地分类表) 时, 只能读这个原值; 读 `retryable` 两种情形不可分。
380
+ */
381
+ serverRetryable;
382
+ /**
383
+ * 服务端建议的等待秒数 (2.19.5 起)。**有限非负数**才收, 其余 (null / 负数 /
384
+ * NaN / Infinity / 非数字) 一律 undefined —— 宁可不给, 绝不编造等待时间。
385
+ */
386
+ retryAfterSecs;
364
387
  errorContractVersion;
365
388
  faultDomain;
366
389
  requestDisposition;
@@ -383,6 +406,8 @@ var init_errors = __esm({
383
406
  this.userMessage = userMessage;
384
407
  this.rawError = rawError;
385
408
  this.retryable = retryable;
409
+ this.serverRetryable = opts.retryable;
410
+ this.retryAfterSecs = finiteNonNegative(opts.retryAfterSecs);
386
411
  this.errorContractVersion = opts.errorContractVersion;
387
412
  this.faultDomain = opts.faultDomain;
388
413
  this.requestDisposition = opts.requestDisposition;
@@ -2197,7 +2222,10 @@ var FileTokenStore = class {
2197
2222
  /**
2198
2223
  * 跨进程临界区. 用 sidecar `<path>.lock` 文件 + O_EXCL 创建语义实现互斥:
2199
2224
  * - 创建成功 = 持有锁; 写入 pid+timestamp 便于诊断
2200
- * - 创建失败 (EEXIST) = 别的进程持锁, backoff 重试
2225
+ * - 创建失败 (EEXIST) = 别的进程持锁, stale 检测后 backoff 重试
2226
+ * - 创建失败 (Windows 的 EPERM / EBUSY) = 前一持有者的 unlink 处于 delete-pending,
2227
+ * 同属争用; 跳过 stale 检测直接 backoff 重试 (见 catch 内注释)。EACCES 不在其中 —
2228
+ * 它是真权限错误, 立即抛
2201
2229
  * - 锁文件 mtime > staleMs = 进程崩溃残留, unlink 后重试
2202
2230
  * - acquireTimeoutMs 超时 = 抛错 (caller 应作为 transient error 处理, 上层 retry)
2203
2231
  *
@@ -2231,20 +2259,22 @@ ${Date.now()}
2231
2259
  };
2232
2260
  break;
2233
2261
  } catch (e) {
2234
- if (!isAlreadyExistsError(e)) throw e;
2235
- let stale = false;
2236
- try {
2237
- const st = await fs.stat(lockPath);
2238
- if (Date.now() - st.mtimeMs > fileLockDefaults.staleMs) stale = true;
2239
- } catch {
2240
- continue;
2241
- }
2242
- if (stale) {
2262
+ if (!isLockContendedError(e)) throw e;
2263
+ if (!isWindowsLockBusyError(e)) {
2264
+ let stale = false;
2243
2265
  try {
2244
- await fs.unlink(lockPath);
2266
+ const st = await fs.stat(lockPath);
2267
+ if (Date.now() - st.mtimeMs > fileLockDefaults.staleMs) stale = true;
2245
2268
  } catch {
2269
+ continue;
2270
+ }
2271
+ if (stale) {
2272
+ try {
2273
+ await fs.unlink(lockPath);
2274
+ } catch {
2275
+ }
2276
+ continue;
2246
2277
  }
2247
- continue;
2248
2278
  }
2249
2279
  if (Date.now() - startMs > fileLockDefaults.acquireTimeoutMs) {
2250
2280
  throw new Error(
@@ -2350,6 +2380,15 @@ function isNotExistError(e) {
2350
2380
  }
2351
2381
  return false;
2352
2382
  }
2383
+ function isWindowsLockBusyError(e) {
2384
+ if (typeof process === "undefined" || process.platform !== "win32") return false;
2385
+ if (typeof e !== "object" || e === null || !("code" in e)) return false;
2386
+ const code = e.code;
2387
+ return code === "EPERM" || code === "EBUSY";
2388
+ }
2389
+ function isLockContendedError(e) {
2390
+ return isAlreadyExistsError(e) || isWindowsLockBusyError(e);
2391
+ }
2353
2392
  function isAlreadyExistsError(e) {
2354
2393
  if (typeof e === "object" && e !== null && "code" in e) {
2355
2394
  return e.code === "EEXIST";
@@ -2943,7 +2982,7 @@ function parseStreamError(data) {
2943
2982
  let code = payload.errorCode ?? "";
2944
2983
  const stage = payload.stage ?? "";
2945
2984
  let message = payload.message ?? "";
2946
- const retryable = payload.retryable ?? false;
2985
+ const retryable = payload.retryable;
2947
2986
  let rawError = "";
2948
2987
  if (payload.error != null) {
2949
2988
  if (typeof payload.error === "string") {
@@ -2961,6 +3000,7 @@ function parseStreamError(data) {
2961
3000
  message,
2962
3001
  rawError,
2963
3002
  retryable,
3003
+ retryAfterSecs: payload.retryAfterSecs,
2964
3004
  errorContractVersion: payload.errorContractVersion,
2965
3005
  faultDomain: payload.faultDomain,
2966
3006
  requestDisposition: payload.requestDisposition,
@@ -3171,6 +3211,25 @@ function notifyGatewayRequestID(cb, headers) {
3171
3211
  } catch {
3172
3212
  }
3173
3213
  }
3214
+ function notifyResponseHeaders(cb, headers) {
3215
+ if (!cb) return;
3216
+ try {
3217
+ cb(headers);
3218
+ } catch {
3219
+ }
3220
+ }
3221
+ function armStreamRequestTimeout(opts, parent) {
3222
+ const ms = opts?.requestTimeoutMs;
3223
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms <= 0) return void 0;
3224
+ return withRequestTimeout(ms, parent);
3225
+ }
3226
+ async function* disposeTimeoutWhenSettled(inner, ctl) {
3227
+ try {
3228
+ yield* inner;
3229
+ } finally {
3230
+ ctl.dispose();
3231
+ }
3232
+ }
3174
3233
  var DEFAULT_API_TIMEOUT_MS = 6e4;
3175
3234
  function newDeferred() {
3176
3235
  let resolve;
@@ -4304,10 +4363,23 @@ var Client = class _Client {
4304
4363
  *
4305
4364
  * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
4306
4365
  * @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
4366
+ * @param opts 见 {@link ChatStreamOptions} (2.19.5 起)
4307
4367
  */
4308
- chatStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
4368
+ chatStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID, opts) {
4309
4369
  return {
4310
- [Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
4370
+ [Symbol.asyncIterator]: () => {
4371
+ const ctl = armStreamRequestTimeout(opts, signal);
4372
+ const inner = this.chatStreamGen(
4373
+ modelID,
4374
+ req,
4375
+ ctl?.signal ?? signal,
4376
+ false,
4377
+ onUpstreamActivity,
4378
+ onGatewayRequestID,
4379
+ opts?.onResponseHeaders
4380
+ );
4381
+ return ctl ? disposeTimeoutWhenSettled(inner, ctl) : inner;
4382
+ }
4311
4383
  };
4312
4384
  }
4313
4385
  /**
@@ -4317,13 +4389,26 @@ var Client = class _Client {
4317
4389
  *
4318
4390
  * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
4319
4391
  * @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
4392
+ * @param opts 见 {@link ChatStreamOptions} (2.19.5 起)
4320
4393
  */
4321
- chatMessagesStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
4394
+ chatMessagesStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID, opts) {
4322
4395
  return {
4323
- [Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
4396
+ [Symbol.asyncIterator]: () => {
4397
+ const ctl = armStreamRequestTimeout(opts, signal);
4398
+ const inner = this.chatMessagesStreamGen(
4399
+ modelID,
4400
+ req,
4401
+ ctl?.signal ?? signal,
4402
+ false,
4403
+ onUpstreamActivity,
4404
+ onGatewayRequestID,
4405
+ opts?.onResponseHeaders
4406
+ );
4407
+ return ctl ? disposeTimeoutWhenSettled(inner, ctl) : inner;
4408
+ }
4324
4409
  };
4325
4410
  }
4326
- async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
4411
+ async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID, onResponseHeaders) {
4327
4412
  const r = { ...req, stream: true };
4328
4413
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
4329
4414
  const token = await this.ensureToken(signal);
@@ -4355,10 +4440,11 @@ var Client = class _Client {
4355
4440
  `stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
4356
4441
  );
4357
4442
  }
4358
- yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
4443
+ yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID, onResponseHeaders);
4359
4444
  return;
4360
4445
  }
4361
4446
  notifyGatewayRequestID(onGatewayRequestID, resp.headers);
4447
+ notifyResponseHeaders(onResponseHeaders, resp.headers);
4362
4448
  if (!resp.ok) {
4363
4449
  const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4364
4450
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
@@ -4393,7 +4479,7 @@ var Client = class _Client {
4393
4479
  }
4394
4480
  }
4395
4481
  }
4396
- async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
4482
+ async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID, onResponseHeaders) {
4397
4483
  const r = { ...req, stream: true };
4398
4484
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
4399
4485
  const token = await this.ensureToken(signal);
@@ -4425,10 +4511,11 @@ var Client = class _Client {
4425
4511
  `messages stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
4426
4512
  );
4427
4513
  }
4428
- yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
4514
+ yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID, onResponseHeaders);
4429
4515
  return;
4430
4516
  }
4431
4517
  notifyGatewayRequestID(onGatewayRequestID, resp.headers);
4518
+ notifyResponseHeaders(onResponseHeaders, resp.headers);
4432
4519
  if (!resp.ok) {
4433
4520
  const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4434
4521
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
@@ -9114,6 +9201,7 @@ exports.isPlatform = isPlatform;
9114
9201
  exports.isRegion = isRegion;
9115
9202
  exports.isSSECommentLine = isSSECommentLine;
9116
9203
  exports.isSSLError = isSSLError;
9204
+ exports.isStreamError = isStreamError;
9117
9205
  exports.isTerminalRemoteEvent = isTerminalRemoteEvent;
9118
9206
  exports.isUserAccessTokenRejected = isUserAccessTokenRejected;
9119
9207
  exports.isValidTokenSet = isValidTokenSet;