@acosmi/sdk-ts 2.4.0 → 2.6.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.
@@ -322,13 +322,20 @@ function resolveThinkingLevel(body, req, caps) {
322
322
  }
323
323
  delete body["temperature"];
324
324
  }
325
- exports.AnthropicAdapter = void 0;
325
+ var ANTHROPIC_SDK_MANAGED_BODY_KEYS; exports.AnthropicAdapter = void 0;
326
326
  var init_anthropic = __esm({
327
327
  "src/models/adapters/anthropic.ts"() {
328
328
  init_types();
329
329
  init_errors();
330
330
  init_betas();
331
331
  init_adapters();
332
+ ANTHROPIC_SDK_MANAGED_BODY_KEYS = /* @__PURE__ */ new Set([
333
+ "thinking",
334
+ "effort",
335
+ "max_tokens",
336
+ "temperature",
337
+ "betas"
338
+ ]);
332
339
  exports.AnthropicAdapter = class {
333
340
  format() {
334
341
  return 0 /* Anthropic */;
@@ -416,6 +423,12 @@ var init_anthropic = __esm({
416
423
  }
417
424
  if (req.extraBody) {
418
425
  for (const [k, v] of Object.entries(req.extraBody)) {
426
+ if (ANTHROPIC_SDK_MANAGED_BODY_KEYS.has(k)) {
427
+ console.warn(
428
+ `acosmi-sdk: extraBody key "${k}" is SDK-managed and was ignored (use the dedicated request field instead).`
429
+ );
430
+ continue;
431
+ }
419
432
  body[k] = v;
420
433
  }
421
434
  }
@@ -775,6 +788,9 @@ var init_openai = __esm({
775
788
  messageStarted = false;
776
789
  thinkingStarted = false;
777
790
  thinkingStopped = false;
791
+ /** thinking block 打开时占用的 Anthropic block index — 关闭时必须用它, 不能用
792
+ * 可能已被 text/tool 推进的 this.blockIndex (否则 content_block_stop 索引错配)。 */
793
+ thinkingBlockIndex = 0;
778
794
  textStarted = false;
779
795
  /** OpenAI tool_call index → Anthropic block index */
780
796
  toolBlockIndex = /* @__PURE__ */ new Map();
@@ -815,6 +831,7 @@ var init_openai = __esm({
815
831
  if (choice.delta.reasoning_content && choice.delta.reasoning_content !== "") {
816
832
  if (!this.thinkingStarted) {
817
833
  this.thinkingStarted = true;
834
+ this.thinkingBlockIndex = this.blockIndex;
818
835
  const blockJSON = JSON.stringify({
819
836
  type: "content_block_start",
820
837
  index: this.blockIndex,
@@ -824,7 +841,7 @@ var init_openai = __esm({
824
841
  }
825
842
  const deltaJSON = JSON.stringify({
826
843
  type: "content_block_delta",
827
- index: this.blockIndex,
844
+ index: this.thinkingBlockIndex,
828
845
  delta: { type: "thinking_delta", thinking: choice.delta.reasoning_content }
829
846
  });
830
847
  events.push({ event: "content_block_delta", data: deltaJSON });
@@ -834,7 +851,7 @@ var init_openai = __esm({
834
851
  this.thinkingStopped = true;
835
852
  const stopJSON = JSON.stringify({
836
853
  type: "content_block_stop",
837
- index: this.blockIndex
854
+ index: this.thinkingBlockIndex
838
855
  });
839
856
  events.push({ event: "content_block_stop", data: stopJSON });
840
857
  this.blockIndex++;
@@ -857,6 +874,15 @@ var init_openai = __esm({
857
874
  }
858
875
  for (const tc of choice.delta.tool_calls ?? []) {
859
876
  if (!this.toolBlockIndex.has(tc.index)) {
877
+ if (this.thinkingStarted && !this.thinkingStopped) {
878
+ this.thinkingStopped = true;
879
+ const stopJSON = JSON.stringify({
880
+ type: "content_block_stop",
881
+ index: this.thinkingBlockIndex
882
+ });
883
+ events.push({ event: "content_block_stop", data: stopJSON });
884
+ this.blockIndex++;
885
+ }
860
886
  if (this.textStarted) {
861
887
  const stopJSON = JSON.stringify({
862
888
  type: "content_block_stop",
@@ -901,9 +927,10 @@ var init_openai = __esm({
901
927
  });
902
928
  events.push({ event: "content_block_stop", data: stopJSON2 });
903
929
  } else if (this.thinkingStarted && !this.thinkingStopped) {
930
+ this.thinkingStopped = true;
904
931
  const stopJSON2 = JSON.stringify({
905
932
  type: "content_block_stop",
906
- index: this.blockIndex
933
+ index: this.thinkingBlockIndex
907
934
  });
908
935
  events.push({ event: "content_block_stop", data: stopJSON2 });
909
936
  }
@@ -944,13 +971,6 @@ function getAdapter(provider) {
944
971
  return defaultOpenAIAdapter;
945
972
  }
946
973
  function getAdapterForModel(m) {
947
- const pref = (m.preferred_format ?? "").trim().toLowerCase();
948
- switch (pref) {
949
- case "anthropic":
950
- return new exports.AnthropicAdapter();
951
- case "openai":
952
- return new exports.OpenAIAdapter();
953
- }
954
974
  let hasAnthropic = false;
955
975
  let hasOpenAI = false;
956
976
  for (const f of m.supported_formats ?? []) {
@@ -963,6 +983,16 @@ function getAdapterForModel(m) {
963
983
  break;
964
984
  }
965
985
  }
986
+ const declared = hasAnthropic || hasOpenAI;
987
+ const pref = (m.preferred_format ?? "").trim().toLowerCase();
988
+ switch (pref) {
989
+ case "anthropic":
990
+ if (!declared || hasAnthropic) return new exports.AnthropicAdapter();
991
+ break;
992
+ case "openai":
993
+ if (!declared || hasOpenAI) return new exports.OpenAIAdapter();
994
+ break;
995
+ }
966
996
  if (hasAnthropic) return new exports.AnthropicAdapter();
967
997
  if (hasOpenAI) return new exports.OpenAIAdapter();
968
998
  return getAdapter((m.provider ?? "").toLowerCase());
@@ -972,6 +1002,7 @@ var init_adapters = __esm({
972
1002
  "src/models/adapters/index.ts"() {
973
1003
  init_anthropic();
974
1004
  init_openai();
1005
+ init_openai();
975
1006
  exports.ProviderFormat = /* @__PURE__ */ ((ProviderFormat2) => {
976
1007
  ProviderFormat2[ProviderFormat2["Anthropic"] = 0] = "Anthropic";
977
1008
  ProviderFormat2[ProviderFormat2["OpenAI"] = 1] = "OpenAI";
@@ -992,8 +1023,14 @@ init_types();
992
1023
  // src/auth/types.ts
993
1024
  function tokenSetIsExpired(t) {
994
1025
  const expiresAt = new Date(t.expires_at).getTime();
1026
+ if (!Number.isFinite(expiresAt)) return true;
995
1027
  return Date.now() > expiresAt - 3e4;
996
1028
  }
1029
+ function isValidTokenSet(x) {
1030
+ if (typeof x !== "object" || x === null) return false;
1031
+ const t = x;
1032
+ return typeof t.access_token === "string" && typeof t.refresh_token === "string" && typeof t.expires_at === "string" && typeof t.scope === "string" && typeof t.client_id === "string" && typeof t.server_url === "string";
1033
+ }
997
1034
 
998
1035
  // src/core/client.ts
999
1036
  init_errors();
@@ -1027,7 +1064,7 @@ var OAuthTokenEndpointError = class extends Error {
1027
1064
  function isInvalidGrantError(err) {
1028
1065
  return err instanceof OAuthTokenEndpointError && err.oauthError === "invalid_grant";
1029
1066
  }
1030
- async function discoverWithProfile(serverURL, profile, signal) {
1067
+ async function discoverWithProfile(serverURL, profile, signal, fetchImpl = globalThis.fetch) {
1031
1068
  let parsed;
1032
1069
  try {
1033
1070
  parsed = new URL(serverURL.replace(/\/+$/, ""));
@@ -1039,7 +1076,7 @@ async function discoverWithProfile(serverURL, profile, signal) {
1039
1076
  const ctl = withTimeout(authTimeoutMs, signal);
1040
1077
  let resp;
1041
1078
  try {
1042
- resp = await fetch(endpoint, { method: "GET", signal: ctl.signal });
1079
+ resp = await fetchImpl(endpoint, { method: "GET", signal: ctl.signal });
1043
1080
  } catch (e) {
1044
1081
  throw new Error(`discover: ${e instanceof Error ? e.message : String(e)}`);
1045
1082
  } finally {
@@ -1061,13 +1098,13 @@ async function discoverWithProfile(serverURL, profile, signal) {
1061
1098
  }
1062
1099
  return meta;
1063
1100
  }
1064
- async function discover(serverURL, signal) {
1065
- return discoverWithProfile(serverURL, "desktop", signal);
1101
+ async function discover(serverURL, signal, fetchImpl = globalThis.fetch) {
1102
+ return discoverWithProfile(serverURL, "desktop", signal, fetchImpl);
1066
1103
  }
1067
- async function discoverWebOAuthMetadata(serverURL, signal) {
1068
- return discoverWithProfile(serverURL, "web", signal);
1104
+ async function discoverWebOAuthMetadata(serverURL, signal, fetchImpl = globalThis.fetch) {
1105
+ return discoverWithProfile(serverURL, "web", signal, fetchImpl);
1069
1106
  }
1070
- async function register(meta, appName, signal) {
1107
+ async function register(meta, appName, signal, fetchImpl = globalThis.fetch) {
1071
1108
  const regReq = {
1072
1109
  client_name: appName,
1073
1110
  token_endpoint_auth_method: "none",
@@ -1078,7 +1115,7 @@ async function register(meta, appName, signal) {
1078
1115
  const ctl = withTimeout(authTimeoutMs, signal);
1079
1116
  let resp;
1080
1117
  try {
1081
- resp = await fetch(meta.registration_endpoint, {
1118
+ resp = await fetchImpl(meta.registration_endpoint, {
1082
1119
  method: "POST",
1083
1120
  headers: { "Content-Type": "application/json" },
1084
1121
  body: JSON.stringify(regReq),
@@ -1098,7 +1135,7 @@ async function register(meta, appName, signal) {
1098
1135
  throw new Error(`register: decode: ${e instanceof Error ? e.message : String(e)}`);
1099
1136
  }
1100
1137
  }
1101
- async function registerWebOAuthClient(meta, opts, signal) {
1138
+ async function registerWebOAuthClient(meta, opts, signal, fetchImpl = globalThis.fetch) {
1102
1139
  const regReq = {
1103
1140
  client_name: opts.clientName,
1104
1141
  token_endpoint_auth_method: "none",
@@ -1110,7 +1147,7 @@ async function registerWebOAuthClient(meta, opts, signal) {
1110
1147
  const ctl = withTimeout(authTimeoutMs, signal);
1111
1148
  let resp;
1112
1149
  try {
1113
- resp = await fetch(meta.registration_endpoint, {
1150
+ resp = await fetchImpl(meta.registration_endpoint, {
1114
1151
  method: "POST",
1115
1152
  headers: { "Content-Type": "application/json" },
1116
1153
  body: JSON.stringify(regReq),
@@ -1314,7 +1351,7 @@ async function createWebAuthorizationRequest(meta, opts) {
1314
1351
  createdAt: Date.now()
1315
1352
  };
1316
1353
  }
1317
- async function completeWebAuthorizationRequest(pending, params, signal) {
1354
+ async function completeWebAuthorizationRequest(pending, params, signal, fetchImpl = globalThis.fetch) {
1318
1355
  if (!params.code) {
1319
1356
  throw new Error("completeWebAuthorizationRequest: missing authorization code");
1320
1357
  }
@@ -1323,18 +1360,19 @@ async function completeWebAuthorizationRequest(pending, params, signal) {
1323
1360
  `completeWebAuthorizationRequest: ${ErrStateMismatch}: callback state does not match pending state (possible CSRF)`
1324
1361
  );
1325
1362
  }
1326
- const meta = await discoverWebOAuthMetadata(pending.serverURL, signal);
1363
+ const meta = await discoverWebOAuthMetadata(pending.serverURL, signal, fetchImpl);
1327
1364
  const resp = await exchangeCode(
1328
1365
  meta,
1329
1366
  pending.clientID,
1330
1367
  params.code,
1331
1368
  pending.redirectURI,
1332
1369
  pending.verifier,
1333
- signal
1370
+ signal,
1371
+ fetchImpl
1334
1372
  );
1335
1373
  return newTokenSet(resp, pending.clientID, pending.serverURL);
1336
1374
  }
1337
- async function exchangeCode(meta, clientID, code, redirectURI, codeVerifier, signal) {
1375
+ async function exchangeCode(meta, clientID, code, redirectURI, codeVerifier, signal, fetchImpl = globalThis.fetch) {
1338
1376
  const data = new URLSearchParams({
1339
1377
  grant_type: "authorization_code",
1340
1378
  client_id: clientID,
@@ -1342,9 +1380,9 @@ async function exchangeCode(meta, clientID, code, redirectURI, codeVerifier, sig
1342
1380
  redirect_uri: redirectURI,
1343
1381
  code_verifier: codeVerifier
1344
1382
  });
1345
- return postToken(meta.token_endpoint, data, signal);
1383
+ return postToken(meta.token_endpoint, data, signal, fetchImpl);
1346
1384
  }
1347
- async function exchangeCodeWithExpiry(meta, clientID, code, redirectURI, codeVerifier, expiresIn, signal) {
1385
+ async function exchangeCodeWithExpiry(meta, clientID, code, redirectURI, codeVerifier, expiresIn, signal, fetchImpl = globalThis.fetch) {
1348
1386
  const data = new URLSearchParams({
1349
1387
  grant_type: "authorization_code",
1350
1388
  client_id: clientID,
@@ -1353,24 +1391,24 @@ async function exchangeCodeWithExpiry(meta, clientID, code, redirectURI, codeVer
1353
1391
  code_verifier: codeVerifier,
1354
1392
  expires_in: String(expiresIn)
1355
1393
  });
1356
- return postToken(meta.token_endpoint, data, signal);
1394
+ return postToken(meta.token_endpoint, data, signal, fetchImpl);
1357
1395
  }
1358
- async function refreshToken(meta, clientID, refreshTokenValue, signal) {
1396
+ async function refreshToken(meta, clientID, refreshTokenValue, signal, fetchImpl = globalThis.fetch) {
1359
1397
  const data = new URLSearchParams({
1360
1398
  grant_type: "refresh_token",
1361
1399
  client_id: clientID,
1362
1400
  refresh_token: refreshTokenValue
1363
1401
  });
1364
- return postToken(meta.token_endpoint, data, signal);
1402
+ return postToken(meta.token_endpoint, data, signal, fetchImpl);
1365
1403
  }
1366
- async function revokeToken(meta, token, signal) {
1404
+ async function revokeToken(meta, token, signal, fetchImpl = globalThis.fetch) {
1367
1405
  if (!meta.revocation_endpoint || meta.revocation_endpoint === "") {
1368
1406
  return;
1369
1407
  }
1370
1408
  const data = new URLSearchParams({ token });
1371
1409
  const ctl = withTimeout(authTimeoutMs, signal);
1372
1410
  try {
1373
- await fetch(meta.revocation_endpoint, {
1411
+ await fetchImpl(meta.revocation_endpoint, {
1374
1412
  method: "POST",
1375
1413
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
1376
1414
  body: data,
@@ -1382,11 +1420,11 @@ async function revokeToken(meta, token, signal) {
1382
1420
  ctl.dispose();
1383
1421
  }
1384
1422
  }
1385
- async function postToken(endpoint, data, signal) {
1423
+ async function postToken(endpoint, data, signal, fetchImpl = globalThis.fetch) {
1386
1424
  const ctl = withTimeout(authTimeoutMs, signal);
1387
1425
  let resp;
1388
1426
  try {
1389
- resp = await fetch(endpoint, {
1427
+ resp = await fetchImpl(endpoint, {
1390
1428
  method: "POST",
1391
1429
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
1392
1430
  body: data,
@@ -1604,7 +1642,15 @@ ${Date.now()}
1604
1642
  await fs.mkdir(dir, { recursive: true, mode: 448 });
1605
1643
  const tmp = `${p}.tmp.${process.pid}.${Date.now()}.${Math.floor(Math.random() * 1e6)}`;
1606
1644
  const data = JSON.stringify(tokens, null, 2);
1607
- await fs.writeFile(tmp, data, { encoding: "utf8", mode: 384 });
1645
+ {
1646
+ const fh = await fs.open(tmp, "w", 384);
1647
+ try {
1648
+ await fh.writeFile(data, { encoding: "utf8" });
1649
+ await fh.sync();
1650
+ } finally {
1651
+ await fh.close();
1652
+ }
1653
+ }
1608
1654
  try {
1609
1655
  await fs.rename(tmp, p);
1610
1656
  } catch (e) {
@@ -1614,6 +1660,15 @@ ${Date.now()}
1614
1660
  }
1615
1661
  throw e;
1616
1662
  }
1663
+ try {
1664
+ const dirHandle = await fs.open(dir, "r");
1665
+ try {
1666
+ await dirHandle.sync();
1667
+ } finally {
1668
+ await dirHandle.close();
1669
+ }
1670
+ } catch {
1671
+ }
1617
1672
  });
1618
1673
  }
1619
1674
  load() {
@@ -1622,7 +1677,14 @@ ${Date.now()}
1622
1677
  const p = await this.resolvePath();
1623
1678
  try {
1624
1679
  const data = await fs.readFile(p, "utf8");
1625
- return JSON.parse(data);
1680
+ let parsed;
1681
+ try {
1682
+ parsed = JSON.parse(data);
1683
+ } catch {
1684
+ return null;
1685
+ }
1686
+ if (!isValidTokenSet(parsed)) return null;
1687
+ return parsed;
1626
1688
  } catch (e) {
1627
1689
  if (isNotExistError(e)) return null;
1628
1690
  throw new Error(
@@ -1673,11 +1735,14 @@ var LocalStorageTokenStore = class {
1673
1735
  async load() {
1674
1736
  const data = globalThis.localStorage.getItem(this.key);
1675
1737
  if (data == null || data === "") return null;
1738
+ let parsed;
1676
1739
  try {
1677
- return JSON.parse(data);
1740
+ parsed = JSON.parse(data);
1678
1741
  } catch {
1679
1742
  return null;
1680
1743
  }
1744
+ if (!isValidTokenSet(parsed)) return null;
1745
+ return parsed;
1681
1746
  }
1682
1747
  async clear() {
1683
1748
  globalThis.localStorage.removeItem(this.key);
@@ -2046,6 +2111,32 @@ function normalizeGatewayBaseURL(input) {
2046
2111
  const path = parsed.pathname.replace(/\/+$/, "");
2047
2112
  return path ? `${parsed.origin}${path}` : parsed.origin;
2048
2113
  }
2114
+ function normalizeOverrideBaseURL(raw, label) {
2115
+ if (typeof raw !== "string") {
2116
+ throw new TypeError(`${label} must be a string`);
2117
+ }
2118
+ const trimmed = raw.trim();
2119
+ if (trimmed.length === 0) {
2120
+ throw new Error(`${label} is empty`);
2121
+ }
2122
+ let parsed;
2123
+ try {
2124
+ parsed = new URL(trimmed);
2125
+ } catch {
2126
+ throw new Error(`${label} is not a valid URL: ${trimmed}`);
2127
+ }
2128
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
2129
+ throw new Error(`${label} only allows http/https, got ${parsed.protocol} (${trimmed})`);
2130
+ }
2131
+ if (!parsed.host) {
2132
+ throw new Error(`${label} has empty host: ${trimmed}`);
2133
+ }
2134
+ if (parsed.search.length > 0 || parsed.hash.length > 0) {
2135
+ throw new Error(`${label} must not contain query or hash: ${trimmed}`);
2136
+ }
2137
+ const path = parsed.pathname.replace(/\/+$/, "");
2138
+ return path ? `${parsed.origin}${path}` : parsed.origin;
2139
+ }
2049
2140
  function pickAndNormalizeGatewayURL(cfg) {
2050
2141
  const inputs = [];
2051
2142
  if (cfg.serverURL !== void 0) inputs.push(["serverURL", cfg.serverURL]);
@@ -2066,6 +2157,7 @@ var ErrOAuthCORSBlocked = "oauth_cors_blocked";
2066
2157
  var ErrRefreshProxyFailed = "refresh_proxy_failed";
2067
2158
  var ErrTokenExpired = "token_expired";
2068
2159
  var CHAT_REQUEST_TIMEOUT_MS = 11 * 60 * 1e3;
2160
+ var DEFAULT_API_TIMEOUT_MS = 6e4;
2069
2161
  function newDeferred() {
2070
2162
  let resolve;
2071
2163
  let reject;
@@ -2123,8 +2215,8 @@ var Client = class _Client {
2123
2215
  constructor(cfg = {}) {
2124
2216
  const picked = pickAndNormalizeGatewayURL(cfg);
2125
2217
  this.serverURL = picked ?? DEFAULT_GATEWAY_BASE_URL;
2126
- this.complianceBaseURL = cfg.complianceBaseURL ? cfg.complianceBaseURL.replace(/\/+$/, "") : null;
2127
- this.apiBaseURL = cfg.apiBaseURL ? cfg.apiBaseURL.replace(/\/+$/, "") : null;
2218
+ this.complianceBaseURL = cfg.complianceBaseURL ? normalizeOverrideBaseURL(cfg.complianceBaseURL, "complianceBaseURL") : null;
2219
+ this.apiBaseURL = cfg.apiBaseURL ? normalizeOverrideBaseURL(cfg.apiBaseURL, "apiBaseURL") : null;
2128
2220
  this.oauthMetadataProfile = cfg.oauthMetadataProfile ?? "desktop";
2129
2221
  this.browserRefreshMode = cfg.browserRefreshMode ?? "direct";
2130
2222
  this.refreshProxyURL = cfg.refreshProxyURL ?? null;
@@ -2216,7 +2308,7 @@ var Client = class _Client {
2216
2308
  try {
2217
2309
  let meta;
2218
2310
  try {
2219
- meta = await discover(this.serverURL, signal);
2311
+ meta = await discover(this.serverURL, signal, this.fetchImpl);
2220
2312
  } catch (err) {
2221
2313
  emitError(ErrDiscovery, err);
2222
2314
  throw new Error(`discovery failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -2225,7 +2317,7 @@ var Client = class _Client {
2225
2317
  let clientID = this.getCachedClientID();
2226
2318
  if (clientID === "") {
2227
2319
  try {
2228
- const reg = await register(meta, appName, signal);
2320
+ const reg = await register(meta, appName, signal, this.fetchImpl);
2229
2321
  clientID = reg.client_id;
2230
2322
  } catch (err) {
2231
2323
  emitError(ErrRegistration, err);
@@ -2242,7 +2334,7 @@ var Client = class _Client {
2242
2334
  verifier = r.verifier;
2243
2335
  } catch (err) {
2244
2336
  try {
2245
- const reg = await register(meta, appName, signal);
2337
+ const reg = await register(meta, appName, signal, this.fetchImpl);
2246
2338
  clientID = reg.client_id;
2247
2339
  } catch (regErr) {
2248
2340
  emitError(ErrRegistration, regErr);
@@ -2270,7 +2362,8 @@ var Client = class _Client {
2270
2362
  result.redirectURI,
2271
2363
  verifier,
2272
2364
  opts.expiresIn,
2273
- signal
2365
+ signal,
2366
+ this.fetchImpl
2274
2367
  );
2275
2368
  } else {
2276
2369
  tokenResp = await exchangeCode(
@@ -2279,7 +2372,8 @@ var Client = class _Client {
2279
2372
  result.code,
2280
2373
  result.redirectURI,
2281
2374
  verifier,
2282
- signal
2375
+ signal,
2376
+ this.fetchImpl
2283
2377
  );
2284
2378
  }
2285
2379
  } catch (err) {
@@ -2316,18 +2410,18 @@ var Client = class _Client {
2316
2410
  if (tokens) {
2317
2411
  if (!meta) {
2318
2412
  try {
2319
- meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
2413
+ meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal, this.fetchImpl);
2320
2414
  } catch (e) {
2321
2415
  console.warn(`[acosmi-sdk] warning: discover for revocation failed: ${e instanceof Error ? e.message : String(e)}`);
2322
2416
  }
2323
2417
  }
2324
2418
  if (meta) {
2325
2419
  try {
2326
- await revokeToken(meta, tokens.access_token, signal);
2420
+ await revokeToken(meta, tokens.access_token, signal, this.fetchImpl);
2327
2421
  } catch {
2328
2422
  }
2329
2423
  try {
2330
- await revokeToken(meta, tokens.refresh_token, signal);
2424
+ await revokeToken(meta, tokens.refresh_token, signal, this.fetchImpl);
2331
2425
  } catch {
2332
2426
  }
2333
2427
  }
@@ -2421,7 +2515,7 @@ var Client = class _Client {
2421
2515
  }
2422
2516
  if (this.meta == null) {
2423
2517
  try {
2424
- this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
2518
+ this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal, this.fetchImpl);
2425
2519
  } catch (e) {
2426
2520
  throw new Error(
2427
2521
  `discover for refresh: ${e instanceof Error ? e.message : String(e)}`
@@ -2434,7 +2528,8 @@ var Client = class _Client {
2434
2528
  this.meta,
2435
2529
  this.tokens.client_id,
2436
2530
  this.tokens.refresh_token,
2437
- signal
2531
+ signal,
2532
+ this.fetchImpl
2438
2533
  );
2439
2534
  } catch (e) {
2440
2535
  const message = e instanceof Error ? e.message : String(e);
@@ -2701,10 +2796,10 @@ var Client = class _Client {
2701
2796
  * v0.5.0: 根据 provider 自动路由到 /anthropic 或 /chat 端点
2702
2797
  */
2703
2798
  async chat(modelID, req, signal) {
2704
- req.stream = false;
2799
+ const r = { ...req, stream: false };
2705
2800
  const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
2706
2801
  try {
2707
- const { body, adapter } = await this.buildChatRequest(modelID, req, ctl.signal);
2802
+ const { body, adapter } = await this.buildChatRequest(modelID, r, ctl.signal);
2708
2803
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
2709
2804
  const { result, headers } = await this.doJSONFullRaw("POST", endpoint, body, ctl.signal);
2710
2805
  const resp = adapter.parseResponse(result);
@@ -2802,11 +2897,11 @@ var Client = class _Client {
2802
2897
  return this.chatMessagesOpenAI(modelID, req, adapter, signal);
2803
2898
  }
2804
2899
  async chatMessagesAnthropic(modelID, req, adapter, signal) {
2805
- req.stream = false;
2900
+ const r = { ...req, stream: false };
2806
2901
  const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
2807
2902
  try {
2808
2903
  const caps = this.getCachedCapabilities(modelID) ?? zeroModelCapabilities();
2809
- const body = adapter.buildRequestBody(caps, req);
2904
+ const body = adapter.buildRequestBody(caps, r);
2810
2905
  const data = JSON.stringify(body);
2811
2906
  const { result } = await this.doJSONFullRaw(
2812
2907
  "POST",
@@ -2839,11 +2934,11 @@ var Client = class _Client {
2839
2934
  }
2840
2935
  }
2841
2936
  async chatMessagesOpenAI(modelID, req, adapter, signal) {
2842
- req.stream = false;
2937
+ const r = { ...req, stream: false };
2843
2938
  const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
2844
2939
  try {
2845
2940
  const caps = this.getCachedCapabilities(modelID) ?? zeroModelCapabilities();
2846
- const body = adapter.buildRequestBody(caps, req);
2941
+ const body = adapter.buildRequestBody(caps, r);
2847
2942
  const data = JSON.stringify(body);
2848
2943
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
2849
2944
  const { result } = await this.doJSONFullRaw("POST", endpoint, data, ctl.signal);
@@ -2873,8 +2968,8 @@ var Client = class _Client {
2873
2968
  };
2874
2969
  }
2875
2970
  async *chatStreamGen(modelID, req, signal, retried) {
2876
- req.stream = true;
2877
- const { body, adapter } = await this.buildChatRequest(modelID, req, signal);
2971
+ const r = { ...req, stream: true };
2972
+ const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
2878
2973
  const token = await this.ensureToken(signal);
2879
2974
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
2880
2975
  const url = this.apiURL(endpoint);
@@ -2942,8 +3037,8 @@ var Client = class _Client {
2942
3037
  }
2943
3038
  }
2944
3039
  async *chatMessagesStreamGen(modelID, req, signal, retried) {
2945
- req.stream = true;
2946
- const { body, adapter } = await this.buildChatRequest(modelID, req, signal);
3040
+ const r = { ...req, stream: true };
3041
+ const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
2947
3042
  const token = await this.ensureToken(signal);
2948
3043
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
2949
3044
  const url = this.apiURL(endpoint);
@@ -3115,6 +3210,9 @@ var Client = class _Client {
3115
3210
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
3116
3211
  }
3117
3212
  const text = await resp.text();
3213
+ if (!text) {
3214
+ return { result: void 0, headers: resp.headers };
3215
+ }
3118
3216
  const result = JSON.parse(text);
3119
3217
  if (result && typeof result === "object" && "code" in result) {
3120
3218
  const bizErr = apiResponseBusinessError(result);
@@ -3215,6 +3313,18 @@ var Client = class _Client {
3215
3313
  ctl.dispose();
3216
3314
  }
3217
3315
  }
3316
+ /**
3317
+ * 给子 client (agent-runs / compliance) 用的请求超时组合器。
3318
+ *
3319
+ * 返回一个 controller, 其 `signal` 同时受默认/指定超时与外部 `parent` signal 约束 —
3320
+ * 二者任一触发都会 abort (用户传入的 signal 仍然生效)。调用方**必须**在 finally 里
3321
+ * `dispose()` 清掉定时器与监听, 否则 timer 泄漏。
3322
+ *
3323
+ * 仅用于非流式 JSON 请求; 流式 (SSE) / 下载路径不应套短超时 (会切断长连接)。
3324
+ */
3325
+ withRequestTimeout(ms, parent) {
3326
+ return withRequestTimeout(ms, parent);
3327
+ }
3218
3328
  /**
3219
3329
  * fetch 包装 — 错误经 classifyTransport 转 NetworkError
3220
3330
  * 6 处原始 fetch() 全部走此 helper
@@ -3784,6 +3894,10 @@ var ScopeRemoteControl = "remote_control";
3784
3894
  var ScopeRemoteControlAgentRun = "remote_control:agent-run";
3785
3895
  var ScopeRemoteControlSessionControl = "remote_control:session-control";
3786
3896
  var ScopeRemoteControlPermissionResponse = "remote_control:permission-response";
3897
+ var ScopeChatBridge = "chat_bridge";
3898
+ var ScopeChatBridgeRead = "chat_bridge:read";
3899
+ var ScopeChatBridgeWrite = "chat_bridge:write";
3900
+ var ScopeChatBridgeRotate = "chat_bridge:rotate";
3787
3901
  var ScopeModels = "models";
3788
3902
  var ScopeModelsChat = "models:chat";
3789
3903
  var ScopeEntitlements = "entitlements";
@@ -3809,6 +3923,9 @@ function skillScopes() {
3809
3923
  function remoteControlScopes() {
3810
3924
  return [ScopeRemoteControl];
3811
3925
  }
3926
+ function chatBridgeScopes() {
3927
+ return [ScopeChatBridge];
3928
+ }
3812
3929
 
3813
3930
  // src/models/index.ts
3814
3931
  init_types();
@@ -4000,9 +4117,10 @@ Client.prototype.waitForPayment = async function(orderID, pollIntervalMs, signal
4000
4117
  if (pollIntervalMs <= 0) pollIntervalMs = 2e3;
4001
4118
  while (true) {
4002
4119
  const status = await this.getOrderStatus(orderID, signal);
4003
- if (isOrderTerminal(status.status)) {
4004
- if (isOrderSuccess(status.status)) return status;
4005
- throw new exports.OrderTerminalError(orderID, status.status);
4120
+ const st = status.paymentStatus ?? status.orderStatus;
4121
+ if (isOrderTerminal(st)) {
4122
+ if (isOrderSuccess(st)) return status;
4123
+ throw new exports.OrderTerminalError(orderID, st);
4006
4124
  }
4007
4125
  await sleepWithSignal(pollIntervalMs, signal);
4008
4126
  }
@@ -4383,6 +4501,9 @@ Client.prototype.updateNotificationPreference = async function(typeCode, pref, s
4383
4501
 
4384
4502
  // src/notifications/ws.ts
4385
4503
  Client.prototype.connect = async function(cfg, signal) {
4504
+ if (this.ws) {
4505
+ await this.disconnect();
4506
+ }
4386
4507
  const noop = () => {
4387
4508
  };
4388
4509
  const filledCfg = {
@@ -4451,11 +4572,17 @@ function getWebSocketCtor() {
4451
4572
  return WSCtor;
4452
4573
  }
4453
4574
  async function wsConnectOnce(c, ws) {
4454
- const token = await c.ensureToken(ws.abort.signal);
4455
4575
  const url = wsURL(c);
4456
4576
  const WSCtor = getWebSocketCtor();
4577
+ const ticketResp = await c.doJSON(
4578
+ "POST",
4579
+ "/ws/stream-ticket",
4580
+ null,
4581
+ ws.abort.signal
4582
+ );
4583
+ const ticket = ticketResp.data.ticket;
4457
4584
  const u = new URL(url);
4458
- u.searchParams.set("token", token);
4585
+ u.searchParams.set("ticket", ticket);
4459
4586
  let conn;
4460
4587
  try {
4461
4588
  conn = new WSCtor(u.toString());
@@ -4911,7 +5038,10 @@ var AgentRunsClient = class {
4911
5038
  );
4912
5039
  const contentType = resp.headers.get("Content-Type") ?? void 0;
4913
5040
  const filename = filenameFromContentDisposition(resp.headers.get("Content-Disposition")) ?? artifactId;
4914
- const data = await readLimited(resp.body, maxDownloadSize);
5041
+ const data = await readLimited(resp.body, maxDownloadSize + 1);
5042
+ if (data.byteLength > maxDownloadSize) {
5043
+ throw new Error(`download artifact: response exceeds ${maxDownloadSize >> 20}MB limit`);
5044
+ }
4915
5045
  return { data, filename, contentType };
4916
5046
  }
4917
5047
  submitLocalToolResult(runId, result, signal) {
@@ -4967,7 +5097,6 @@ var AgentRunsClient = class {
4967
5097
  };
4968
5098
  }
4969
5099
  const ctl = new AbortController();
4970
- const timer = setTimeout(() => ctl.abort(), timeoutMs);
4971
5100
  let parentAbort;
4972
5101
  if (signal) {
4973
5102
  if (signal.aborted) ctl.abort();
@@ -4976,7 +5105,18 @@ var AgentRunsClient = class {
4976
5105
  signal.addEventListener("abort", parentAbort);
4977
5106
  }
4978
5107
  }
4979
- try {
5108
+ let timer;
5109
+ const timeoutResult = new Promise((resolve) => {
5110
+ timer = setTimeout(() => {
5111
+ ctl.abort();
5112
+ resolve({
5113
+ requestId: event.requestId,
5114
+ ok: false,
5115
+ error: `local tool timed out after ${timeoutMs}ms`
5116
+ });
5117
+ }, timeoutMs);
5118
+ });
5119
+ const handlerTask = (async () => {
4980
5120
  const content = await handler(event.input, {
4981
5121
  runId,
4982
5122
  requestId: event.requestId,
@@ -4984,6 +5124,11 @@ var AgentRunsClient = class {
4984
5124
  signal: ctl.signal
4985
5125
  });
4986
5126
  return { requestId: event.requestId, ok: true, content };
5127
+ })();
5128
+ handlerTask.catch(() => {
5129
+ });
5130
+ try {
5131
+ return await Promise.race([handlerTask, timeoutResult]);
4987
5132
  } catch (e) {
4988
5133
  if (signal?.aborted) throw e;
4989
5134
  const timedOut = ctl.signal.aborted;
@@ -5016,14 +5161,29 @@ var AgentRunsClient = class {
5016
5161
  }
5017
5162
  }
5018
5163
  async requestAPI(method, path, body, signal, opts) {
5019
- const resp = await this.requestRaw(method, path, body, signal, opts);
5164
+ const resp = await this.requestRaw(method, path, body, signal, {
5165
+ ...opts,
5166
+ timeoutMs: opts.timeoutMs ?? DEFAULT_API_TIMEOUT_MS
5167
+ });
5020
5168
  const text = await resp.text();
5169
+ if (!text) return void 0;
5021
5170
  const result = JSON.parse(text);
5022
5171
  const bizErr = apiResponseBusinessError(result);
5023
5172
  if (bizErr) throw bizErr;
5024
5173
  return result.data;
5025
5174
  }
5026
5175
  async requestRaw(method, path, body, signal, opts, retried = false) {
5176
+ if (opts.timeoutMs != null && opts.timeoutMs > 0) {
5177
+ const ctl = this.client.withRequestTimeout(opts.timeoutMs, signal);
5178
+ try {
5179
+ return await this.requestRawInner(method, path, body, ctl.signal, opts, retried);
5180
+ } finally {
5181
+ ctl.dispose();
5182
+ }
5183
+ }
5184
+ return this.requestRawInner(method, path, body, signal, opts, retried);
5185
+ }
5186
+ async requestRawInner(method, path, body, signal, opts, retried) {
5027
5187
  const token = await this.client.ensureToken(signal);
5028
5188
  const url = this.client.apiURL(path);
5029
5189
  const headers = {
@@ -5042,7 +5202,7 @@ var AgentRunsClient = class {
5042
5202
  } catch {
5043
5203
  }
5044
5204
  await this.client.forceRefresh(signal);
5045
- return this.requestRaw(method, path, body, signal, opts, true);
5205
+ return this.requestRawInner(method, path, body, signal, opts, true);
5046
5206
  }
5047
5207
  if (resp.status < 200 || resp.status >= 300) {
5048
5208
  const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
@@ -6374,6 +6534,14 @@ var ComplianceClient = class {
6374
6534
  });
6375
6535
  }
6376
6536
  async executeJson(method, path, body, signal, opts, retried = false) {
6537
+ const ctl = this.client.withRequestTimeout(DEFAULT_API_TIMEOUT_MS, signal);
6538
+ try {
6539
+ return await this.executeJsonInner(method, path, body, ctl.signal, opts, retried);
6540
+ } finally {
6541
+ ctl.dispose();
6542
+ }
6543
+ }
6544
+ async executeJsonInner(method, path, body, signal, opts, retried) {
6377
6545
  const token = await this.client.ensureToken(signal);
6378
6546
  const url = this.client.complianceURL(path);
6379
6547
  const headers = {
@@ -6393,7 +6561,7 @@ var ComplianceClient = class {
6393
6561
  } catch {
6394
6562
  }
6395
6563
  await this.client.forceRefresh(signal);
6396
- return this.executeJson(method, path, body, signal, opts, true);
6564
+ return this.executeJsonInner(method, path, body, signal, opts, true);
6397
6565
  }
6398
6566
  if (resp.status < 200 || resp.status >= 300) {
6399
6567
  const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
@@ -6418,7 +6586,11 @@ var ComplianceClient = class {
6418
6586
  let lastValue;
6419
6587
  while (Date.now() < deadline) {
6420
6588
  if (opts.signal?.aborted) {
6421
- throw new CompliancePollError("compliance poll aborted", "unknown");
6589
+ throw new CompliancePollError(
6590
+ "compliance poll aborted",
6591
+ "unknown",
6592
+ deriveLastInfo(lastValue, false)
6593
+ );
6422
6594
  }
6423
6595
  lastValue = await fetcher();
6424
6596
  const decision = classify(lastValue);
@@ -6426,7 +6598,8 @@ var ComplianceClient = class {
6426
6598
  if (decision === "failed") {
6427
6599
  throw new CompliancePollError(
6428
6600
  "compliance poll observed terminal failure",
6429
- "terminal_failure"
6601
+ "terminal_failure",
6602
+ deriveLastInfo(lastValue, true)
6430
6603
  );
6431
6604
  }
6432
6605
  const sleepMs = Math.min(interval, deadline - Date.now());
@@ -6434,9 +6607,30 @@ var ComplianceClient = class {
6434
6607
  await sleep2(sleepMs, opts.signal);
6435
6608
  interval = Math.min(Math.floor(interval * cfg.multiplier), cfg.maxIntervalMs);
6436
6609
  }
6437
- throw new CompliancePollError("compliance poll timed out", "timeout");
6610
+ throw new CompliancePollError(
6611
+ "compliance poll timed out",
6612
+ "timeout",
6613
+ deriveLastInfo(lastValue, false)
6614
+ );
6438
6615
  }
6439
6616
  };
6617
+ function deriveLastInfo(value, terminal) {
6618
+ if (value == null || typeof value !== "object") return void 0;
6619
+ const v = value;
6620
+ const statusStr = typeof v["status"] === "string" && v["status"] || typeof v["verificationStatus"] === "string" && v["verificationStatus"] || "";
6621
+ const rawCode = v["errorCode"] ?? v["code"];
6622
+ const code = typeof rawCode === "number" ? rawCode : 0;
6623
+ const rawMsg = v["errorMessage"] ?? v["message"];
6624
+ const message = typeof rawMsg === "string" && rawMsg || (statusStr ? `last polled status: ${statusStr}` : "") || "compliance poll: last observed status (no detail)";
6625
+ return {
6626
+ code,
6627
+ message,
6628
+ key: "UNKNOWN_COMPLIANCE_ERROR",
6629
+ retryable: false,
6630
+ terminal,
6631
+ stepUpRequired: false
6632
+ };
6633
+ }
6440
6634
  function classifyTimestamp(status) {
6441
6635
  switch (status) {
6442
6636
  case "VERIFIED":
@@ -6556,14 +6750,36 @@ Client.prototype.listPlans = async function(audience, signal) {
6556
6750
  );
6557
6751
  return Array.isArray(resp.data) ? resp.data : [];
6558
6752
  };
6559
- Client.prototype.listUserSubscriptions = async function(signal) {
6753
+ Client.prototype.getMembership = async function(signal) {
6560
6754
  const resp = await this.doJSON(
6561
6755
  "GET",
6562
- "/distribution/user/subscriptions",
6756
+ "/entitlements/membership",
6563
6757
  null,
6564
6758
  signal
6565
6759
  );
6566
- return Array.isArray(resp.data) ? resp.data : [];
6760
+ return resp.data;
6761
+ };
6762
+ Client.prototype.getSubscriptionTier = async function(signal) {
6763
+ const resp = await this.doJSON(
6764
+ "GET",
6765
+ "/entitlements/subscription",
6766
+ null,
6767
+ signal
6768
+ );
6769
+ return resp.data;
6770
+ };
6771
+ Client.prototype.subscriptionPrecheck = async function(signal) {
6772
+ const resp = await this.doJSON(
6773
+ "GET",
6774
+ "/consumer/subscriptions/precheck",
6775
+ null,
6776
+ signal
6777
+ );
6778
+ return resp.data;
6779
+ };
6780
+ Client.prototype.listUserSubscriptions = async function(signal) {
6781
+ const m = await this.getMembership(signal);
6782
+ return m.hasActive ? [m] : [];
6567
6783
  };
6568
6784
  Client.prototype.getPlanByCode = async function(planCode, signal) {
6569
6785
  if (!planCode) return null;
@@ -6988,6 +7204,7 @@ exports.BillingModeEnum = BillingModeEnum;
6988
7204
  exports.Client = Client;
6989
7205
  exports.ComplianceClient = ComplianceClient;
6990
7206
  exports.CompliancePollError = CompliancePollError;
7207
+ exports.DEFAULT_API_TIMEOUT_MS = DEFAULT_API_TIMEOUT_MS;
6991
7208
  exports.DEFAULT_GATEWAY_BASE_URL = DEFAULT_GATEWAY_BASE_URL;
6992
7209
  exports.DefaultRetryPolicy = DefaultRetryPolicy;
6993
7210
  exports.ErrAuthDenied = ErrAuthDenied;
@@ -7038,6 +7255,10 @@ exports.RETRY_ADVICE_REASONS = RETRY_ADVICE_REASONS;
7038
7255
  exports.RegionScopeEnum = RegionScopeEnum;
7039
7256
  exports.ScopeAI = ScopeAI;
7040
7257
  exports.ScopeAccount = ScopeAccount;
7258
+ exports.ScopeChatBridge = ScopeChatBridge;
7259
+ exports.ScopeChatBridgeRead = ScopeChatBridgeRead;
7260
+ exports.ScopeChatBridgeRotate = ScopeChatBridgeRotate;
7261
+ exports.ScopeChatBridgeWrite = ScopeChatBridgeWrite;
7041
7262
  exports.ScopeComplianceContractSigningRead = ScopeComplianceContractSigningRead;
7042
7263
  exports.ScopeComplianceContractSigningWrite = ScopeComplianceContractSigningWrite;
7043
7264
  exports.ScopeComplianceContractTemplateRead = ScopeComplianceContractTemplateRead;
@@ -7079,6 +7300,7 @@ exports.authorize = authorize;
7079
7300
  exports.bucketInfoIsCommercial = bucketInfoIsCommercial;
7080
7301
  exports.bucketRowIsCommercial = bucketRowIsCommercial;
7081
7302
  exports.buildBetas = buildBetas;
7303
+ exports.chatBridgeScopes = chatBridgeScopes;
7082
7304
  exports.classifyComplianceError = classifyComplianceError;
7083
7305
  exports.commerceScopes = commerceScopes;
7084
7306
  exports.completeWebAuthorizationRequest = completeWebAuthorizationRequest;
@@ -7111,6 +7333,7 @@ exports.isRegion = isRegion;
7111
7333
  exports.isSSECommentLine = isSSECommentLine;
7112
7334
  exports.isSSLError = isSSLError;
7113
7335
  exports.isTerminalRemoteEvent = isTerminalRemoteEvent;
7336
+ exports.isValidTokenSet = isValidTokenSet;
7114
7337
  exports.maxEndUserIdLength = maxEndUserIdLength;
7115
7338
  exports.modelScopes = modelScopes;
7116
7339
  exports.modelSupportsImageInput = modelSupportsImageInput;
@@ -7120,6 +7343,7 @@ exports.newThinkingConfig = newThinkingConfig;
7120
7343
  exports.newTokenSet = newTokenSet;
7121
7344
  exports.newWebSearchTool = newWebSearchTool;
7122
7345
  exports.normalizeGatewayBaseURL = normalizeGatewayBaseURL;
7346
+ exports.normalizeOverrideBaseURL = normalizeOverrideBaseURL;
7123
7347
  exports.parseNotificationEvent = parseNotificationEvent;
7124
7348
  exports.parseRemoteControlEvent = parseRemoteControlEvent;
7125
7349
  exports.parseSettlement = parseSettlement;