omnigateway 0.15.3 → 0.15.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.
Files changed (97) hide show
  1. package/README.md +90 -6
  2. package/bin/omni.js +218 -190
  3. package/gateway.js +390 -338
  4. package/package.json +1 -1
  5. package/public/assets/_app-kgxk7ake.js +1 -0
  6. package/public/assets/_app.accounts-3jabfvcs.js +1 -0
  7. package/public/assets/_app.console-y69399jc.js +1 -0
  8. package/public/assets/_app.database-r5kg3838.js +1 -0
  9. package/public/assets/_app.index-22awhb38.js +1 -0
  10. package/public/assets/_app.keys-7vh81n1w.js +1 -0
  11. package/public/assets/_app.logs-rssv5a6z.js +1 -0
  12. package/public/assets/_app.models-82m2f0kr.js +1 -0
  13. package/public/assets/_app.plugins.$pluginId-e4xva5tz.js +1 -0
  14. package/public/assets/_app.settings-fqzg7wnn.js +1 -0
  15. package/public/assets/_app.usage-32vje0s7.js +1 -0
  16. package/public/assets/client-d3mjj5ey.js +1 -0
  17. package/public/assets/index-0j7sghrn.js +2 -0
  18. package/public/assets/index-4dz4bgrb.js +2 -0
  19. package/public/assets/index-85cnhw3e.js +2 -0
  20. package/public/assets/index-8bewp9z1.js +6 -0
  21. package/public/assets/index-938qd7p2.js +2 -0
  22. package/public/assets/index-d09hs7ex.js +2 -0
  23. package/public/assets/index-d0t1fj1y.js +2 -0
  24. package/public/assets/index-dq2f7yk0.js +2 -0
  25. package/public/assets/index-f7t0kve8.js +2 -0
  26. package/public/assets/index-fcew0gga.js +2 -0
  27. package/public/assets/index-h3nb7n4d.css +1 -0
  28. package/public/assets/index-hk28xepa.js +2 -0
  29. package/public/assets/index-nnpqs2w6.js +2 -0
  30. package/public/assets/index-p9vbm21a.js +46 -0
  31. package/public/assets/index-sbe0ydnc.js +2 -0
  32. package/public/assets/index-t1cs42r4.js +2 -0
  33. package/public/assets/index-v31xha7b.js +2 -0
  34. package/public/assets/index-wjqdtafp.js +2 -0
  35. package/public/assets/index-xdyjb1an.js +2 -0
  36. package/public/assets/index-z7c4qz9d.js +54 -0
  37. package/public/assets/index-zkt5p0qd.js +2 -0
  38. package/public/assets/login-p97b96t9.js +1 -0
  39. package/public/index.html +5 -13
  40. package/public/shared/chunks/react-e7vf2dk6.js +2 -0
  41. package/public/shared/chunks/react-mv7wrde1.js +2 -0
  42. package/public/shared/chunks/react-ybbhws22.js +2 -0
  43. package/public/shared/chunks/react-z0w6knjn.js +2 -0
  44. package/public/shared/dashboard-sdk.js +1 -1
  45. package/public/shared/jsx-runtime.js +1 -1
  46. package/public/shared/react-dom-client.js +9 -9
  47. package/public/shared/react-dom.js +1 -1
  48. package/public/shared/react-query.js +1 -1
  49. package/public/shared/react.js +1 -1
  50. package/public/shared/styled-components.js +5 -6
  51. package/public/assets/Chip-B2iXmJJC.js +0 -37
  52. package/public/assets/CopyValue-CWSTp4v8.js +0 -27
  53. package/public/assets/Field-CUEEy19T.js +0 -60
  54. package/public/assets/Lamp-CL0i4yaa.js +0 -26
  55. package/public/assets/Meter-stpt3vQu.js +0 -14
  56. package/public/assets/Panel-CsovmtxF.js +0 -225
  57. package/public/assets/Rack-1lijWt5h.js +0 -483
  58. package/public/assets/Readout-DlT5oxGO.js +0 -31
  59. package/public/assets/RequestTable-uRTmuPwB.js +0 -93
  60. package/public/assets/Select-C0c13SKD.js +0 -141
  61. package/public/assets/SummaryDeck-DnQnRmQ8.js +0 -15
  62. package/public/assets/Table-CVDZ69Zx.js +0 -38
  63. package/public/assets/Toggle-BvVa_jla.js +0 -39
  64. package/public/assets/TokenBreakdown-B8cSaOOr.js +0 -32
  65. package/public/assets/WindowChart-CaPUJ4GJ.js +0 -11
  66. package/public/assets/_app-CSru2YTE.js +0 -1
  67. package/public/assets/_app.accounts-DmJhe6QV.js +0 -70
  68. package/public/assets/_app.console-DQlcBpSu.js +0 -24
  69. package/public/assets/_app.database-DoDu8HOG.js +0 -24
  70. package/public/assets/_app.index-BEeD4XSS.js +0 -67
  71. package/public/assets/_app.keys-MXvgkBUB.js +0 -120
  72. package/public/assets/_app.logs-CjUjeVHg.js +0 -46
  73. package/public/assets/_app.models-mNIL-1oS.js +0 -148
  74. package/public/assets/_app.plugins._pluginId-CsJXQg6X.js +0 -20
  75. package/public/assets/_app.settings-CYMwWA8D.js +0 -88
  76. package/public/assets/_app.usage-Dd33vB8x.js +0 -78
  77. package/public/assets/chevron-right-ocqzquMZ.js +0 -1
  78. package/public/assets/client-KUNw8ZtZ.js +0 -48
  79. package/public/assets/index-B9izdV6t.js +0 -14
  80. package/public/assets/index-Co2s5xMk.css +0 -1
  81. package/public/assets/limits-iRyDMg04.js +0 -1
  82. package/public/assets/login-DrbTJF6e.js +0 -45
  83. package/public/assets/plus-D_lvSfDL.js +0 -1
  84. package/public/assets/preload-helper-1xe0b53X.js +0 -1
  85. package/public/assets/reasons-Du1OBWAM.js +0 -1
  86. package/public/assets/rotate-ccw-CwTftDdz.js +0 -1
  87. package/public/assets/shared-HVgLEGgl.js +0 -77
  88. package/public/assets/trash-CmuxOGpN.js +0 -1
  89. package/public/shared/chunks/jsx-runtime-CznXPbDH.js +0 -1
  90. package/public/shared/chunks/react-DK6rpPfu.js +0 -1
  91. package/public/shared/chunks/react-dom-Wr82bmbV.js +0 -1
  92. package/public/shared/chunks/rolldown-runtime-CbXtAM7H.js +0 -1
  93. /package/public/assets/{archivo-latin-ext-standard-normal-7khWdh9v.woff2 → archivo-latin-ext-standard-normal-5717f37059660ca5.woff2} +0 -0
  94. /package/public/assets/{archivo-latin-standard-normal-DY7AcnAa.woff2 → archivo-latin-standard-normal-e3a28eade21a900c.woff2} +0 -0
  95. /package/public/assets/{archivo-vietnamese-standard-normal-rJmnGBSt.woff2 → archivo-vietnamese-standard-normal-332e6f66de84927c.woff2} +0 -0
  96. /package/public/assets/{spline-sans-mono-latin-ext-wght-normal-Dh0aNLWd.woff2 → spline-sans-mono-latin-ext-wght-normal-0ca9a3989044d1f9.woff2} +0 -0
  97. /package/public/assets/{spline-sans-mono-latin-wght-normal-DlaB5ohX.woff2 → spline-sans-mono-latin-wght-normal-46b7dcafe3e51dbe.woff2} +0 -0
package/README.md CHANGED
@@ -81,7 +81,7 @@ boundary, and the background loops.
81
81
 
82
82
  ## Requirements
83
83
 
84
- - [Bun](https://bun.sh/) 1.4 or later. Bun is the runtime, not just the
84
+ - [Bun](https://bun.sh/) 1.4.4 or later. Bun is the runtime, not just the
85
85
  installer, so a Node-only machine cannot run OmniGateway.
86
86
  - A directory that persists, for the SQLite database.
87
87
  - At least one Anthropic, OpenAI, Kimi Coding, Kilo, or xAI account to connect.
@@ -216,8 +216,12 @@ omni keys guardrail <id> --clear
216
216
  The classifier sees the request's system prompt and the last few messages a human
217
217
  wrote (`guardrailHistoryTurns`, default 3, 1..10), oldest first, and judges the
218
218
  newest in their light — so "continue" after a forbidden ask is judged as that
219
- ask. It never sees tool results, images, or assistant replies, and only a plain
220
- `ALLOW` lets the request through. A deny is refused as `CONTENT_FILTER` (400); a
219
+ ask. It also sees the text of the tool results that came back after the oldest of
220
+ those messages (capped at 16,000 characters, newest first), as data the client
221
+ received. It never sees images, files, tool-call arguments, or assistant replies,
222
+ and only a plain `ALLOW` lets the request through. Tool output can sway the
223
+ verdict either way — a fetched page can talk the classifier round or push it to
224
+ refuse legitimate work — and an agent pays one classifier call per tool turn. A deny is refused as `CONTENT_FILTER` (400); a
221
225
  classifier that times out (`guardrailTimeoutMs`, default 10s), errors, or answers
222
226
  anything else refuses as `UPSTREAM` (502), and a key with a policy while
223
227
  `guardrailModel` is unset refuses as `INTERNAL` (500): **it fails closed**.
@@ -225,7 +229,7 @@ Streaming requests receive the same refusals as in-stream errors. The refusal
225
229
  messages are fixed; the classifier's words never reach the client. Each check is
226
230
  its own request row under the key, tagged `guardrail:classifier` and charged to
227
231
  it, and verdicts are cached for an hour per key, policy, model and judged text,
228
- so an agent's tool turns on one human message are judged once. The key holder sees
232
+ so a repeated request is judged once, though each new tool turn is a new one. The key holder sees
229
233
  the policy and those rows on their client dashboard. A key without a policy is
230
234
  never judged and pays nothing. `omni doctor` warns when keys carry a policy and
231
235
  nothing can judge them.
@@ -233,10 +237,80 @@ nothing can judge them.
233
237
  **This is a guardrail, not a security boundary.** It stops ordinary misuse, not a
234
238
  client set on getting past it — by talking the classifier round, spreading a
235
239
  request over more messages than the window holds, leaving it out of the history
236
- it sends, or hiding it in tool results or images. **Rolling back** to
240
+ it sends, hiding it in images, or planting text in tool output the classifier
241
+ reads. **Rolling back** to
237
242
  a build without usage policies ignores them: every key's requests are served
238
243
  unjudged until you upgrade again.
239
244
 
245
+ A key can also be set to **route confidential requests to a local model**. A
246
+ classifier running on your own infrastructure reads what the request carries; if
247
+ anything in it is confidential, the request is served by a model you host instead
248
+ of the one the client asked for. It is active only when the global switch
249
+ `smartRouterEnabled` **and** the key's flag are both on:
250
+
251
+ ```bash
252
+ omni settings set smartRouterClassifierModel local-judge # a virtual model, every target a custom endpoint
253
+ omni settings set smartRouterLocalModel local-llm # same rule
254
+ omni settings set smartRouterEnabled true
255
+ omni keys smart-routing <id> --on # or: omni keys create --smart-routing
256
+ omni keys smart-routing <id> --off
257
+ ```
258
+
259
+ Both models must be configured virtual models whose every target is the `custom`
260
+ provider, and the gateway re-checks that at the moment of each send, so a model
261
+ edited later cannot quietly start pointing at an external provider. Anything
262
+ else is refused, never routed externally. `smartRouterPolicy` says what
263
+ "confidential" means (personal data, credentials, salaries and HR records,
264
+ customer records, non-public financials, documents marked internal, by default;
265
+ editable on the console's Settings screen, which can reset it) and
266
+ `smartRouterTimeoutMs` bounds each classifier call (default 10s, 1..60000).
267
+
268
+ Everything the request carries is judged — system and mid-conversation system
269
+ turns, user and assistant text, thinking, tool-call arguments, tool results, tool
270
+ names, descriptions and input schemas, citations, the text inside provider-native
271
+ blocks (a text document, a search result, an MCP result, a shell output) and
272
+ pass-through vendor fields — not just the newest message, because a client
273
+ resends the whole conversation. Only images, files and base64 payloads are not
274
+ judged. The text is split into segments of up to
275
+ 8,000 characters, each judged `PUBLIC` or `CONFIDENTIAL` by the local classifier,
276
+ at most four at a time. Verdicts are cached for an hour per classifier, policy
277
+ and segment, so a conversation that grows is judged only on what is new; failures
278
+ are not cached. A request with more than 64 segments still to judge goes local
279
+ without being judged.
280
+
281
+ | Outcome | Result | Row tag |
282
+ | --- | --- | --- |
283
+ | everything public | served by the model the client asked for | `smart-router:public` |
284
+ | anything confidential | served by `smartRouterLocalModel` | `smart-router:local` |
285
+ | more than 64 segments still to judge | served by `smartRouterLocalModel`, not judged | `smart-router:local`, `smart-router:oversize` |
286
+ | asked for a local-only model already | served as asked, not judged | `smart-router:already-local` |
287
+ | classifier timeout, error, or unreadable reply | refused, `UPSTREAM` (502) | `smart-router:unavailable` |
288
+ | either model unset, unresolved, or not local-only | refused, `INTERNAL` (500) | `smart-router:unconfigured` |
289
+
290
+ **It fails closed and never falls back to an external provider**: if the local
291
+ model itself fails, the client gets that failure. A confidential request the local
292
+ model cannot serve is refused with `NO_CANDIDATES` (503) rather than sent out — one
293
+ carrying provider-native content (an Anthropic `search_result` or `document`, a
294
+ server-tool result) or provider-defined tools (`web_search`, `bash`, …), which only
295
+ that provider can accept, or tools or images the local model lacks. The row still
296
+ carries `smart-router:local`. Each check is its own request
297
+ row under the key, tagged `smart-router:classifier` and charged to it. When a
298
+ key also has a usage policy, smart routing runs first, and a request that goes
299
+ local has its policy judged by the smart-router classifier, never by
300
+ `guardrailModel`. `omni doctor` has a "smart routing" row; the console's
301
+ Settings screen warns under each model picker when the model is unset (switch
302
+ on), does not resolve, or is not local-only, and the Keys board says when
303
+ flagged keys' requests are refused or unscreened. The client
304
+ dashboard shows "Confidential routing: on/off" for the key. The client-visible
305
+ signals are in [docs/client-api.md](docs/client-api.md#confidential-routing).
306
+
307
+ **This reduces leaks of ordinary confidential content; it is not a security
308
+ boundary.** It does not stop deliberate evasion (encoding, splitting a secret
309
+ across messages, prompt injection aimed at the classifier), confidential content
310
+ inside images or files, or a classifier that simply misses. **Rolling back** to a
311
+ build without it ignores the flag and sends every request to the external
312
+ provider (it fails open) until you upgrade again.
313
+
240
314
  Now use it:
241
315
 
242
316
  ```bash
@@ -463,7 +537,7 @@ Worth knowing before you deploy it:
463
537
  classifier calls instead; these remain billed as token usage. See
464
538
  [Anthropic's notice guide](https://code.claude.com/docs/en/auto-mode-classifier-billing).
465
539
  - **An OpenAI OAuth (ChatGPT) target presents itself as Codex, and answers like
466
- it.** Requests on that leg match Codex 0.163.0's TUI field by field, which
540
+ it.** Requests on that leg follow Codex 0.165.0's captured TUI shape, which
467
541
  changes model behaviour for every client routed there, Claude Code included:
468
542
  one tool call per turn (`parallel_tool_calls: false`), terser answers
469
543
  (`text.verbosity: "low"`), and a request that names no reasoning effort —
@@ -559,6 +633,10 @@ conventions, [docs/adding-a-provider.md](docs/adding-a-provider.md) for the
559
633
  provider checklist, and `docs/superpowers/specs/` for the design documents
560
634
  behind each feature.
561
635
 
636
+ The checkout pins Bun 1.4.4 for local builds, CI, and releases. See the
637
+ [Bun built-ins audit](docs/bun-builtins-audit.md) for native-tool migrations and
638
+ compatibility boundaries.
639
+
562
640
  ```bash
563
641
  git clone https://github.com/harismawan/omnigateway.git
564
642
  cd omnigateway
@@ -568,5 +646,11 @@ bun run build:dashboard # the gateway serves this build
568
646
  bun run dev # gateway on 9000, with file watching
569
647
  ```
570
648
 
649
+ For dashboard development, run `bun run dev:dashboard` in another terminal
650
+ (port 5173, API/health proxied to 9000). Bun rebuilds after source changes and
651
+ reloads the page; component state resets, with no React Fast Refresh.
652
+ `bun run --cwd apps/dashboard preview` serves an existing build on port 4173.
653
+ Both commands accept `--host`, `--port` and `--upstream` options.
654
+
571
655
  Releases are published to npm from a `v*` tag, with provenance attesting which
572
656
  commit produced them.