{"_id":"@aidex/gateway","_rev":"2-b603d292503bd7f2ca9caa8d84696cc0","name":"@aidex/gateway","dist-tags":{"latest":"1.2.0"},"versions":{"1.1.0":{"name":"@aidex/gateway","version":"1.1.0","keywords":["ai","gateway","routing","selection","provider-agnostic"],"author":{"name":"Sudheer Babu","email":"isudheerbabu.dev@gmail.com"},"license":"MIT","_id":"@aidex/gateway@1.1.0","maintainers":[{"name":"sudheerbabu","email":"isudheerbabu.dev@gmail.com"}],"homepage":"https://github.com/getaidex/aidex/tree/main/packages/gateway#readme","bugs":{"url":"https://github.com/getaidex/aidex/issues"},"dist":{"shasum":"5ec28bda0ac21fc2ebd6a8382acb12e7c0e557ac","tarball":"https://registry.npmjs.org/@aidex/gateway/-/gateway-1.1.0.tgz","fileCount":26,"integrity":"sha512-ookk5RitSsL3ZdP/paQ7v1Zgn1vOwkqot7T+uwUBFmpVW2HkodkzMTVecqbZCCSaJ4iM+i6scLIG94BikGQWYg==","signatures":[{"sig":"MEYCIQCskfyALpCEC3L371RQAteSrABHoW5/6Ell1gBGE+xF2QIhANpdnEz07z/etCsqGb8sXTJWLWrMV22noJaXMKZDNiHP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":153686},"main":"./dist/index.cjs","type":"module","_from":"file:aidex-gateway-1.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.19.0","pnpm":">=9"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"build":"tsc -b && tsup","typecheck":"tsc -b --noEmit"},"_npmUser":{"name":"sudheerbabu","email":"isudheerbabu.dev@gmail.com"},"_resolved":"/tmp/c890a1f185510fceeebeb1d550082d9a/aidex-gateway-1.1.0.tgz","_integrity":"sha512-ookk5RitSsL3ZdP/paQ7v1Zgn1vOwkqot7T+uwUBFmpVW2HkodkzMTVecqbZCCSaJ4iM+i6scLIG94BikGQWYg==","repository":{"url":"git+https://github.com/getaidex/aidex.git","type":"git","directory":"packages/gateway"},"_npmVersion":"10.9.8","description":"Aidex Gateway — cross-provider selection/routing, retry/fallback execution, and optional @aidex/guardrails wiring, built on @aidex/catalog's ModelCatalog and @aidex/providers' ProviderError hierarchy. No connection resolution — callers supply how a candid","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","dependencies":{"@aidex/core":"1.1.0","@aidex/catalog":"1.1.0","@aidex/providers":"1.1.0","@aidex/guardrails":"1.1.0","@aidex/observability":"1.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gateway_1.1.0_1787417535836_0.23408590717395716","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@aidex/gateway","version":"1.2.0","description":"Aidex Gateway — cross-provider selection/routing, retry/fallback execution, and optional @aidex/guardrails wiring, built on @aidex/catalog's ModelCatalog and @aidex/providers' ProviderError hierarchy. No connection resolution — callers supply how a candid","keywords":["ai","gateway","routing","selection","provider-agnostic"],"license":"MIT","author":"Sudheer Babu <isudheerbabu.dev@gmail.com>","homepage":"https://github.com/getaidex/aidex/tree/main/packages/gateway#readme","repository":{"type":"git","url":"git+https://github.com/getaidex/aidex.git","directory":"packages/gateway"},"bugs":{"url":"https://github.com/getaidex/aidex/issues"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"sideEffects":false,"publishConfig":{"access":"public"},"dependencies":{"@aidex/core":"1.2.0","@aidex/catalog":"1.2.0","@aidex/providers":"1.2.0","@aidex/observability":"1.2.0","@aidex/guardrails":"1.2.0"},"engines":{"node":">=20.19.0","pnpm":">=9"},"scripts":{"build":"tsc -b && tsup","typecheck":"tsc -b --noEmit"},"_nodeVersion":"24.13.0","_id":"@aidex/gateway@1.2.0","dist":{"integrity":"sha512-9Kx38xz3PFoEyFXqIMfI+rQ1+/yNCiGiDLakvxevkGxM6YxlmSs5uJfPWk1aqNix5siJzhjsGKohyf9ATsNcRw==","shasum":"5e6a001d4ab29b83cbcf1a4d5dbc2e2f6df24ca2","tarball":"https://registry.npmjs.org/@aidex/gateway/-/gateway-1.2.0.tgz","fileCount":26,"unpackedSize":153786,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDRpycmzS0T43iXA5WQUfjQY9cw9PHbbCzLTJSKPUltqAiAJa5IkSj8mDFe5+BtKL+5wNa9G85EpsIB434fb2VfKrw=="}]},"_npmUser":{"name":"sudheerbabu","email":"isudheerbabu.dev@gmail.com"},"directories":{},"maintainers":[{"name":"sudheerbabu","email":"isudheerbabu.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gateway_1.2.0_1787491722361_0.46223609940056987"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-22T16:52:15.687Z","modified":"2026-08-23T13:28:42.660Z","1.1.0":"2026-08-22T16:52:15.966Z","1.2.0":"2026-08-23T13:28:42.490Z"},"bugs":{"url":"https://github.com/getaidex/aidex/issues"},"author":"Sudheer Babu <isudheerbabu.dev@gmail.com>","license":"MIT","homepage":"https://github.com/getaidex/aidex/tree/main/packages/gateway#readme","keywords":["ai","gateway","routing","selection","provider-agnostic"],"repository":{"type":"git","url":"git+https://github.com/getaidex/aidex.git","directory":"packages/gateway"},"description":"Aidex Gateway — cross-provider selection/routing, retry/fallback execution, and optional @aidex/guardrails wiring, built on @aidex/catalog's ModelCatalog and @aidex/providers' ProviderError hierarchy. No connection resolution — callers supply how a candid","maintainers":[{"name":"sudheerbabu","email":"isudheerbabu.dev@gmail.com"}],"readme":"# @aidex/gateway\n\n## Installation\n\n```sh\npnpm add @aidex/gateway @aidex/catalog @aidex/providers @aidex/guardrails\n```\n\n```sh\nnpm install @aidex/gateway @aidex/catalog @aidex/providers @aidex/guardrails\n```\n\nAidex Gateway 1.1's cross-provider selection/routing, retry/fallback\nexecution, and optional `@aidex/guardrails` wiring, per the approved\narchitecture:\n\n```\nProvider capabilities -> Model Catalog -> selection/routing -> Guardrails -> Gateway/execution\n```\n\nThis package implements the routing/selection stage (given a request and\n`@aidex/catalog`'s `ModelCatalog`, which candidates satisfy it, ranked),\nthe execution stage (dispatching a request against those candidates with\nretry/fallback), and the guardrail-wiring stage (running\n`@aidex/guardrails`' `composeGuardrails()` once before dispatch and once\nafter a successful response). Per Aidex's kernel philosophy\n([ADR-001](../../docs/decisions/ADR-001-kernel-philosophy.md)), none of\nthis lives in `@aidex/core` — cross-provider routing/retry/fallback was\nexplicitly kept out of the frozen kernel.\n\n## Usage\n\n```ts\nimport { GatewayExecutor, DefaultRoutingPolicy, DefaultRetryPolicy, DefaultFallbackPolicy } from '@aidex/gateway';\nimport { ModelCatalog } from '@aidex/catalog';\nimport { GeminiProvider, ClaudeProvider } from '@aidex/providers';\nimport { SizeLimitGuardrail } from '@aidex/guardrails';\n\nconst catalog = new ModelCatalog();\ncatalog.register({ providerType: 'gemini', modelId: 'gemini-2.5-flash', modalities: { text: true, image: true } /* ... */ });\ncatalog.register({ providerType: 'claude', modelId: 'claude-sonnet-4', modalities: { text: true } /* ... */ });\n\nconst routing = new DefaultRoutingPolicy();\nconst candidates = routing.selectCandidates({ capabilities: { text: true } }, catalog);\n\nconst executor = new GatewayExecutor({\n  retryPolicy: new DefaultRetryPolicy(),\n  fallbackPolicy: new DefaultFallbackPolicy(),\n  // Deliberately caller-supplied — see \"Provider selection\" below.\n  resolveProvider: (candidate) =>\n    candidate.providerType === 'gemini'\n      ? new GeminiProvider({ apiKey: process.env.GEMINI_KEY })\n      : new ClaudeProvider({ apiKey: process.env.CLAUDE_KEY }),\n  inputGuardrails: [new SizeLimitGuardrail({ maxTotalBytes: 5_000_000 })],\n});\n\nconst response = await executor.execute({ candidates, prompt: { content: 'Hello' } });\n// or, with guardrails enforced:\nconst { response: guarded, warnings } = await executor.executeWithGuardrails({ candidates, prompt: { content: 'Hello' } });\n```\n\n## Routing\n\n`DefaultRoutingPolicy.selectCandidates(request, catalog, options?)` ranks\n`ModelCatalog` entries by declared capability match\n(`RoutingCapabilityRequirements`, a type-level subset of\n`ModelCatalogFilter`), optional `allowedProviderTypes`, an optional\nexplicit `priority` map (`\"providerType::modelId\"` → lower-is-preferred\nrank; unlisted candidates rank after every listed one), and\n`acceptableStatuses` (defaults to `['active', 'preview']`). Output is\npurely an ordered list of `RoutingCandidate` (`{ providerType, modelId }`)\n— catalog identity only, never a connection, never a live `Provider`,\nnever anything that could carry credentials. No execution, no retry, no\nconnection resolution happens in this stage.\n\n## Retry / Fallback\n\nKept conceptually distinct even though `GatewayExecutor` runs them as one\nloop:\n\n- **Retry** — same candidate, same request. `DefaultRetryPolicy`\n  (`{ maxAttempts = 3, baseDelayMs = 200, maxDelayMs = 5_000 }`) is\n  exponential backoff with full jitter (AWS's algorithm — a uniform random\n  delay between 0 and the capped exponential value), gated entirely by\n  `ProviderError.retryable`, never by an error's subtype directly.\n- **Fallback** — advances to the next ranked candidate, only after retry\n  is exhausted or an error is fallback-eligible. `DefaultFallbackPolicy`\n  simply takes the next candidate in `RoutingPolicy`'s existing rank order\n  — no re-ranking, no re-filtering (implement `FallbackPolicy` yourself for\n  error-aware fallback, e.g. skipping a candidate on the same vendor that\n  just failed).\n- **Never retried or fallen back on**: an auth failure (says nothing about\n  another candidate's credentials) or an invalid-request error (will be\n  invalid against every candidate) — both throw `GatewayExhaustedError`\n  immediately. Cancellation (`AbortSignal`) stops the loop outright, no\n  retry, no fallback.\n\n## Guardrails\n\n`GatewayExecutor.executeWithGuardrails()` wraps `execute()` with\n`inputGuardrails`/`outputGuardrails` — input guardrails run once, before\nrouting/dispatch even starts; output guardrails run once, after the\nprovider has already succeeded; **never** per retry/fallback attempt.\n`execute()` itself is completely unaffected by guardrail configuration —\na caller with no guardrails configured, or that calls `execute()`\ndirectly, sees zero behavior change. A deny throws\n`GuardrailDeniedError` (never a `ProviderError` — the retry/fallback loop\nnever sees or acts on a guardrail decision) and, when `observability` is\nconfigured, emits a `'guardrail'` event first (`executionId`/`stage`/\n`code` only — never a guardrail's own free-form `reason`). See\n`@aidex/guardrails`' README for the built-in guardrails themselves; this\npackage only ever calls `composeGuardrails()`, never reimplements\nguardrail logic.\n\n## Provider selection\n\n`GatewayExecutorConfig.resolveProvider(candidate): Provider` is always\ncaller-supplied. `@aidex/gateway` deliberately does not store or resolve\nconnections/credentials (that's `@aidex/connections`) or decide *how* a\n`RoutingCandidate` becomes a live `Provider` — a `RoutingCandidate` carries\nonly `providerType`/`modelId` (catalog identity), since\n`@aidex/connections`' `Connection` has no `modelId` to correlate against.\nAn application typically closes over its own `ConnectionManager` inside\n`resolveProvider`.\n\n## Observability correlation\n\nWhen `observability` (an `@aidex/observability` `ObservabilityBus`) is\nconfigured, every execution reports one routing-decision event (candidates\nconsidered + whichever was selected, once execution concludes, via\n`trackRoutingDecision`) and one attempt event per actual provider dispatch\n(via `trackAttempt` — `outcome` discriminates `'success'`/`'retry'`/\n`'fallback'`/`'exhausted'`, so a retry/fallback/attempt sequence is one\ntyped event category, not three, all correlated by `executionId`). A\nguardrail deny separately emits a `'guardrail'` event (see \"Guardrails\"\nabove). Omitting `observability` behaves exactly as before these events\nexisted — no calls, no behavior change. `@aidex/admin` consumes these same\nevents to populate `ExecutionRecord.routing`/`.guardrailDenial` for the AI\nControl Center — see that package's README, \"Gateway routing/attempt\nobservability.\"\n\n## Tool calling\n\n`@aidex/gateway` does **not** resolve tool calls against a registry or\norchestrate a tool-calling round trip — that foundation\n(`ToolCallingProvider`, `generateWithTools()`,\n`toToolDeclarations()`/`resolveToolCalls()`) lives entirely in\n`@aidex/providers`, independent of `GatewayExecutor`. See that package's\nREADME, \"Tool calling,\" for the full caller-driven round trip.\n\n## SDK integration\n\n`@aidex/sdk`'s `AIBuilder.gateway(config)` / `AI.gateway()` expose a\n`GatewayExecutor` built the same way as above, unwrapped — no SDK-side\nglue, since `GatewayExecutor` already takes everything it needs\n(candidates, prompt, options) directly at call time. `AI.tools()` exposes\nthe SDK's `ToolRegistry` the same way; combining `ai.gateway()`'s\n`executeWithGuardrails()`/`execute()` with `ai.tools()` and\n`@aidex/providers`' tool-calling bridge is an application-level choice —\nneither `@aidex/gateway` nor `@aidex/sdk` wires the two together\nautomatically.\n\n```ts\nimport { AIBuilder } from '@aidex/sdk';\n\nconst ai = new AIBuilder()\n  .provider(defaultProvider)\n  .gateway({ retryPolicy, fallbackPolicy, resolveProvider, inputGuardrails })\n  .build();\n\nconst response = await ai.gateway().execute({ candidates, prompt });\n```\n\n## Not in this package\n\n- Health-aware routing — `HealthCheckableProvider`/`checkHealth()`\n  (`@aidex/providers`) is not consulted by `DefaultRoutingPolicy`;\n  `DefaultRoutingPolicy` is unmodified by that capability's existence.\n- AI Control / budget-policy integration — no `@aidex/ai-control` wiring,\n  no `BudgetPolicy` enforcement.\n- Live provider health checks influencing candidate selection.\n- Guardrail logic itself — every guardrail decision and its composition is\n  `@aidex/guardrails`' own `composeGuardrails()`, only ever called.\n","readmeFilename":""}