omnigateway 0.12.11 → 0.12.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +1 -0
  2. package/bin/omni.js +488 -119
  3. package/gateway.js +488 -111
  4. package/package.json +1 -1
  5. package/public/assets/{Chip-D4qvhu1D.js → Chip-D0XSbQUr.js} +1 -1
  6. package/public/assets/{CopyValue-SnsT2LML.js → CopyValue-DAlmkISB.js} +3 -3
  7. package/public/assets/{Field-BYBri2NV.js → Field-DG1317zr.js} +1 -1
  8. package/public/assets/Lamp-Dk9XrTCg.js +26 -0
  9. package/public/assets/{Panel-CWmOTDAP.js → Panel-CsovmtxF.js} +23 -4
  10. package/public/assets/Rack-CDUOJkS2.js +483 -0
  11. package/public/assets/{Readout-BTh732hP.js → Readout-DlT5oxGO.js} +1 -1
  12. package/public/assets/RequestTable-i3TtCB9m.js +93 -0
  13. package/public/assets/{SummaryDeck-7ivuca39.js → SummaryDeck-DrzTQQo5.js} +2 -2
  14. package/public/assets/{Toggle-t82IhqEt.js → Toggle-CdMD58sy.js} +1 -1
  15. package/public/assets/{TokenBreakdown-D1Wtza1y.js → TokenBreakdown-BC6nqo1v.js} +1 -1
  16. package/public/assets/{WindowChart-BeGPsccS.js → WindowChart-Bqbl-KFO.js} +2 -2
  17. package/public/assets/_app-CSru2YTE.js +1 -0
  18. package/public/assets/_app.accounts-B2lQkMb0.js +70 -0
  19. package/public/assets/_app.console-a2TJDoBC.js +24 -0
  20. package/public/assets/_app.database-CqSoTi2l.js +24 -0
  21. package/public/assets/_app.index-BV1kJJjA.js +67 -0
  22. package/public/assets/_app.keys-Dq5O0AG9.js +92 -0
  23. package/public/assets/_app.logs-PjRK5wqy.js +46 -0
  24. package/public/assets/_app.models-BfmeeB5e.js +148 -0
  25. package/public/assets/_app.plugins._pluginId-Owb05aFv.js +20 -0
  26. package/public/assets/{_app.settings-C3GzeJ4q.js → _app.settings-5i-vvT-H.js} +7 -7
  27. package/public/assets/_app.usage--5qFtU1W.js +76 -0
  28. package/public/assets/chevron-down-Bb5ZGvwk.js +1 -0
  29. package/public/assets/chevron-right-hwF5mD6-.js +1 -0
  30. package/public/assets/{client-k1tkFSNH.js → client-BcXc3lek.js} +4 -4
  31. package/public/assets/{dist-D03q-60i.js → dist-BBGxva0Y.js} +1 -1
  32. package/public/assets/index-D1RDaq3l.js +14 -0
  33. package/public/assets/{login-DW2Ipp21.js → login-GB0ZGUvA.js} +4 -4
  34. package/public/assets/plus-BgcHxxIr.js +1 -0
  35. package/public/assets/{preload-helper-BPaHpbO_.js → preload-helper-B7KDmXJ9.js} +1 -1
  36. package/public/assets/rotate-ccw-Do43Argv.js +1 -0
  37. package/public/assets/{shared-Dtkw6SE0.js → shared-DDpLUhCp.js} +2 -2
  38. package/public/assets/{trash-D4QWzEK_.js → trash-00950_yY.js} +1 -1
  39. package/public/index.html +5 -5
  40. package/public/assets/Lamp-DkvXKB-B.js +0 -26
  41. package/public/assets/Rack-CEuCdVXc.js +0 -483
  42. package/public/assets/RequestTable-D8L6iVJV.js +0 -93
  43. package/public/assets/_app-Drf03PWk.js +0 -1
  44. package/public/assets/_app.accounts-W1USUo2Q.js +0 -70
  45. package/public/assets/_app.console-Co9d2ZiD.js +0 -44
  46. package/public/assets/_app.database-CtFJLcfE.js +0 -24
  47. package/public/assets/_app.index-DigYfob3.js +0 -67
  48. package/public/assets/_app.keys-B1fRMyU-.js +0 -92
  49. package/public/assets/_app.logs-CFixPsUw.js +0 -60
  50. package/public/assets/_app.models-Dpl1O2RE.js +0 -148
  51. package/public/assets/_app.plugins._pluginId-BK0ADugW.js +0 -20
  52. package/public/assets/_app.usage-D2qlcEp4.js +0 -76
  53. package/public/assets/chevron-down-Bs0tSOyA.js +0 -1
  54. package/public/assets/chevron-right-DSaI1kFo.js +0 -1
  55. package/public/assets/index-Bk9sabex.js +0 -14
  56. package/public/assets/plus-BCfjC6nk.js +0 -1
package/bin/omni.js CHANGED
@@ -24739,12 +24739,18 @@ var ANTHROPIC_MODELS = {
24739
24739
  };
24740
24740
  var ONE_M_SUFFIX = "[1m]";
24741
24741
  var DATED_SUFFIX = /-\d{8}$/;
24742
- function anthropicReasoningForm(model) {
24742
+ function anthropicChoice(model) {
24743
24743
  let id = model.trim();
24744
24744
  if (id.toLowerCase().endsWith(ONE_M_SUFFIX))
24745
24745
  id = id.slice(0, -ONE_M_SUFFIX.length).trim();
24746
24746
  id = id.replace(DATED_SUFFIX, "");
24747
- return ANTHROPIC_MODELS.models.find((m) => m.id === id)?.reasoningForm ?? "adaptive";
24747
+ return ANTHROPIC_MODELS.models.find((m) => m.id === id);
24748
+ }
24749
+ function anthropicReasoningForm(model) {
24750
+ return anthropicChoice(model)?.reasoningForm ?? "adaptive";
24751
+ }
24752
+ function anthropicMaxOutputTokens(model) {
24753
+ return anthropicChoice(model)?.limits.maxOutputTokens;
24748
24754
  }
24749
24755
 
24750
24756
  // packages/providers/src/anthropic/descriptor.ts
@@ -25635,7 +25641,8 @@ function codecAdapter(id, capabilities2, codec2, origins) {
25635
25641
  credentials: req.credentials,
25636
25642
  fail,
25637
25643
  ...req.requestId === undefined ? {} : { requestId: req.requestId },
25638
- ...req.autoCache === undefined ? {} : { autoCacheEnabled: req.autoCache }
25644
+ ...req.autoCache === undefined ? {} : { autoCacheEnabled: req.autoCache },
25645
+ ...req.maxOutputTokens === undefined ? {} : { maxOutputTokens: req.maxOutputTokens }
25639
25646
  }));
25640
25647
  const described = built?.request ?? {};
25641
25648
  const request2 = {
@@ -27073,6 +27080,69 @@ function systemText(system, provider, note2) {
27073
27080
  `);
27074
27081
  }
27075
27082
 
27083
+ // packages/providers/src/toolResultFiles.ts
27084
+ function isTextual(mediaType) {
27085
+ const type = mediaType.split(";")[0]?.trim().toLowerCase() ?? "";
27086
+ return type.startsWith("text/") || type.endsWith("+json") || type.endsWith("+xml") || TEXTUAL.has(type);
27087
+ }
27088
+ var TEXTUAL = new Set([
27089
+ "application/json",
27090
+ "application/x-ndjson",
27091
+ "application/xml",
27092
+ "application/yaml",
27093
+ "application/x-yaml",
27094
+ "application/toml",
27095
+ "application/javascript",
27096
+ "application/typescript",
27097
+ "application/sql",
27098
+ "application/x-sh",
27099
+ "message/rfc822"
27100
+ ]);
27101
+ function fileText(file2) {
27102
+ return Buffer.from(file2.data, "base64").toString("utf8");
27103
+ }
27104
+ function splitFiles(files, carries) {
27105
+ const text = [];
27106
+ const carried = [];
27107
+ let dropped = false;
27108
+ for (const file2 of files) {
27109
+ if (isTextual(file2.mediaType))
27110
+ text.push(fileText(file2));
27111
+ else if (carries(file2.mediaType))
27112
+ carried.push(file2);
27113
+ else
27114
+ dropped = true;
27115
+ }
27116
+ return { text, carried, dropped };
27117
+ }
27118
+ function withFileText(content, text) {
27119
+ return [content, ...text].filter((t) => t.length > 0).join(`
27120
+
27121
+ `);
27122
+ }
27123
+ var RESPONSES_FILE_TYPES = Object.assign(Object.create(null), {
27124
+ "application/pdf": "pdf",
27125
+ "application/rtf": "rtf",
27126
+ "application/msword": "doc",
27127
+ "application/vnd.ms-excel": "xls",
27128
+ "application/vnd.ms-powerpoint": "ppt",
27129
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
27130
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
27131
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx"
27132
+ });
27133
+ function fileName(file2) {
27134
+ return file2.filename ?? `file.${RESPONSES_FILE_TYPES[file2.mediaType] ?? "bin"}`;
27135
+ }
27136
+ function responsesFiles(files) {
27137
+ const { text, carried, dropped } = splitFiles(files, (t) => (t in RESPONSES_FILE_TYPES));
27138
+ const parts = carried.map((file2) => ({
27139
+ type: "input_file",
27140
+ filename: fileName(file2),
27141
+ file_data: `data:${file2.mediaType};base64,${file2.data}`
27142
+ }));
27143
+ return { parts, text, dropped };
27144
+ }
27145
+
27076
27146
  // packages/providers/src/anthropic/wire.ts
27077
27147
  var OAUTH_IDENTITY = "You are Claude Code, Anthropic's official CLI for Claude.";
27078
27148
  function wireCacheControl(c) {
@@ -27110,22 +27180,13 @@ function encodeBlock(b, cloak) {
27110
27180
  ...cache
27111
27181
  };
27112
27182
  case "toolResult": {
27113
- const documents = (b.files ?? []).flatMap((file2) => {
27114
- const source = file2.mediaType === "application/pdf" ? { type: "base64", media_type: file2.mediaType, data: file2.data } : file2.mediaType === "text/plain" ? {
27115
- type: "text",
27116
- media_type: file2.mediaType,
27117
- data: Buffer.from(file2.data, "base64").toString("utf8")
27118
- } : undefined;
27119
- if (source === undefined)
27120
- return [];
27121
- return [
27122
- {
27123
- type: "document",
27124
- source,
27125
- ...file2.filename !== undefined && { title: file2.filename }
27126
- }
27127
- ];
27128
- });
27183
+ const files = splitFiles(b.files ?? [], (t) => t === "application/pdf");
27184
+ const text = withFileText(b.content, files.text);
27185
+ const documents = files.carried.map((file2) => ({
27186
+ type: "document",
27187
+ source: { type: "base64", media_type: file2.mediaType, data: file2.data },
27188
+ ...file2.filename !== undefined && { title: file2.filename }
27189
+ }));
27129
27190
  const parts = [
27130
27191
  ...(b.images ?? []).map((image) => encodeBlock(image, cloak)),
27131
27192
  ...documents,
@@ -27134,7 +27195,7 @@ function encodeBlock(b, cloak) {
27134
27195
  return {
27135
27196
  type: "tool_result",
27136
27197
  tool_use_id: b.toolUseId,
27137
- content: parts.length === 0 ? b.content : [...b.content.length > 0 ? [{ type: "text", text: b.content }] : [], ...parts],
27198
+ content: parts.length === 0 ? text : [...text.length > 0 ? [{ type: "text", text }] : [], ...parts],
27138
27199
  is_error: b.isError,
27139
27200
  ...cache
27140
27201
  };
@@ -27286,6 +27347,12 @@ function addAutoCacheBreakpoints(body, req, note2) {
27286
27347
  lastHistory.cache_control = { type: "ephemeral" };
27287
27348
  note2("anthropic:history-cache-breakpoint-added");
27288
27349
  }
27350
+ function defaultMaxTokens(model, saved) {
27351
+ const ceiling = anthropicMaxOutputTokens(model);
27352
+ if (saved === undefined)
27353
+ return ceiling ?? 4096;
27354
+ return ceiling === undefined ? saved : Math.min(saved, ceiling);
27355
+ }
27289
27356
  function toWire(req, model, opts) {
27290
27357
  const cloak = opts.cloak ?? null;
27291
27358
  const degradations = [];
@@ -27310,8 +27377,12 @@ function toWire(req, model, opts) {
27310
27377
  note2("anthropic:system-turn-cache-control-dropped");
27311
27378
  for (const m of req.messages) {
27312
27379
  for (const b of m.content) {
27313
- if (b.type === "toolResult" && b.files?.some((f) => f.mediaType !== "application/pdf" && f.mediaType !== "text/plain")) {
27314
- note2("anthropic:files-dropped");
27380
+ if (b.type === "toolResult" && b.files !== undefined) {
27381
+ const files = splitFiles(b.files, (t) => t === "application/pdf");
27382
+ if (files.text.length > 0)
27383
+ note2("anthropic:tool-result-files-inlined");
27384
+ if (files.dropped)
27385
+ note2("anthropic:files-dropped");
27315
27386
  }
27316
27387
  }
27317
27388
  }
@@ -27328,7 +27399,7 @@ function toWire(req, model, opts) {
27328
27399
  }
27329
27400
  return [{ role: m.role, content: encodeSystemTurn(m.content, cloak) }];
27330
27401
  }),
27331
- max_tokens: req.maxTokens ?? 4096,
27402
+ max_tokens: req.maxTokens ?? defaultMaxTokens(model, opts.maxOutputTokens),
27332
27403
  stream: req.stream
27333
27404
  };
27334
27405
  if (systemCache.retarget !== undefined) {
@@ -27467,7 +27538,8 @@ var anthropicCodec = {
27467
27538
  const { body, degradations } = toWire(input2.request, input2.model, {
27468
27539
  oauth,
27469
27540
  cloak,
27470
- autoCache: input2.autoCacheEnabled === true
27541
+ autoCache: input2.autoCacheEnabled === true,
27542
+ ...input2.maxOutputTokens === undefined ? {} : { maxOutputTokens: input2.maxOutputTokens }
27471
27543
  });
27472
27544
  const firstUser = input2.request.messages.find((m) => m.role === "user");
27473
27545
  const firstText = firstUser?.content.find((b) => b.type === "text");
@@ -27800,8 +27872,125 @@ var anthropicOAuthFlow = {
27800
27872
  if (!usageReadable(res.status, "anthropic"))
27801
27873
  return null;
27802
27874
  return parseAnthropicUsage(parsed(res.body), now());
27875
+ },
27876
+ async* resetCredits({ secrets }) {
27877
+ if (secrets.accessToken === null)
27878
+ return null;
27879
+ const res = yield getJsonRequest(RESET_STATUS_URL, anthropicProfile, {
27880
+ accessToken: secrets.accessToken,
27881
+ extraHeaders: SIDE_HEADERS
27882
+ });
27883
+ if (!usageReadable(res.status, "anthropic"))
27884
+ return null;
27885
+ const root = recordOf(parsed(res.body));
27886
+ return root === null ? null : parseResetGrants(root.cedar_ember ?? null);
27887
+ },
27888
+ async* redeemReset({ secrets, creditId, requestId, fail }) {
27889
+ if (secrets.accessToken === null)
27890
+ throw fail("AUTH", "credential holds no access token");
27891
+ const grantId = grantOf(creditId);
27892
+ if (grantId === null)
27893
+ throw fail("CONFLICT", "that reset credit is not available");
27894
+ const profile = yield getJsonRequest(PROFILE_URL, anthropicProfile, {
27895
+ accessToken: secrets.accessToken,
27896
+ extraHeaders: SIDE_HEADERS
27897
+ });
27898
+ if (profile.status < 200 || profile.status >= 300) {
27899
+ throw fail(redeemErrorCode(profile.status), `profile read refused: http_${profile.status}`, {
27900
+ status: profile.status
27901
+ });
27902
+ }
27903
+ const orgId = orgIdOf(parsed(profile.body));
27904
+ if (orgId === null)
27905
+ throw fail("UPSTREAM", "profile names no organization");
27906
+ const res = yield postJsonRequest(`https://api.anthropic.com/api/organizations/${orgId}/reset_rate_limits`, anthropicProfile, {
27907
+ contentType: "application/json",
27908
+ body: JSON.stringify({ program: RESET_PROGRAM, grant_id: grantId, request_id: requestId }),
27909
+ extraHeaders: [["Authorization", `Bearer ${secrets.accessToken}`], ...SIDE_HEADERS]
27910
+ });
27911
+ if (res.status < 200 || res.status >= 300) {
27912
+ throw fail(redeemErrorCode(res.status), `reset claim refused: http_${res.status}`, {
27913
+ status: res.status
27914
+ });
27915
+ }
27916
+ return claimOutcome(parsed(res.body), fail);
27803
27917
  }
27804
27918
  };
27919
+ var RESET_PROGRAM = "cedar_ember";
27920
+ var RESET_STATUS_URL = `${USAGE_URL}?cedar_ember=1&skip_spend=1`;
27921
+ var PROFILE_URL = "https://api.anthropic.com/api/oauth/profile";
27922
+ var ORG_ID = /^[A-Za-z0-9-]{1,64}$/;
27923
+ var SIDE_HEADERS = [["anthropic-beta", "oauth-2025-04-20"]];
27924
+ var USE_SUFFIX = /-u(\d+)$/;
27925
+ function creditIdOf(grantId, left) {
27926
+ return `${grantId}-u${left}`;
27927
+ }
27928
+ function grantOf(creditId) {
27929
+ const grant = creditId.replace(USE_SUFFIX, "");
27930
+ return grant === creditId || grant === "" ? null : grant;
27931
+ }
27932
+ function orgIdOf(value) {
27933
+ const org = recordOf(recordOf(value)?.organization);
27934
+ const uuid3 = org?.uuid;
27935
+ return typeof uuid3 === "string" && ORG_ID.test(uuid3) ? uuid3 : null;
27936
+ }
27937
+ function parseResetGrants(value) {
27938
+ if (value === null)
27939
+ return { available: 0, credits: [] };
27940
+ const block = recordOf(value);
27941
+ if (block === null || !Array.isArray(block.grants))
27942
+ return null;
27943
+ const next = typeof block.next_grant_id === "string" ? block.next_grant_id : null;
27944
+ const atLimit = block.at_limit === true;
27945
+ let available = 0;
27946
+ const credits = block.grants.flatMap((raw) => {
27947
+ const g = recordOf(raw);
27948
+ if (g === null || typeof g.id !== "string")
27949
+ return [];
27950
+ const left = typeof g.resets_left === "number" ? g.resets_left : 0;
27951
+ const claimable = left > 0 && g.usable_now === true && g.paused !== true && (g.use_requires_limit !== true || atLimit) && (next === null || next === g.id);
27952
+ if (claimable)
27953
+ available += left;
27954
+ return [
27955
+ {
27956
+ id: creditIdOf(g.id, left),
27957
+ status: claimable ? "available" : left > 0 ? "unavailable" : "used",
27958
+ title: typeof g.label === "string" && g.label !== "" ? g.label : null,
27959
+ grantedAt: isoOrNull(g.starts_at),
27960
+ expiresAt: isoOrNull(g.ends_at)
27961
+ }
27962
+ ];
27963
+ });
27964
+ return { available, credits };
27965
+ }
27966
+ function claimOutcome(value, fail) {
27967
+ const body = recordOf(value);
27968
+ const result = typeof body?.result === "string" ? body.result : null;
27969
+ if (result === "reset") {
27970
+ return { windowsReset: Array.isArray(body?.cleared) ? body.cleared.length : null };
27971
+ }
27972
+ if (result === "cooldown")
27973
+ throw fail("RATE_LIMIT", "reset claim refused: cooldown");
27974
+ if (result === "already_used" || result === "not_limited" || result === "ineligible") {
27975
+ throw fail("CONFLICT", `reset claim refused: ${result}`);
27976
+ }
27977
+ throw fail("UPSTREAM", "reset claim answered without a reset");
27978
+ }
27979
+ function redeemErrorCode(status) {
27980
+ if (status === 429)
27981
+ return "RATE_LIMIT";
27982
+ if (status === 401 || status === 403)
27983
+ return "AUTH";
27984
+ if (status >= 400 && status < 500)
27985
+ return "CONFLICT";
27986
+ return "UPSTREAM";
27987
+ }
27988
+ function isoOrNull(value) {
27989
+ if (typeof value !== "string")
27990
+ return null;
27991
+ const at = Date.parse(value);
27992
+ return Number.isNaN(at) ? null : at;
27993
+ }
27805
27994
  // packages/providers/src/antigravity/codec.ts
27806
27995
  import { createHash as createHash2 } from "crypto";
27807
27996
 
@@ -28406,16 +28595,19 @@ function toAntigravityWire(req, model, identity) {
28406
28595
  note2("antigravity:tool-result-unmatched");
28407
28596
  if (block.isError === true)
28408
28597
  note2("antigravity:tool-result-error-flag-dropped");
28598
+ const files = splitFiles(block.files ?? [], () => true);
28599
+ if (files.text.length > 0)
28600
+ note2("antigravity:tool-result-files-inlined");
28409
28601
  parts.push({
28410
28602
  functionResponse: {
28411
28603
  name: cloakName2(cloak, name ?? block.toolUseId),
28412
- response: { output: block.content }
28604
+ response: { output: withFileText(block.content, files.text) }
28413
28605
  }
28414
28606
  });
28415
28607
  for (const image of block.images ?? []) {
28416
28608
  parts.push({ inlineData: { mimeType: image.mediaType, data: image.data } });
28417
28609
  }
28418
- for (const file2 of block.files ?? []) {
28610
+ for (const file2 of files.carried) {
28419
28611
  parts.push({ inlineData: { mimeType: file2.mediaType, data: file2.data } });
28420
28612
  }
28421
28613
  role = "user";
@@ -29120,7 +29312,7 @@ var grokOAuthFlow = {
29120
29312
 
29121
29313
  // packages/providers/src/kilo/oauth.ts
29122
29314
  var CODES_URL = "https://api.kilo.ai/api/device-auth/codes";
29123
- var PROFILE_URL = "https://api.kilo.ai/api/profile";
29315
+ var PROFILE_URL2 = "https://api.kilo.ai/api/profile";
29124
29316
  var FALLBACK_VERIFICATION_URL = "https://kilo.ai";
29125
29317
  var DEFAULT_EXPIRES_SECONDS = 300;
29126
29318
  var POLL_INTERVAL_SECONDS = 3;
@@ -29152,7 +29344,7 @@ function deviceCodeFrom(value, fail) {
29152
29344
  }
29153
29345
  async function* orgIdFor(accessToken) {
29154
29346
  try {
29155
- const res = yield getJsonRequest(PROFILE_URL, kiloProfile, { accessToken });
29347
+ const res = yield getJsonRequest(PROFILE_URL2, kiloProfile, { accessToken });
29156
29348
  if (res.status < 200 || res.status >= 300)
29157
29349
  return null;
29158
29350
  const record2 = recordFrom(parsed(res.body));
@@ -29660,6 +29852,7 @@ var AUTHORIZE_URL3 = "https://auth.openai.com/oauth/authorize";
29660
29852
  var TOKEN_URL5 = "https://auth.openai.com/oauth/token";
29661
29853
  var SCOPES4 = "openid profile email offline_access";
29662
29854
  var USAGE_URL3 = "https://chatgpt.com/backend-api/wham/usage";
29855
+ var RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits";
29663
29856
  function isRecord7(value) {
29664
29857
  return typeof value === "object" && value !== null;
29665
29858
  }
@@ -29813,8 +30006,78 @@ var openaiOAuthFlow = {
29813
30006
  if (!usageReadable(res.status, "openai"))
29814
30007
  return null;
29815
30008
  return parseOpenAIUsage(parsed(res.body), now());
30009
+ },
30010
+ async* resetCredits({ secrets, providerData }) {
30011
+ if (secrets.accessToken === null)
30012
+ return null;
30013
+ const res = yield getJsonRequest(RESET_CREDITS_URL, openaiProfile, {
30014
+ accessToken: secrets.accessToken,
30015
+ extraHeaders: accountHeader(providerData)
30016
+ });
30017
+ if (!usageReadable(res.status, "openai"))
30018
+ return null;
30019
+ return parseResetCredits(parsed(res.body));
30020
+ },
30021
+ async* redeemReset({ secrets, providerData, creditId, requestId, fail }) {
30022
+ if (secrets.accessToken === null)
30023
+ throw fail("AUTH", "credential holds no access token");
30024
+ const res = yield postJsonRequest(`${RESET_CREDITS_URL}/consume`, openaiProfile, {
30025
+ contentType: "application/json",
30026
+ body: JSON.stringify({ credit_id: creditId, redeem_request_id: requestId }),
30027
+ extraHeaders: [
30028
+ ["Authorization", `Bearer ${secrets.accessToken}`],
30029
+ ...accountHeader(providerData)
30030
+ ]
30031
+ });
30032
+ if (res.status < 200 || res.status >= 300) {
30033
+ throw fail(redeemErrorCode2(res.status), `reset credit redeem refused: http_${res.status}`, {
30034
+ status: res.status
30035
+ });
30036
+ }
30037
+ const body = recordOf(parsed(res.body));
30038
+ const windowsReset = body === null ? null : numberOf(body, ["windows_reset"]);
30039
+ return { windowsReset };
29816
30040
  }
29817
30041
  };
30042
+ function accountHeader(providerData) {
30043
+ const accountId = accountIdFromProviderData(providerData);
30044
+ return accountId === null ? [] : [["chatgpt-account-id", accountId]];
30045
+ }
30046
+ function redeemErrorCode2(status) {
30047
+ if (status === 429)
30048
+ return "RATE_LIMIT";
30049
+ if (status === 401 || status === 403)
30050
+ return "AUTH";
30051
+ if (status >= 400 && status < 500)
30052
+ return "CONFLICT";
30053
+ return "UPSTREAM";
30054
+ }
30055
+ function isoOrNull2(value) {
30056
+ if (typeof value !== "string")
30057
+ return null;
30058
+ const at = Date.parse(value);
30059
+ return Number.isFinite(at) ? at : null;
30060
+ }
30061
+ function parseResetCredits(value) {
30062
+ const root = recordOf(value);
30063
+ if (root === null || !Array.isArray(root.credits))
30064
+ return null;
30065
+ const credits = root.credits.flatMap((raw) => {
30066
+ const c = recordOf(raw);
30067
+ if (c === null || typeof c.id !== "string" || typeof c.status !== "string")
30068
+ return [];
30069
+ return [
30070
+ {
30071
+ id: c.id,
30072
+ status: c.status,
30073
+ title: typeof c.title === "string" ? c.title : null,
30074
+ grantedAt: isoOrNull2(c.granted_at),
30075
+ expiresAt: isoOrNull2(c.expires_at)
30076
+ }
30077
+ ];
30078
+ });
30079
+ return { available: credits.filter((c) => c.status === "available").length, credits };
30080
+ }
29818
30081
 
29819
30082
  // packages/providers/src/builtinOAuth.ts
29820
30083
  function builtinOAuthFlows() {
@@ -30158,61 +30421,6 @@ async function* decodeCustomResponses(messages) {
30158
30421
  }
30159
30422
  }
30160
30423
 
30161
- // packages/providers/src/responsesFile.ts
30162
- var ACCEPTED = new Set([
30163
- "application/pdf",
30164
- "text/plain",
30165
- "text/csv",
30166
- "text/markdown",
30167
- "text/html",
30168
- "text/css",
30169
- "text/xml",
30170
- "text/calendar",
30171
- "text/tab-separated-values",
30172
- "text/javascript",
30173
- "text/x-python",
30174
- "text/x-c",
30175
- "text/x-java",
30176
- "text/x-sh",
30177
- "text/x-sql",
30178
- "text/x-typescript",
30179
- "text/x-yaml",
30180
- "application/json",
30181
- "application/javascript",
30182
- "application/typescript",
30183
- "application/toml",
30184
- "application/yaml",
30185
- "application/x-yaml",
30186
- "message/rfc822",
30187
- "application/rtf",
30188
- "application/msword",
30189
- "application/vnd.ms-excel",
30190
- "application/vnd.ms-powerpoint",
30191
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
30192
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
30193
- "application/vnd.openxmlformats-officedocument.presentationml.presentation"
30194
- ]);
30195
- var TEXTUAL = new Set(["application/xml", "application/sql", "application/x-sh"]);
30196
- function responsesFiles(files) {
30197
- const parts = [];
30198
- const text = [];
30199
- let dropped = false;
30200
- for (const file2 of files) {
30201
- if (ACCEPTED.has(file2.mediaType)) {
30202
- parts.push({
30203
- type: "input_file",
30204
- ...file2.filename !== undefined && { filename: file2.filename },
30205
- file_data: `data:${file2.mediaType};base64,${file2.data}`
30206
- });
30207
- } else if (file2.mediaType.startsWith("text/") || TEXTUAL.has(file2.mediaType)) {
30208
- text.push(Buffer.from(file2.data, "base64").toString("utf8"));
30209
- } else {
30210
- dropped = true;
30211
- }
30212
- }
30213
- return { parts, text, dropped };
30214
- }
30215
-
30216
30424
  // packages/providers/src/custom/wire.ts
30217
30425
  function encodeChatToolChoice(c) {
30218
30426
  switch (c.type) {
@@ -30276,19 +30484,23 @@ function toCustomChatWire(req, model) {
30276
30484
  function: { name: block.name, arguments: JSON.stringify(block.input) }
30277
30485
  });
30278
30486
  break;
30279
- case "toolResult":
30487
+ case "toolResult": {
30280
30488
  if (block.native !== undefined)
30281
30489
  note2("custom:anthropic-native-block-dropped");
30490
+ const files = splitFiles(block.files ?? [], () => false);
30282
30491
  messages.push({
30283
30492
  role: "tool",
30284
30493
  tool_call_id: block.toolUseId,
30285
- content: block.content
30494
+ content: withFileText(block.content, files.text)
30286
30495
  });
30287
30496
  if (block.images !== undefined)
30288
30497
  note2("custom:images-dropped");
30289
- if (block.files !== undefined)
30498
+ if (files.text.length > 0)
30499
+ note2("custom:tool-result-files-inlined");
30500
+ if (files.dropped)
30290
30501
  note2("custom:files-dropped");
30291
30502
  break;
30503
+ }
30292
30504
  case "providerNative":
30293
30505
  note2("custom:anthropic-native-block-dropped");
30294
30506
  break;
@@ -30410,9 +30622,7 @@ function toCustomResponsesWire(req, model) {
30410
30622
  input2.push({
30411
30623
  type: "function_call_output",
30412
30624
  call_id: block.toolUseId,
30413
- output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
30414
-
30415
- `)
30625
+ output: withFileText(block.content, files.text)
30416
30626
  });
30417
30627
  if (block.images !== undefined) {
30418
30628
  note2("custom:tool-result-images-moved");
@@ -30798,9 +31008,7 @@ function toGrokWire(req, model) {
30798
31008
  input2.push({
30799
31009
  type: "function_call_output",
30800
31010
  call_id: block.toolUseId,
30801
- output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
30802
-
30803
- `)
31011
+ output: withFileText(block.content, files.text)
30804
31012
  });
30805
31013
  if (block.images !== undefined) {
30806
31014
  note2("grok:tool-result-images-moved");
@@ -31258,15 +31466,20 @@ function toKiloWire(req, model) {
31258
31466
  function: { name: block.name, arguments: JSON.stringify(block.input) }
31259
31467
  });
31260
31468
  break;
31261
- case "toolResult":
31469
+ case "toolResult": {
31262
31470
  if (block.native !== undefined)
31263
31471
  note2("kilo:anthropic-native-block-dropped");
31264
31472
  flush();
31473
+ const files = splitFiles(block.files ?? [], (t) => t === "application/pdf");
31265
31474
  messages.push({
31266
31475
  role: "tool",
31267
31476
  tool_call_id: block.toolUseId,
31268
- content: block.content
31477
+ content: withFileText(block.content, files.text)
31269
31478
  });
31479
+ if (files.text.length > 0)
31480
+ note2("kilo:tool-result-files-inlined");
31481
+ if (files.dropped)
31482
+ note2("kilo:files-dropped");
31270
31483
  for (const image of block.images ?? []) {
31271
31484
  note2("kilo:tool-result-images-moved");
31272
31485
  toolImages.push({
@@ -31274,17 +31487,18 @@ function toKiloWire(req, model) {
31274
31487
  image_url: { url: `data:${image.mediaType};base64,${image.data}` }
31275
31488
  });
31276
31489
  }
31277
- for (const file2 of block.files ?? []) {
31490
+ for (const file2 of files.carried) {
31278
31491
  note2("kilo:tool-result-files-moved");
31279
31492
  toolImages.push({
31280
31493
  type: "file",
31281
31494
  file: {
31282
- ...file2.filename !== undefined && { filename: file2.filename },
31495
+ filename: fileName(file2),
31283
31496
  file_data: `data:${file2.mediaType};base64,${file2.data}`
31284
31497
  }
31285
31498
  });
31286
31499
  }
31287
31500
  break;
31501
+ }
31288
31502
  case "providerNative":
31289
31503
  note2("kilo:anthropic-native-block-dropped");
31290
31504
  break;
@@ -31538,19 +31752,23 @@ function toChatWire(req, model, vendor = "kimi") {
31538
31752
  function: { name: block.name, arguments: JSON.stringify(block.input) }
31539
31753
  });
31540
31754
  break;
31541
- case "toolResult":
31755
+ case "toolResult": {
31542
31756
  if (block.native !== undefined)
31543
31757
  note2("kimi:anthropic-native-block-dropped");
31758
+ const files = splitFiles(block.files ?? [], () => false);
31544
31759
  messages.push({
31545
31760
  role: "tool",
31546
31761
  tool_call_id: block.toolUseId,
31547
- content: block.content
31762
+ content: withFileText(block.content, files.text)
31548
31763
  });
31549
31764
  if (block.images !== undefined)
31550
31765
  note2("kimi:images-dropped");
31551
- if (block.files !== undefined)
31766
+ if (files.text.length > 0)
31767
+ note2("kimi:tool-result-files-inlined");
31768
+ if (files.dropped)
31552
31769
  note2("kimi:files-dropped");
31553
31770
  break;
31771
+ }
31554
31772
  case "providerNative":
31555
31773
  note2("kimi:anthropic-native-block-dropped");
31556
31774
  break;
@@ -31957,9 +32175,7 @@ function toMuseWire(req, model) {
31957
32175
  input2.push({
31958
32176
  type: "function_call_output",
31959
32177
  call_id: block.toolUseId,
31960
- output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
31961
-
31962
- `)
32178
+ output: withFileText(block.content, files.text)
31963
32179
  });
31964
32180
  if (block.images !== undefined) {
31965
32181
  note2("muse:tool-result-images-moved");
@@ -32385,9 +32601,7 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
32385
32601
  input2.push({
32386
32602
  type: "function_call_output",
32387
32603
  call_id: block.toolUseId,
32388
- output: [block.content, ...files.text].filter((t) => t.length > 0).join(`
32389
-
32390
- `)
32604
+ output: withFileText(block.content, files.text)
32391
32605
  });
32392
32606
  if (block.images !== undefined) {
32393
32607
  note2("openai:tool-result-images-moved");
@@ -32794,6 +33008,11 @@ var quotaRefreshSchema = exports_external.discriminatedUnion("kind", [
32794
33008
  }).strict(),
32795
33009
  exports_external.object({ kind: exports_external.literal("all") }).strict()
32796
33010
  ]);
33011
+ var accountIdSchema = exports_external.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/, "credentialId must be an account id");
33012
+ var redeemResetSchema = exports_external.object({
33013
+ credentialId: accountIdSchema,
33014
+ creditId: exports_external.string().min(1).max(128).regex(/^[A-Za-z0-9_-]+$/).optional()
33015
+ }).strict();
32797
33016
  var dimensionSchema = exports_external.enum([
32798
33017
  "credential",
32799
33018
  "model",
@@ -35203,6 +35422,29 @@ function oauthAdapter(id, flow, opts = {}) {
35203
35422
  return Promise.resolve(null);
35204
35423
  return runStep(id, "usage", step, deps, origins);
35205
35424
  }
35425
+ },
35426
+ ...flow.resetCredits === undefined ? {} : {
35427
+ resetCredits: (secrets, deps, providerData) => {
35428
+ const step = flow.resetCredits?.({ secrets, providerData, ...helpers(deps) });
35429
+ if (step === undefined)
35430
+ return Promise.resolve(null);
35431
+ return runStep(id, "resetCredits", step, deps, origins);
35432
+ }
35433
+ },
35434
+ ...flow.redeemReset === undefined ? {} : {
35435
+ redeemReset: (secrets, deps, providerData, creditId, requestId) => {
35436
+ const step = flow.redeemReset?.({
35437
+ secrets,
35438
+ providerData,
35439
+ creditId,
35440
+ requestId,
35441
+ ...helpers(deps)
35442
+ });
35443
+ if (step === undefined) {
35444
+ return Promise.reject(flowFailure(id, "redeemReset", "has no redeem step"));
35445
+ }
35446
+ return runStep(id, "redeemReset", step, deps, origins);
35447
+ }
35206
35448
  }
35207
35449
  };
35208
35450
  if (flow.kind === "pkce")
@@ -35238,11 +35480,32 @@ function isAuthorizeStart(value) {
35238
35480
  const candidate = value;
35239
35481
  return typeof candidate.authorizeUrl === "string" && typeof candidate.pending === "object" && candidate.pending !== null;
35240
35482
  }
35483
+ function isResetCreditsOrNull(value) {
35484
+ if (value === null)
35485
+ return true;
35486
+ if (typeof value !== "object")
35487
+ return false;
35488
+ const candidate = value;
35489
+ return typeof candidate.available === "number" && Array.isArray(candidate.credits) && candidate.credits.every((c) => {
35490
+ if (typeof c !== "object" || c === null)
35491
+ return false;
35492
+ const row = c;
35493
+ return typeof row.id === "string" && typeof row.status === "string" && (row.title === null || typeof row.title === "string") && (row.grantedAt === null || typeof row.grantedAt === "number") && (row.expiresAt === null || typeof row.expiresAt === "number");
35494
+ });
35495
+ }
35496
+ function isResetRedeemed(value) {
35497
+ if (typeof value !== "object" || value === null)
35498
+ return false;
35499
+ const held = value.windowsReset;
35500
+ return held === null || typeof held === "number";
35501
+ }
35241
35502
  var RETURN_SHAPE = {
35242
35503
  start: isAuthorizeStart,
35243
35504
  begin: isAuthorizeStart,
35244
35505
  exchange: isFlowResult,
35245
- refresh: isFlowResult
35506
+ refresh: isFlowResult,
35507
+ resetCredits: isResetCreditsOrNull,
35508
+ redeemReset: isResetRedeemed
35246
35509
  };
35247
35510
 
35248
35511
  // packages/control/src/oauth/index.ts
@@ -35462,6 +35725,11 @@ function validateOAuthFlow(id, value) {
35462
35725
  if (value.usage !== undefined) {
35463
35726
  checkAt(typeof value.usage === "function", id, "oauth.usage", "a function");
35464
35727
  }
35728
+ for (const fn of ["resetCredits", "redeemReset"]) {
35729
+ if (value[fn] !== undefined) {
35730
+ checkAt(typeof value[fn] === "function", id, `oauth.${fn}`, "a function");
35731
+ }
35732
+ }
35465
35733
  if (kind === "device") {
35466
35734
  checkAt(typeof value.begin === "function", id, "oauth.begin", "a function");
35467
35735
  checkAt(typeof value.needsDeviceId === "boolean", id, "oauth.needsDeviceId", "a boolean");
@@ -35657,6 +35925,52 @@ async function quotaHistory(deps, input2) {
35657
35925
 
35658
35926
  // packages/control/src/quota/clientHistory.ts
35659
35927
  var MAX_SPAN_MS = 16 * 24 * 60 * 60 * 1000;
35928
+ // packages/control/src/quota/resets.ts
35929
+ async function resettable(deps, credentialId) {
35930
+ const credential = await deps.store.credentials.get(credentialId.trim());
35931
+ if (credential === null)
35932
+ throw new GatewayError("BAD_REQUEST", "no such credential");
35933
+ const provider = deps.providers[credential.provider];
35934
+ const list = provider?.resetCredits;
35935
+ const redeem = provider?.redeemReset;
35936
+ if (credential.authType !== "oauth" || list === undefined || redeem === undefined) {
35937
+ throw new GatewayError("BAD_REQUEST", "this account's provider has no quota resets");
35938
+ }
35939
+ return { credential, list, redeem };
35940
+ }
35941
+ async function listFor(deps, r) {
35942
+ const secrets = await usageSecretsFor(deps, r.credential);
35943
+ const read = await r.list(secrets, { http: deps.http, now: deps.now }, r.credential.providerData);
35944
+ if (read === null) {
35945
+ throw new GatewayError("UPSTREAM", "provider answered the reset list with nothing usable", {
35946
+ gatewayAuthored: true
35947
+ });
35948
+ }
35949
+ return read;
35950
+ }
35951
+ async function listResetCredits(deps, credentialId) {
35952
+ const r = await resettable(deps, credentialId);
35953
+ return { credentialId: r.credential.id, ...await listFor(deps, r) };
35954
+ }
35955
+ async function redeemResetCredit(deps, request2) {
35956
+ const r = await resettable(deps, request2.credentialId);
35957
+ return deps.coord.mutex.withLock(PROBE_LOCK_PREFIX + r.credential.id, PROBE_LOCK_TTL_MS, PROBE_LOCK_WAIT_MS, () => redeemLocked(deps, r, request2));
35958
+ }
35959
+ async function redeemLocked(deps, r, request2) {
35960
+ const available = (await listFor(deps, r)).credits.filter((c) => c.status === "available").sort((a, b) => (a.expiresAt ?? Number.POSITIVE_INFINITY) - (b.expiresAt ?? Number.POSITIVE_INFINITY));
35961
+ const credit = request2.creditId === undefined ? available[0] : available.find((c) => c.id === request2.creditId);
35962
+ if (credit === undefined) {
35963
+ throw new GatewayError("CONFLICT", request2.creditId === undefined ? "no reset credit is available for this account" : "that reset credit is not available");
35964
+ }
35965
+ const secrets = await usageSecretsFor(deps, r.credential);
35966
+ const { windowsReset } = await r.redeem(secrets, { http: deps.http, now: deps.now }, r.credential.providerData, credit.id, crypto.randomUUID());
35967
+ let quotaRefreshed = false;
35968
+ try {
35969
+ quotaRefreshed = await probe(deps, r.credential) !== null;
35970
+ } catch {}
35971
+ return { credentialId: r.credential.id, creditId: credit.id, windowsReset, quotaRefreshed };
35972
+ }
35973
+
35660
35974
  // packages/control/src/quota/poll.ts
35661
35975
  var CONCURRENCY = 4;
35662
35976
  var RATE_LIMIT_COOLDOWN_MS = 180000;
@@ -35664,14 +35978,17 @@ var COOLDOWN_PREFIX = "quota:cooldown:";
35664
35978
  var PROBE_LOCK_PREFIX = "quota:probe:";
35665
35979
  var PROBE_LOCK_TTL_MS = 60000;
35666
35980
  var PROBE_LOCK_WAIT_MS = 30000;
35981
+ async function usageSecretsFor(deps, credential) {
35982
+ const refreshed = credential.hasRefreshToken && credential.expiresAt !== null && credential.expiresAt - SCHEDULER_REFRESH_LEAD_MS <= deps.now() ? await deps.refresh(credential) : null;
35983
+ return refreshed === null ? await credential.openForUsage() : { accessToken: refreshed.accessToken };
35984
+ }
35667
35985
  async function probe(deps, credential) {
35668
35986
  if (credential.authType !== "oauth")
35669
35987
  return null;
35670
35988
  const provider = deps.providers[credential.provider];
35671
35989
  if (provider?.usage === undefined)
35672
35990
  return null;
35673
- const refreshed = credential.hasRefreshToken && credential.expiresAt !== null && credential.expiresAt - SCHEDULER_REFRESH_LEAD_MS <= deps.now() ? await deps.refresh(credential) : null;
35674
- const secrets = refreshed === null ? await credential.openForUsage() : { accessToken: refreshed.accessToken };
35991
+ const secrets = await usageSecretsFor(deps, credential);
35675
35992
  const report = await provider.usage(secrets, { http: deps.http, now: deps.now }, credential.providerData);
35676
35993
  if (report === null || report.windows.length === 0)
35677
35994
  return null;
@@ -35834,6 +36151,12 @@ function quotaOps(deps) {
35834
36151
  outcomes.push(result?.outcome ?? { kind: "failed", credentialId: credential.id, code: "INTERNAL" });
35835
36152
  }
35836
36153
  return { outcomes };
36154
+ },
36155
+ resetCredits: (credentialId) => listResetCredits(deps, credentialId),
36156
+ redeemReset: (request2) => redeemResetCredit(deps, request2),
36157
+ hasResets: (provider) => {
36158
+ const flow = deps.providers[provider];
36159
+ return flow?.resetCredits !== undefined && flow.redeemReset !== undefined;
35837
36160
  }
35838
36161
  };
35839
36162
  }
@@ -38018,16 +38341,7 @@ var quotaRefresh = {
38018
38341
  const store = await ctx.store();
38019
38342
  const credentials = await listCredentials(store);
38020
38343
  const wanted = id === undefined ? credentials : credentials.filter((c) => c.id === id);
38021
- const providers = wanted.every((c) => Object.hasOwn(PROVIDER_DESCRIPTORS, c.provider)) ? OAUTH_PROVIDERS : (await connectRegistryFor(ctx.root.root)).providers;
38022
- const http = nodeHttpClient();
38023
- const ops = quotaOps({
38024
- store,
38025
- coord: memoryCoord({ now: ctx.now }),
38026
- providers,
38027
- http,
38028
- refresh: createRefresher({ store, providers, http, now: ctx.now }),
38029
- now: ctx.now
38030
- });
38344
+ const ops = await opsFor(ctx, wanted);
38031
38345
  note(ctx, writer, id === undefined ? "refreshing every account\u2026" : `refreshing ${id}\u2026`);
38032
38346
  const result = await ops.refresh(id === undefined ? { kind: "all" } : { kind: "one", credentialId: id });
38033
38347
  const labels = new Map(credentials.map((c) => [c.id, c.label]));
@@ -38053,6 +38367,59 @@ var quotaRefresh = {
38053
38367
  }
38054
38368
  }
38055
38369
  };
38370
+ async function opsFor(ctx, wanted) {
38371
+ const store = await ctx.store();
38372
+ const providers = wanted.every((c) => Object.hasOwn(PROVIDER_DESCRIPTORS, c.provider)) ? OAUTH_PROVIDERS : (await connectRegistryFor(ctx.root.root)).providers;
38373
+ const http = nodeHttpClient();
38374
+ return quotaOps({
38375
+ store,
38376
+ coord: memoryCoord({ now: ctx.now }),
38377
+ providers,
38378
+ http,
38379
+ refresh: createRefresher({ store, providers, http, now: ctx.now }),
38380
+ now: ctx.now
38381
+ });
38382
+ }
38383
+ var quotaResets = {
38384
+ usage: "quota resets <id>",
38385
+ summary: "List an account's banked quota resets (Codex, Claude)",
38386
+ async run(args, { ctx, writer }) {
38387
+ const id = requirePositional(args, 0, "credential id");
38388
+ const credentials = (await listCredentials(await ctx.store())).filter((c) => c.id === id);
38389
+ const listed = await (await opsFor(ctx, credentials)).resetCredits(id);
38390
+ emit(ctx, writer, listed, () => [
38391
+ table([{ header: "CREDIT" }, { header: "STATUS" }, { header: "TITLE" }, { header: "EXPIRES" }], listed.credits.map((c) => [c.id, c.status, c.title ?? dash, formatTime(c.expiresAt)])),
38392
+ "",
38393
+ `${listed.available} available`
38394
+ ].join(`
38395
+ `));
38396
+ }
38397
+ };
38398
+ var quotaReset = {
38399
+ usage: "quota reset <id> [--credit CREDIT_ID]",
38400
+ summary: "Spend one banked quota reset on an account (irreversible)",
38401
+ options: { credit: { type: "string" } },
38402
+ async run(args, { ctx, writer, prompt }) {
38403
+ const id = requirePositional(args, 0, "credential id");
38404
+ const creditId = stringFlag(args.values, "credit");
38405
+ const credentials = (await listCredentials(await ctx.store())).filter((c) => c.id === id);
38406
+ const label3 = credentials[0]?.label ?? id;
38407
+ const ops = await opsFor(ctx, credentials);
38408
+ const provider2 = credentials[0]?.provider;
38409
+ if (provider2 === undefined)
38410
+ throw new CliError("no such credential");
38411
+ if (!ops.hasResets(provider2))
38412
+ throw new CliError("this account's provider has no quota resets");
38413
+ if (!await prompt.confirm(`spend one banked quota reset on "${label3}" (${id})?`)) {
38414
+ throw new CliError("cancelled");
38415
+ }
38416
+ const result = await ops.redeemReset({
38417
+ credentialId: id,
38418
+ ...creditId === undefined ? {} : { creditId }
38419
+ });
38420
+ emit(ctx, writer, result, () => `${label3}: reset ${result.creditId} redeemed` + (result.windowsReset === null ? "" : `, ${result.windowsReset} window(s) reset`) + (result.quotaRefreshed ? "; quota re-read" : "; quota re-read failed, next poll will update it"));
38421
+ }
38422
+ };
38056
38423
 
38057
38424
  // apps/cli/src/commands/service.ts
38058
38425
  import { existsSync as existsSync5 } from "fs";
@@ -38143,7 +38510,7 @@ function createServiceDeps(input2) {
38143
38510
  }
38144
38511
 
38145
38512
  // apps/cli/src/version.ts
38146
- var VERSION = "0.12.11";
38513
+ var VERSION = "0.12.13";
38147
38514
 
38148
38515
  // apps/cli/src/commands/service.ts
38149
38516
  function gatewayArgv(root) {
@@ -38860,6 +39227,8 @@ var COMMANDS = {
38860
39227
  "credentials add-key": credentialsAddKey,
38861
39228
  "credentials health": credentialsHealth,
38862
39229
  "quota refresh": quotaRefresh,
39230
+ "quota resets": quotaResets,
39231
+ "quota reset": quotaReset,
38863
39232
  "models list": modelsList,
38864
39233
  "models show": modelsShow,
38865
39234
  "models put": modelsPut,