omnigateway 0.13.3 → 0.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -397,6 +397,11 @@ Worth knowing before you deploy it:
397
397
  - **The gateway does not know which model accepts which request shape.** An
398
398
  unsupported combination surfaces as the provider's own 400 rather than being
399
399
  caught earlier.
400
+ - **Thinking controls retain their wire intent.** Anthropic `between_tools` passes
401
+ through; other providers treat it as off and report a degradation. Unparsed
402
+ Anthropic thinking fields (including beta controls) pass through only to
403
+ Anthropic; supply any required beta header yourself. Hidden adaptive display
404
+ omits generated Responses reasoning summaries, without inventing a default.
400
405
  - Not in scope: semantic caching, billing.
401
406
 
402
407
  What is missing on purpose, what is missing for now, and what is designed but not
package/bin/omni.js CHANGED
@@ -13963,6 +13963,9 @@ function toWire(req, model, opts) {
13963
13963
  addAutoCacheBreakpoints(body, req, note);
13964
13964
  if (req.reasoning !== undefined) {
13965
13965
  switch (req.reasoning.mode) {
13966
+ case "betweenTools":
13967
+ body.thinking = { type: "between_tools" };
13968
+ break;
13966
13969
  case "adaptive":
13967
13970
  if (anthropicReasoningForm(model) === "budget") {
13968
13971
  body.thinking = { type: "disabled" };
@@ -14001,7 +14004,10 @@ function toWire(req, model, opts) {
14001
14004
  } else if (!nativeFormat && read.kind === "tooDeep") {
14002
14005
  note("anthropic:response-schema-too-deep");
14003
14006
  }
14004
- const vendorRaw = req.vendor?.anthropic ?? {};
14007
+ const { thinking: thinkingExtras, ...vendorRaw } = req.vendor?.anthropic ?? {};
14008
+ if (body.thinking !== undefined && isRecord2(thinkingExtras)) {
14009
+ body.thinking = { ...thinkingExtras, ...body.thinking };
14010
+ }
14005
14011
  const vendorConfig = vendorRaw.output_config;
14006
14012
  const encoderConfig = isRecord2(body.output_config) ? body.output_config : undefined;
14007
14013
  let unreadableFormat = false;
@@ -15178,6 +15184,10 @@ function toAntigravityWire(req, model, identity) {
15178
15184
  }
15179
15185
  if (req.reasoning !== undefined) {
15180
15186
  switch (req.reasoning.mode) {
15187
+ case "betweenTools":
15188
+ note("antigravity:reasoning-between-tools-as-off");
15189
+ generationConfig.thinkingConfig = { thinkingBudget: 0, includeThoughts: false };
15190
+ break;
15181
15191
  case "off":
15182
15192
  generationConfig.thinkingConfig = { thinkingBudget: 0, includeThoughts: false };
15183
15193
  break;
@@ -15195,7 +15205,7 @@ function toAntigravityWire(req, model, identity) {
15195
15205
  break;
15196
15206
  case "adaptive":
15197
15207
  generationConfig.thinkingConfig = {
15198
- includeThoughts: req.reasoning.display !== "omitted"
15208
+ includeThoughts: req.reasoning.display !== "omitted" && req.reasoning.display !== "updates"
15199
15209
  };
15200
15210
  if (req.reasoning.effort !== undefined)
15201
15211
  note("antigravity:reasoning-effort-dropped");
@@ -17070,6 +17080,8 @@ function toCustomChatWire(req, model) {
17070
17080
  }
17071
17081
  if (req.toolChoice !== undefined)
17072
17082
  body.tool_choice = encodeChatToolChoice(req.toolChoice);
17083
+ if (req.reasoning?.mode === "betweenTools")
17084
+ note("custom:reasoning-between-tools-as-off");
17073
17085
  const effort = customEffort(req.reasoning);
17074
17086
  if (effort !== undefined)
17075
17087
  body.reasoning_effort = effort;
@@ -17200,9 +17212,14 @@ function toCustomResponsesWire(req, model) {
17200
17212
  }
17201
17213
  if (req.toolChoice !== undefined)
17202
17214
  body.tool_choice = encodeResponsesToolChoice(req.toolChoice);
17215
+ if (req.reasoning?.mode === "betweenTools")
17216
+ note("custom:reasoning-between-tools-as-off");
17203
17217
  const effort = customEffort(req.reasoning);
17204
17218
  if (effort !== undefined)
17205
- body.reasoning = { effort, summary: "auto" };
17219
+ body.reasoning = {
17220
+ effort,
17221
+ ...req.reasoning?.mode === "adaptive" && (req.reasoning.display === "omitted" || req.reasoning.display === "updates") ? {} : { summary: "auto" }
17222
+ };
17206
17223
  else if (req.reasoning?.mode === "budget")
17207
17224
  note("custom:reasoning-budget-dropped");
17208
17225
  Object.assign(body, req.vendor?.openai ?? {});
@@ -17595,12 +17612,17 @@ function toGrokWire(req, model) {
17595
17612
  }
17596
17613
  if (req.toolChoice !== undefined)
17597
17614
  body.tool_choice = encodeToolChoice3(req.toolChoice);
17598
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
17615
+ if (req.reasoning?.mode === "betweenTools")
17616
+ note("grok:reasoning-between-tools-as-off");
17617
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
17599
17618
  if (req.reasoning.mode === "budget") {
17600
17619
  note("grok:reasoning-budget-dropped");
17601
17620
  } else {
17602
17621
  const effort = req.reasoning.effort ?? "medium";
17603
- body.reasoning = { effort, summary: "concise" };
17622
+ body.reasoning = {
17623
+ effort,
17624
+ ...req.reasoning.display === "omitted" || req.reasoning.display === "updates" ? {} : { summary: "concise" }
17625
+ };
17604
17626
  }
17605
17627
  }
17606
17628
  Object.assign(body, req.vendor?.grok ?? {});
@@ -18060,7 +18082,9 @@ function toKiloWire(req, model) {
18060
18082
  }
18061
18083
  if (req.toolChoice !== undefined)
18062
18084
  body.tool_choice = encodeToolChoice4(req.toolChoice);
18063
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
18085
+ if (req.reasoning?.mode === "betweenTools")
18086
+ note("kilo:reasoning-between-tools-as-off");
18087
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
18064
18088
  if (req.reasoning.mode === "budget") {
18065
18089
  body.reasoning = { max_tokens: req.reasoning.budgetTokens };
18066
18090
  } else {
@@ -18338,6 +18362,8 @@ function toChatWire(req, model, vendor = "kimi") {
18338
18362
  }
18339
18363
  if (req.toolChoice !== undefined)
18340
18364
  body.tool_choice = encodeToolChoice5(req.toolChoice);
18365
+ if (req.reasoning?.mode === "betweenTools")
18366
+ note("kimi:reasoning-between-tools-as-off");
18341
18367
  if (req.reasoning !== undefined)
18342
18368
  note("kimi:reasoning-dropped");
18343
18369
  Object.assign(body, req.vendor?.[vendor] ?? {});
@@ -18760,12 +18786,17 @@ function toMuseWire(req, model) {
18760
18786
  }
18761
18787
  if (req.toolChoice !== undefined)
18762
18788
  body.tool_choice = encodeToolChoice6(req.toolChoice);
18763
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
18789
+ if (req.reasoning?.mode === "betweenTools")
18790
+ note("muse:reasoning-between-tools-as-off");
18791
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
18764
18792
  if (req.reasoning.mode === "budget") {
18765
18793
  note("muse:reasoning-budget-dropped");
18766
18794
  } else {
18767
18795
  const effort = req.reasoning.effort ?? "medium";
18768
- body.reasoning = { effort, summary: "auto" };
18796
+ body.reasoning = {
18797
+ effort,
18798
+ ...req.reasoning.display === "omitted" || req.reasoning.display === "updates" ? {} : { summary: "auto" }
18799
+ };
18769
18800
  }
18770
18801
  }
18771
18802
  const key = suppliedKey(req) ?? cacheKey(req, instructions ?? "", input[0]);
@@ -19196,12 +19227,17 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
19196
19227
  }
19197
19228
  if (req.toolChoice !== undefined)
19198
19229
  body.tool_choice = encodeToolChoice7(req.toolChoice);
19199
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
19230
+ if (req.reasoning?.mode === "betweenTools")
19231
+ degradations.push("openai:reasoning-between-tools-as-off");
19232
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
19200
19233
  if (req.reasoning.mode === "budget") {
19201
19234
  degradations.push("openai:reasoning-budget-dropped");
19202
19235
  } else {
19203
19236
  const effort = req.reasoning.effort ?? "medium";
19204
- body.reasoning = { effort, summary: "auto" };
19237
+ body.reasoning = {
19238
+ effort,
19239
+ ...req.reasoning.display === "omitted" || req.reasoning.display === "updates" ? {} : { summary: "auto" }
19240
+ };
19205
19241
  }
19206
19242
  }
19207
19243
  const key = suppliedKey2(req) ?? cacheKey2(req, instructions ?? "", input[0]);
@@ -19794,7 +19830,7 @@ function requiredCapabilities(request) {
19794
19830
  return {
19795
19831
  tools: (request.tools?.length ?? 0) > 0,
19796
19832
  images,
19797
- reasoning: request.reasoning !== undefined && request.reasoning.mode !== "off"
19833
+ reasoning: request.reasoning !== undefined && request.reasoning.mode !== "off" && request.reasoning.mode !== "betweenTools"
19798
19834
  };
19799
19835
  }
19800
19836
  function cooldownMs(failures, threshold, base) {
@@ -25073,7 +25109,7 @@ function createServiceDeps(input) {
25073
25109
  }
25074
25110
 
25075
25111
  // apps/cli/src/version.ts
25076
- var VERSION = "0.13.3";
25112
+ var VERSION = "0.13.4";
25077
25113
 
25078
25114
  // apps/cli/src/commands/service.ts
25079
25115
  function gatewayArgv(root) {
package/gateway.js CHANGED
@@ -19628,6 +19628,9 @@ function toWire(req, model, opts) {
19628
19628
  addAutoCacheBreakpoints(body, req, note);
19629
19629
  if (req.reasoning !== undefined) {
19630
19630
  switch (req.reasoning.mode) {
19631
+ case "betweenTools":
19632
+ body.thinking = { type: "between_tools" };
19633
+ break;
19631
19634
  case "adaptive":
19632
19635
  if (anthropicReasoningForm(model) === "budget") {
19633
19636
  body.thinking = { type: "disabled" };
@@ -19666,7 +19669,10 @@ function toWire(req, model, opts) {
19666
19669
  } else if (!nativeFormat && read.kind === "tooDeep") {
19667
19670
  note("anthropic:response-schema-too-deep");
19668
19671
  }
19669
- const vendorRaw = req.vendor?.anthropic ?? {};
19672
+ const { thinking: thinkingExtras, ...vendorRaw } = req.vendor?.anthropic ?? {};
19673
+ if (body.thinking !== undefined && isRecord2(thinkingExtras)) {
19674
+ body.thinking = { ...thinkingExtras, ...body.thinking };
19675
+ }
19670
19676
  const vendorConfig = vendorRaw.output_config;
19671
19677
  const encoderConfig = isRecord2(body.output_config) ? body.output_config : undefined;
19672
19678
  let unreadableFormat = false;
@@ -20843,6 +20849,10 @@ function toAntigravityWire(req, model, identity) {
20843
20849
  }
20844
20850
  if (req.reasoning !== undefined) {
20845
20851
  switch (req.reasoning.mode) {
20852
+ case "betweenTools":
20853
+ note("antigravity:reasoning-between-tools-as-off");
20854
+ generationConfig.thinkingConfig = { thinkingBudget: 0, includeThoughts: false };
20855
+ break;
20846
20856
  case "off":
20847
20857
  generationConfig.thinkingConfig = { thinkingBudget: 0, includeThoughts: false };
20848
20858
  break;
@@ -20860,7 +20870,7 @@ function toAntigravityWire(req, model, identity) {
20860
20870
  break;
20861
20871
  case "adaptive":
20862
20872
  generationConfig.thinkingConfig = {
20863
- includeThoughts: req.reasoning.display !== "omitted"
20873
+ includeThoughts: req.reasoning.display !== "omitted" && req.reasoning.display !== "updates"
20864
20874
  };
20865
20875
  if (req.reasoning.effort !== undefined)
20866
20876
  note("antigravity:reasoning-effort-dropped");
@@ -22735,6 +22745,8 @@ function toCustomChatWire(req, model) {
22735
22745
  }
22736
22746
  if (req.toolChoice !== undefined)
22737
22747
  body.tool_choice = encodeChatToolChoice(req.toolChoice);
22748
+ if (req.reasoning?.mode === "betweenTools")
22749
+ note("custom:reasoning-between-tools-as-off");
22738
22750
  const effort = customEffort(req.reasoning);
22739
22751
  if (effort !== undefined)
22740
22752
  body.reasoning_effort = effort;
@@ -22865,9 +22877,14 @@ function toCustomResponsesWire(req, model) {
22865
22877
  }
22866
22878
  if (req.toolChoice !== undefined)
22867
22879
  body.tool_choice = encodeResponsesToolChoice(req.toolChoice);
22880
+ if (req.reasoning?.mode === "betweenTools")
22881
+ note("custom:reasoning-between-tools-as-off");
22868
22882
  const effort = customEffort(req.reasoning);
22869
22883
  if (effort !== undefined)
22870
- body.reasoning = { effort, summary: "auto" };
22884
+ body.reasoning = {
22885
+ effort,
22886
+ ...req.reasoning?.mode === "adaptive" && (req.reasoning.display === "omitted" || req.reasoning.display === "updates") ? {} : { summary: "auto" }
22887
+ };
22871
22888
  else if (req.reasoning?.mode === "budget")
22872
22889
  note("custom:reasoning-budget-dropped");
22873
22890
  Object.assign(body, req.vendor?.openai ?? {});
@@ -23260,12 +23277,17 @@ function toGrokWire(req, model) {
23260
23277
  }
23261
23278
  if (req.toolChoice !== undefined)
23262
23279
  body.tool_choice = encodeToolChoice3(req.toolChoice);
23263
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
23280
+ if (req.reasoning?.mode === "betweenTools")
23281
+ note("grok:reasoning-between-tools-as-off");
23282
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
23264
23283
  if (req.reasoning.mode === "budget") {
23265
23284
  note("grok:reasoning-budget-dropped");
23266
23285
  } else {
23267
23286
  const effort = req.reasoning.effort ?? "medium";
23268
- body.reasoning = { effort, summary: "concise" };
23287
+ body.reasoning = {
23288
+ effort,
23289
+ ...req.reasoning.display === "omitted" || req.reasoning.display === "updates" ? {} : { summary: "concise" }
23290
+ };
23269
23291
  }
23270
23292
  }
23271
23293
  Object.assign(body, req.vendor?.grok ?? {});
@@ -23725,7 +23747,9 @@ function toKiloWire(req, model) {
23725
23747
  }
23726
23748
  if (req.toolChoice !== undefined)
23727
23749
  body.tool_choice = encodeToolChoice4(req.toolChoice);
23728
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
23750
+ if (req.reasoning?.mode === "betweenTools")
23751
+ note("kilo:reasoning-between-tools-as-off");
23752
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
23729
23753
  if (req.reasoning.mode === "budget") {
23730
23754
  body.reasoning = { max_tokens: req.reasoning.budgetTokens };
23731
23755
  } else {
@@ -24003,6 +24027,8 @@ function toChatWire(req, model, vendor = "kimi") {
24003
24027
  }
24004
24028
  if (req.toolChoice !== undefined)
24005
24029
  body.tool_choice = encodeToolChoice5(req.toolChoice);
24030
+ if (req.reasoning?.mode === "betweenTools")
24031
+ note("kimi:reasoning-between-tools-as-off");
24006
24032
  if (req.reasoning !== undefined)
24007
24033
  note("kimi:reasoning-dropped");
24008
24034
  Object.assign(body, req.vendor?.[vendor] ?? {});
@@ -24425,12 +24451,17 @@ function toMuseWire(req, model) {
24425
24451
  }
24426
24452
  if (req.toolChoice !== undefined)
24427
24453
  body.tool_choice = encodeToolChoice6(req.toolChoice);
24428
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
24454
+ if (req.reasoning?.mode === "betweenTools")
24455
+ note("muse:reasoning-between-tools-as-off");
24456
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
24429
24457
  if (req.reasoning.mode === "budget") {
24430
24458
  note("muse:reasoning-budget-dropped");
24431
24459
  } else {
24432
24460
  const effort = req.reasoning.effort ?? "medium";
24433
- body.reasoning = { effort, summary: "auto" };
24461
+ body.reasoning = {
24462
+ effort,
24463
+ ...req.reasoning.display === "omitted" || req.reasoning.display === "updates" ? {} : { summary: "auto" }
24464
+ };
24434
24465
  }
24435
24466
  }
24436
24467
  const key = suppliedKey(req) ?? cacheKey(req, instructions ?? "", input[0]);
@@ -24861,12 +24892,17 @@ function toResponsesWire(req, model, opts = { oauth: false }) {
24861
24892
  }
24862
24893
  if (req.toolChoice !== undefined)
24863
24894
  body.tool_choice = encodeToolChoice7(req.toolChoice);
24864
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
24895
+ if (req.reasoning?.mode === "betweenTools")
24896
+ degradations.push("openai:reasoning-between-tools-as-off");
24897
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off" && req.reasoning.mode !== "betweenTools") {
24865
24898
  if (req.reasoning.mode === "budget") {
24866
24899
  degradations.push("openai:reasoning-budget-dropped");
24867
24900
  } else {
24868
24901
  const effort = req.reasoning.effort ?? "medium";
24869
- body.reasoning = { effort, summary: "auto" };
24902
+ body.reasoning = {
24903
+ effort,
24904
+ ...req.reasoning.display === "omitted" || req.reasoning.display === "updates" ? {} : { summary: "auto" }
24905
+ };
24870
24906
  }
24871
24907
  }
24872
24908
  const key = suppliedKey2(req) ?? cacheKey2(req, instructions ?? "", input[0]);
@@ -25383,7 +25419,7 @@ function requiredCapabilities(request) {
25383
25419
  return {
25384
25420
  tools: (request.tools?.length ?? 0) > 0,
25385
25421
  images,
25386
- reasoning: request.reasoning !== undefined && request.reasoning.mode !== "off"
25422
+ reasoning: request.reasoning !== undefined && request.reasoning.mode !== "off" && request.reasoning.mode !== "betweenTools"
25387
25423
  };
25388
25424
  }
25389
25425
  function cooldownMs(failures, threshold, base) {
@@ -46949,10 +46985,11 @@ var schema = object({
46949
46985
  thinking: union([
46950
46986
  object({
46951
46987
  type: literal("adaptive"),
46952
- display: _enum(["summarized", "omitted"]).optional()
46988
+ display: _enum(["summarized", "omitted", "updates"]).optional()
46953
46989
  }),
46954
46990
  object({ type: literal("enabled"), budget_tokens: number2().int().positive() }),
46955
- object({ type: literal("disabled") })
46991
+ object({ type: literal("disabled") }),
46992
+ object({ type: literal("between_tools") })
46956
46993
  ]).optional(),
46957
46994
  metadata: object({ user_id: string2().max(512).nullish() }).nullish()
46958
46995
  });
@@ -47178,6 +47215,8 @@ function toIrReasoning(thinking, effort) {
47178
47215
  return { mode: "budget", budgetTokens: thinking.budget_tokens };
47179
47216
  case "disabled":
47180
47217
  return { mode: "off" };
47218
+ case "between_tools":
47219
+ return { mode: "betweenTools" };
47181
47220
  }
47182
47221
  }
47183
47222
  function readBetas(headers) {
@@ -47237,8 +47276,13 @@ function parseAnthropicRequest(body, headers) {
47237
47276
  const conversation = typeof userId === "string" && userId.length > 0 ? userId : readConversationHeader(headers ?? undefined);
47238
47277
  if (conversation !== undefined)
47239
47278
  request.conversationId = conversation;
47240
- const extras = extraFields(body, KNOWN);
47241
- if (extras !== undefined)
47279
+ const rawThinking = body.thinking;
47280
+ const thinkingExtras = parsed.thinking !== undefined && typeof rawThinking === "object" && rawThinking !== null ? extraFields(rawThinking, ["type", "display", "budget_tokens"]) : undefined;
47281
+ const extras = {
47282
+ ...extraFields(body, KNOWN),
47283
+ ...thinkingExtras === undefined ? {} : { thinking: thinkingExtras }
47284
+ };
47285
+ if (Object.keys(extras).length > 0)
47242
47286
  request.vendor = { anthropic: extras };
47243
47287
  if (named.betas.length > 0)
47244
47288
  request.betas = named.betas;
@@ -49035,7 +49079,7 @@ function createRing(limits = DEFAULT_RING_LIMITS) {
49035
49079
  }
49036
49080
 
49037
49081
  // apps/gateway/src/version.ts
49038
- var VERSION = "0.13.3";
49082
+ var VERSION = "0.13.4";
49039
49083
 
49040
49084
  // apps/gateway/src/app.ts
49041
49085
  var ADMIN_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnigateway",
3
- "version": "0.13.3",
3
+ "version": "0.13.4",
4
4
  "description": "Self-hosted AI gateway with Anthropic- and OpenAI-compatible APIs, an admin console, and a CLI",
5
5
  "license": "MIT",
6
6
  "author": "Harismawan <mail@harismawan.com>",