@axemere/gateway-google 0.1.9
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/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +64 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +54 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Axemere LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @axemere/gateway-google
|
|
2
|
+
|
|
3
|
+
Google Generative AI drop-in wrapper for the [Axemere AI Gateway](https://axemere.ai).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @axemere/gateway-google @google/generative-ai
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { genaiClient } from "@axemere/gateway-google";
|
|
15
|
+
import { AiGatewayConfig } from "@axemere/gateway";
|
|
16
|
+
|
|
17
|
+
const ai = genaiClient(new AiGatewayConfig());
|
|
18
|
+
const model = ai.getGenerativeModel({ model: "gemini-1.5-flash" });
|
|
19
|
+
const result = await model.generateContent("Explain quantum entanglement in one sentence.");
|
|
20
|
+
console.log(result.response.text());
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The returned client is a standard `GoogleGenerativeAI` instance — no other code changes needed.
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
Reads `AXEMERE_GATEWAY_URL` and `AXEMERE_GATEWAY_TOKEN` from the environment, or pass an
|
|
28
|
+
`AiGatewayConfig` instance explicitly.
|
|
29
|
+
|
|
30
|
+
See [@axemere/gateway](https://www.npmjs.com/package/@axemere/gateway) for all configuration options.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
2
|
+
import type { ModelParams, RequestOptions } from "@google/generative-ai";
|
|
3
|
+
import { AiGatewayConfig } from "@axemere/gateway";
|
|
4
|
+
export { AiGatewayConfig };
|
|
5
|
+
/**
|
|
6
|
+
* GoogleGenerativeAI subclass that automatically routes all model requests
|
|
7
|
+
* through the Axemere AI Gateway. Gateway auth headers and base URL are injected
|
|
8
|
+
* into every getGenerativeModel() call without requiring the caller to pass
|
|
9
|
+
* requestOptions manually.
|
|
10
|
+
*/
|
|
11
|
+
declare class GatewayGenerativeAI extends GoogleGenerativeAI {
|
|
12
|
+
private readonly _gatewayRequestOptions;
|
|
13
|
+
constructor(apiKey: string, gatewayRequestOptions: RequestOptions);
|
|
14
|
+
getGenerativeModel(modelParams: ModelParams, requestOptions?: RequestOptions): import("@google/generative-ai").GenerativeModel;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a GoogleGenerativeAI client pre-configured to route through the Axemere AI Gateway.
|
|
18
|
+
*
|
|
19
|
+
* The returned client is a standard GoogleGenerativeAI instance — use it exactly as you would
|
|
20
|
+
* the official @google/generative-ai package. All requests are proxied through the gateway,
|
|
21
|
+
* which applies policy, budgets, and records usage.
|
|
22
|
+
*
|
|
23
|
+
* @param config - AiGatewayConfig instance (reads env vars if omitted).
|
|
24
|
+
* @returns A GoogleGenerativeAI instance with gateway routing applied to every model request.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const ai = genaiClient(new AiGatewayConfig());
|
|
29
|
+
* const model = ai.getGenerativeModel({ model: "gemini-1.5-flash" });
|
|
30
|
+
* const result = await model.generateContent("Hello");
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function genaiClient(config?: AiGatewayConfig): GatewayGenerativeAI;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AiGatewayConfig = void 0;
|
|
4
|
+
exports.genaiClient = genaiClient;
|
|
5
|
+
const generative_ai_1 = require("@google/generative-ai");
|
|
6
|
+
const gateway_1 = require("@axemere/gateway");
|
|
7
|
+
Object.defineProperty(exports, "AiGatewayConfig", { enumerable: true, get: function () { return gateway_1.AiGatewayConfig; } });
|
|
8
|
+
/**
|
|
9
|
+
* GoogleGenerativeAI subclass that automatically routes all model requests
|
|
10
|
+
* through the Axemere AI Gateway. Gateway auth headers and base URL are injected
|
|
11
|
+
* into every getGenerativeModel() call without requiring the caller to pass
|
|
12
|
+
* requestOptions manually.
|
|
13
|
+
*/
|
|
14
|
+
class GatewayGenerativeAI extends generative_ai_1.GoogleGenerativeAI {
|
|
15
|
+
constructor(apiKey, gatewayRequestOptions) {
|
|
16
|
+
super(apiKey);
|
|
17
|
+
this._gatewayRequestOptions = gatewayRequestOptions;
|
|
18
|
+
}
|
|
19
|
+
getGenerativeModel(modelParams, requestOptions) {
|
|
20
|
+
// Merge gateway defaults under caller-supplied options so callers can
|
|
21
|
+
// still override baseUrl or add their own custom headers.
|
|
22
|
+
const merged = {
|
|
23
|
+
...this._gatewayRequestOptions,
|
|
24
|
+
...requestOptions,
|
|
25
|
+
};
|
|
26
|
+
// Merge customHeaders: gateway headers first, caller headers win on conflict.
|
|
27
|
+
// Note: x-goog-api-key cannot be set via customHeaders (SDK enforces this),
|
|
28
|
+
// so the placeholder key is forwarded as-is. The gateway recognises
|
|
29
|
+
// PLACEHOLDER_API_KEY ("axemere-proxy-managed") and does not treat it as BYOK.
|
|
30
|
+
const gwHeaders = new Headers(this._gatewayRequestOptions.customHeaders ?? {});
|
|
31
|
+
if (requestOptions?.customHeaders) {
|
|
32
|
+
const callerHeaders = new Headers(requestOptions.customHeaders);
|
|
33
|
+
callerHeaders.forEach((val, key) => gwHeaders.set(key, val));
|
|
34
|
+
}
|
|
35
|
+
merged.customHeaders = gwHeaders;
|
|
36
|
+
return super.getGenerativeModel(modelParams, merged);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a GoogleGenerativeAI client pre-configured to route through the Axemere AI Gateway.
|
|
41
|
+
*
|
|
42
|
+
* The returned client is a standard GoogleGenerativeAI instance — use it exactly as you would
|
|
43
|
+
* the official @google/generative-ai package. All requests are proxied through the gateway,
|
|
44
|
+
* which applies policy, budgets, and records usage.
|
|
45
|
+
*
|
|
46
|
+
* @param config - AiGatewayConfig instance (reads env vars if omitted).
|
|
47
|
+
* @returns A GoogleGenerativeAI instance with gateway routing applied to every model request.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const ai = genaiClient(new AiGatewayConfig());
|
|
52
|
+
* const model = ai.getGenerativeModel({ model: "gemini-1.5-flash" });
|
|
53
|
+
* const result = await model.generateContent("Hello");
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function genaiClient(config) {
|
|
57
|
+
const cfg = config ?? new gateway_1.AiGatewayConfig();
|
|
58
|
+
const headers = (0, gateway_1.aiGatewayHeaders)(cfg, { targetHost: "generativelanguage.googleapis.com" });
|
|
59
|
+
const gatewayRequestOptions = {
|
|
60
|
+
baseUrl: cfg.gateway_url,
|
|
61
|
+
customHeaders: new Headers(headers),
|
|
62
|
+
};
|
|
63
|
+
return new GatewayGenerativeAI(gateway_1.PLACEHOLDER_API_KEY, gatewayRequestOptions);
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const generative_ai_1 = require("@google/generative-ai");
|
|
4
|
+
const gateway_1 = require("@axemere/gateway");
|
|
5
|
+
const index_1 = require("./index");
|
|
6
|
+
describe("genaiClient()", () => {
|
|
7
|
+
it("returns a GoogleGenerativeAI instance", () => {
|
|
8
|
+
const cfg = new gateway_1.AiGatewayConfig({ gateway_url: "http://localhost:7080" });
|
|
9
|
+
const client = (0, index_1.genaiClient)(cfg);
|
|
10
|
+
expect(client).toBeInstanceOf(generative_ai_1.GoogleGenerativeAI);
|
|
11
|
+
});
|
|
12
|
+
it("constructs with default config when no config passed", () => {
|
|
13
|
+
delete process.env["AXEMERE_GATEWAY_URL"];
|
|
14
|
+
delete process.env["AXEMERE_GATEWAY_TOKEN"];
|
|
15
|
+
expect(() => (0, index_1.genaiClient)()).not.toThrow();
|
|
16
|
+
});
|
|
17
|
+
it("injects Authorization header from gateway_token", () => {
|
|
18
|
+
const cfg = new gateway_1.AiGatewayConfig({
|
|
19
|
+
gateway_url: "http://localhost:7080",
|
|
20
|
+
gateway_token: "tok_test",
|
|
21
|
+
});
|
|
22
|
+
const client = (0, index_1.genaiClient)(cfg);
|
|
23
|
+
// Retrieve the options injected into getGenerativeModel by calling it and
|
|
24
|
+
// inspecting the GenerativeModel's private _requestOptions.
|
|
25
|
+
const model = client.getGenerativeModel({ model: "gemini-1.5-flash" });
|
|
26
|
+
const opts = model
|
|
27
|
+
._requestOptions;
|
|
28
|
+
expect(opts.customHeaders.get("Authorization")).toBe("Bearer tok_test");
|
|
29
|
+
});
|
|
30
|
+
it("sets baseUrl to the gateway URL", () => {
|
|
31
|
+
const cfg = new gateway_1.AiGatewayConfig({ gateway_url: "http://localhost:7080" });
|
|
32
|
+
const client = (0, index_1.genaiClient)(cfg);
|
|
33
|
+
const model = client.getGenerativeModel({ model: "gemini-1.5-flash" });
|
|
34
|
+
const opts = model
|
|
35
|
+
._requestOptions;
|
|
36
|
+
expect(opts.baseUrl).toBe("http://localhost:7080");
|
|
37
|
+
});
|
|
38
|
+
it("sets X-MVGC-Target-Host to generativelanguage.googleapis.com", () => {
|
|
39
|
+
const cfg = new gateway_1.AiGatewayConfig({ gateway_url: "http://localhost:7080" });
|
|
40
|
+
const client = (0, index_1.genaiClient)(cfg);
|
|
41
|
+
const model = client.getGenerativeModel({ model: "gemini-1.5-flash" });
|
|
42
|
+
const opts = model
|
|
43
|
+
._requestOptions;
|
|
44
|
+
expect(opts.customHeaders.get("X-MVGC-Target-Host")).toBe("generativelanguage.googleapis.com");
|
|
45
|
+
});
|
|
46
|
+
it("caller requestOptions override gateway defaults", () => {
|
|
47
|
+
const cfg = new gateway_1.AiGatewayConfig({ gateway_url: "http://localhost:7080" });
|
|
48
|
+
const client = (0, index_1.genaiClient)(cfg);
|
|
49
|
+
const model = client.getGenerativeModel({ model: "gemini-1.5-flash" }, { baseUrl: "http://other-gateway:9090" });
|
|
50
|
+
const opts = model
|
|
51
|
+
._requestOptions;
|
|
52
|
+
expect(opts.baseUrl).toBe("http://other-gateway:9090");
|
|
53
|
+
});
|
|
54
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@axemere/gateway-google",
|
|
3
|
+
"version": "0.1.9",
|
|
4
|
+
"description": "Axemere AI Gateway SDK — Google Generative AI wrapper",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/Axemere-LLC/axemere-node.git",
|
|
18
|
+
"directory": "packages/gateway-google"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@google/generative-ai": ">=0.21.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@axemere/gateway": "0.1.9"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@google/generative-ai": "^0.24.0",
|
|
31
|
+
"typescript": "^5.4.0",
|
|
32
|
+
"@types/node": "^20.0.0",
|
|
33
|
+
"@types/jest": "^29.0.0",
|
|
34
|
+
"jest": "^29.0.0",
|
|
35
|
+
"ts-jest": "^29.0.0"
|
|
36
|
+
},
|
|
37
|
+
"jest": {
|
|
38
|
+
"preset": "ts-jest",
|
|
39
|
+
"testEnvironment": "node",
|
|
40
|
+
"transform": {
|
|
41
|
+
"^.+\\.tsx?$": [
|
|
42
|
+
"ts-jest",
|
|
43
|
+
{
|
|
44
|
+
"useESM": false
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc",
|
|
51
|
+
"test": "jest"
|
|
52
|
+
}
|
|
53
|
+
}
|