npm-ai-hooks 1.0.2 → 2.0.0
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 +1 -1
- package/Readme.md +379 -137
- package/dist/cjs/index.js +14 -0
- package/dist/cjs/providers/base/BaseProvider.js +121 -0
- package/dist/cjs/providers/base/ProviderConfig.js +118 -0
- package/dist/cjs/providers/base/ProviderConfigs.js +185 -0
- package/dist/cjs/providers/base/ProviderRegistry.js +47 -0
- package/dist/cjs/providers/base/SpecializedProviders.js +58 -0
- package/dist/cjs/providers/index.js +82 -0
- package/dist/cjs/providers/init.js +90 -0
- package/dist/{wrap.js → cjs/wrap.js} +43 -12
- package/dist/esm/errors.js +17 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/providers/base/BaseProvider.js +114 -0
- package/dist/esm/providers/base/ProviderConfig.js +114 -0
- package/dist/esm/providers/base/ProviderConfigs.js +182 -0
- package/dist/esm/providers/base/ProviderRegistry.js +43 -0
- package/dist/esm/providers/base/SpecializedProviders.js +52 -0
- package/dist/esm/providers/index.js +75 -0
- package/dist/esm/providers/init.js +81 -0
- package/dist/esm/types/claude.js +4 -0
- package/dist/esm/types/core/providers.js +1 -0
- package/dist/esm/types/deepseek.js +4 -0
- package/dist/esm/types/gemini.js +4 -0
- package/dist/esm/types/groq.js +1 -0
- package/dist/esm/types/index.js +20 -0
- package/dist/esm/types/mistral.js +4 -0
- package/dist/esm/types/openai.js +4 -0
- package/dist/esm/types/openrouter.js +1 -0
- package/dist/esm/types/perplexity.js +4 -0
- package/dist/esm/types/xai.js +4 -0
- package/dist/esm/wrap.js +113 -0
- package/dist/index.d.ts +1 -0
- package/dist/providers/base/BaseProvider.d.ts +33 -0
- package/dist/providers/base/ProviderConfig.d.ts +28 -0
- package/dist/providers/base/ProviderConfigs.d.ts +31 -0
- package/dist/providers/base/ProviderRegistry.d.ts +12 -0
- package/dist/providers/base/SpecializedProviders.d.ts +68 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/init.d.ts +58 -0
- package/package.json +50 -12
- package/dist/index.js +0 -6
- package/dist/providers/claude.d.ts +0 -2
- package/dist/providers/claude.js +0 -60
- package/dist/providers/deepkseek.d.ts +0 -2
- package/dist/providers/deepkseek.js +0 -57
- package/dist/providers/gemini.d.ts +0 -2
- package/dist/providers/gemini.js +0 -58
- package/dist/providers/groq.d.ts +0 -2
- package/dist/providers/groq.js +0 -57
- package/dist/providers/index.js +0 -75
- package/dist/providers/mistral.d.ts +0 -2
- package/dist/providers/mistral.js +0 -57
- package/dist/providers/openai.d.ts +0 -2
- package/dist/providers/openai.js +0 -57
- package/dist/providers/openrouter.d.ts +0 -1
- package/dist/providers/openrouter.js +0 -55
- package/dist/providers/perplexity.d.ts +0 -2
- package/dist/providers/perplexity.js +0 -57
- package/dist/providers/xai.d.ts +0 -2
- package/dist/providers/xai.js +0 -57
- /package/dist/{errors.js → cjs/errors.js} +0 -0
- /package/dist/{types → cjs/types}/claude.js +0 -0
- /package/dist/{types → cjs/types}/core/providers.js +0 -0
- /package/dist/{types → cjs/types}/deepseek.js +0 -0
- /package/dist/{types → cjs/types}/gemini.js +0 -0
- /package/dist/{types → cjs/types}/groq.js +0 -0
- /package/dist/{types → cjs/types}/index.js +0 -0
- /package/dist/{types → cjs/types}/mistral.js +0 -0
- /package/dist/{types → cjs/types}/openai.js +0 -0
- /package/dist/{types → cjs/types}/openrouter.js +0 -0
- /package/dist/{types → cjs/types}/perplexity.js +0 -0
- /package/dist/{types → cjs/types}/xai.js +0 -0
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npm-ai-hooks",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Universal AI Hook Layer for Node.js – one wrapper for all AI providers. Inject LLM-like behavior into any JavaScript or TypeScript function with a single line, without writing prompts, handling SDKs, or locking into any provider.",
|
|
5
|
-
"main": "dist/index.js",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Universal AI Hook Layer for Node.js and React – one wrapper for all AI providers. Inject LLM-like behavior into any JavaScript or TypeScript function with a single line, without writing prompts, handling SDKs, or locking into any provider.",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/esm/index.js",
|
|
12
|
+
"require": "./dist/cjs/index.js"
|
|
12
13
|
}
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
@@ -19,12 +20,27 @@
|
|
|
19
20
|
"scripts": {
|
|
20
21
|
"dev": "ts-node src/index.ts",
|
|
21
22
|
"clean": "rimraf dist",
|
|
22
|
-
"build": "npm run clean &&
|
|
23
|
+
"build": "npm run clean && npm run build:esm && npm run build:cjs",
|
|
24
|
+
"build:esm": "tsc --project tsconfig.esm.json",
|
|
25
|
+
"build:cjs": "tsc --project tsconfig.cjs.json",
|
|
23
26
|
"test": "jest --verbose",
|
|
27
|
+
"test:watch": "jest --watch",
|
|
28
|
+
"test:coverage": "jest --coverage",
|
|
29
|
+
"test:ci": "jest --ci --coverage --watchAll=false",
|
|
30
|
+
"test:providers": "jest tests/providers.test.ts --verbose",
|
|
31
|
+
"test:tasks": "jest tests/tasks.test.ts --verbose",
|
|
32
|
+
"test:errors": "jest tests/error-handling.test.ts --verbose",
|
|
33
|
+
"test:integration": "jest tests/integration.test.ts --verbose",
|
|
34
|
+
"test:performance": "jest tests/performance.test.ts --verbose",
|
|
35
|
+
"test:env": "jest --testNamePattern=\"Real API|Environment-based\" --verbose",
|
|
36
|
+
"test:mock": "jest --testNamePattern=\"Provider Detection|Task Tests\" --verbose",
|
|
24
37
|
"lint": "eslint . --ext .ts",
|
|
25
38
|
"format": "prettier --write .",
|
|
26
39
|
"prepare": "npm run build",
|
|
27
|
-
"demo": "npx ts-node examples/demo.ts"
|
|
40
|
+
"demo": "npx ts-node examples/demo.ts",
|
|
41
|
+
"setup:dev": "bash scripts/setup-dev.sh",
|
|
42
|
+
"setup:dev:win": "scripts\\setup-dev.bat",
|
|
43
|
+
"setup:dev:ps": "powershell -ExecutionPolicy Bypass -File scripts\\setup-dev.ps1"
|
|
28
44
|
},
|
|
29
45
|
"keywords": [
|
|
30
46
|
"ai",
|
|
@@ -39,19 +55,19 @@
|
|
|
39
55
|
"groq",
|
|
40
56
|
"mistral"
|
|
41
57
|
],
|
|
42
|
-
"author": "AteebNoOne <
|
|
58
|
+
"author": "AteebNoOne <ateebnoone@gmail.com>",
|
|
43
59
|
"repository": {
|
|
44
60
|
"type": "git",
|
|
45
|
-
"url": "https://github.com/
|
|
61
|
+
"url": "https://github.com/iTeebot/npm-ai-hooks.git"
|
|
46
62
|
},
|
|
47
63
|
"license": "MIT",
|
|
48
64
|
"dependencies": {
|
|
49
|
-
"axios": "^1.12.2"
|
|
50
|
-
"dotenv": "^17.2.3"
|
|
65
|
+
"axios": "^1.12.2"
|
|
51
66
|
},
|
|
52
67
|
"devDependencies": {
|
|
53
68
|
"@types/jest": "^30.0.0",
|
|
54
69
|
"@types/node": "^24.7.0",
|
|
70
|
+
"dotenv": "^17.2.3",
|
|
55
71
|
"eslint": "^9.37.0",
|
|
56
72
|
"jest": "^30.2.0",
|
|
57
73
|
"prettier": "^3.6.2",
|
|
@@ -60,6 +76,28 @@
|
|
|
60
76
|
"ts-node": "^10.9.2",
|
|
61
77
|
"typescript": "^5.9.3"
|
|
62
78
|
},
|
|
79
|
+
"keywords": [
|
|
80
|
+
"ai",
|
|
81
|
+
"llm",
|
|
82
|
+
"openai",
|
|
83
|
+
"claude",
|
|
84
|
+
"gemini",
|
|
85
|
+
"groq",
|
|
86
|
+
"openrouter",
|
|
87
|
+
"deepseek",
|
|
88
|
+
"mistral",
|
|
89
|
+
"xai",
|
|
90
|
+
"perplexity",
|
|
91
|
+
"react",
|
|
92
|
+
"vite",
|
|
93
|
+
"express",
|
|
94
|
+
"nodejs",
|
|
95
|
+
"typescript",
|
|
96
|
+
"hooks",
|
|
97
|
+
"wrapper",
|
|
98
|
+
"universal",
|
|
99
|
+
"cross-platform"
|
|
100
|
+
],
|
|
63
101
|
"engines": {
|
|
64
102
|
"node": ">=18"
|
|
65
103
|
},
|
package/dist/index.js
DELETED
package/dist/providers/claude.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callClaude = callClaude;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://api.anthropic.com/v1";
|
|
10
|
-
const ANTHROPIC_VERSION = "2023-06-01";
|
|
11
|
-
async function callClaude(prompt, model) {
|
|
12
|
-
const apiKey = process.env.AI_HOOK_CLAUDE_KEY;
|
|
13
|
-
if (!apiKey) {
|
|
14
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing Claude API key.", "claude", "Set AI_HOOK_CLAUDE_KEY in your environment variables.");
|
|
15
|
-
}
|
|
16
|
-
try {
|
|
17
|
-
const response = await axios_1.default.post(`${BASE_URL}/messages`, {
|
|
18
|
-
model,
|
|
19
|
-
max_tokens: 4096,
|
|
20
|
-
messages: [
|
|
21
|
-
{
|
|
22
|
-
role: "user",
|
|
23
|
-
content: prompt
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}, {
|
|
27
|
-
headers: {
|
|
28
|
-
"x-api-key": apiKey,
|
|
29
|
-
"anthropic-version": ANTHROPIC_VERSION,
|
|
30
|
-
"Content-Type": "application/json"
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
const output = response.data?.content?.[0]?.text;
|
|
34
|
-
if (!output) {
|
|
35
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "Claude returned empty response", "claude", "Check your model and API key");
|
|
36
|
-
}
|
|
37
|
-
return output;
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
if (err.response) {
|
|
41
|
-
const status = err.response.status;
|
|
42
|
-
const text = err.response.data?.error
|
|
43
|
-
? JSON.stringify(err.response.data.error)
|
|
44
|
-
: err.response.statusText || "Unknown error";
|
|
45
|
-
if (status === 400)
|
|
46
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `Claude rejected the request: ${text}`, "claude", "Check your prompt and model");
|
|
47
|
-
if (status === 401)
|
|
48
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid Claude API key: ${text}`, "claude", "Verify your AI_HOOK_CLAUDE_KEY environment variable");
|
|
49
|
-
if (status === 429)
|
|
50
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to Claude: ${text}`, "claude", "Throttle requests or upgrade your plan");
|
|
51
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `Claude API error: ${text}`, "claude");
|
|
52
|
-
}
|
|
53
|
-
else if (err.request) {
|
|
54
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting Claude", "claude", "Check your internet connection");
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "claude");
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callDeepSeek = callDeepSeek;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://api.deepseek.com/v1";
|
|
10
|
-
async function callDeepSeek(prompt, model) {
|
|
11
|
-
const apiKey = process.env.AI_HOOK_DEEPSEEK_KEY;
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing DeepSeek API key.", "deepseek", "Set AI_HOOK_DEEPSEEK_KEY in your environment variables.");
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios_1.default.post(`${BASE_URL}/chat/completions`, {
|
|
17
|
-
model,
|
|
18
|
-
messages: [
|
|
19
|
-
{
|
|
20
|
-
role: "user",
|
|
21
|
-
content: prompt
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}, {
|
|
25
|
-
headers: {
|
|
26
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
27
|
-
"Content-Type": "application/json"
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const output = response.data?.choices?.[0]?.message?.content;
|
|
31
|
-
if (!output) {
|
|
32
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "DeepSeek returned empty response", "deepseek", "Check your model and API key");
|
|
33
|
-
}
|
|
34
|
-
return output;
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
if (err.response) {
|
|
38
|
-
const status = err.response.status;
|
|
39
|
-
const text = err.response.data?.error
|
|
40
|
-
? JSON.stringify(err.response.data.error)
|
|
41
|
-
: err.response.statusText || "Unknown error";
|
|
42
|
-
if (status === 400)
|
|
43
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `DeepSeek rejected the request: ${text}`, "deepseek", "Check your prompt and model");
|
|
44
|
-
if (status === 401)
|
|
45
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid DeepSeek API key: ${text}`, "deepseek", "Verify your AI_HOOK_DEEPSEEK_KEY environment variable");
|
|
46
|
-
if (status === 429)
|
|
47
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to DeepSeek: ${text}`, "deepseek", "Throttle requests or upgrade your plan");
|
|
48
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `DeepSeek API error: ${text}`, "deepseek");
|
|
49
|
-
}
|
|
50
|
-
else if (err.request) {
|
|
51
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting DeepSeek", "deepseek", "Check your internet connection");
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "deepseek");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
package/dist/providers/gemini.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callGemini = callGemini;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
10
|
-
async function callGemini(prompt, model) {
|
|
11
|
-
const apiKey = process.env.AI_HOOK_GEMINI_KEY;
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing Gemini API key.", "gemini", "Set AI_HOOK_GEMINI_KEY in your environment variables.");
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios_1.default.post(`${BASE_URL}/models/${model}:generateContent?key=${apiKey}`, {
|
|
17
|
-
contents: [
|
|
18
|
-
{
|
|
19
|
-
parts: [
|
|
20
|
-
{
|
|
21
|
-
text: prompt
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}, {
|
|
27
|
-
headers: {
|
|
28
|
-
"Content-Type": "application/json"
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
const output = response.data?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
32
|
-
if (!output) {
|
|
33
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "Gemini returned empty response", "gemini", "Check your model and API key");
|
|
34
|
-
}
|
|
35
|
-
return output;
|
|
36
|
-
}
|
|
37
|
-
catch (err) {
|
|
38
|
-
if (err.response) {
|
|
39
|
-
const status = err.response.status;
|
|
40
|
-
const text = err.response.data?.error
|
|
41
|
-
? JSON.stringify(err.response.data.error)
|
|
42
|
-
: err.response.statusText || "Unknown error";
|
|
43
|
-
if (status === 400)
|
|
44
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `Gemini rejected the request: ${text}`, "gemini", "Check your prompt and model");
|
|
45
|
-
if (status === 401)
|
|
46
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid Gemini API key: ${text}`, "gemini", "Verify your AI_HOOK_GEMINI_KEY environment variable");
|
|
47
|
-
if (status === 429)
|
|
48
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to Gemini: ${text}`, "gemini", "Throttle requests or upgrade your plan");
|
|
49
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `Gemini API error: ${text}`, "gemini");
|
|
50
|
-
}
|
|
51
|
-
else if (err.request) {
|
|
52
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting Gemini", "gemini", "Check your internet connection");
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "gemini");
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
package/dist/providers/groq.d.ts
DELETED
package/dist/providers/groq.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callGroq = callGroq;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://api.groq.com/openai/v1";
|
|
10
|
-
async function callGroq(prompt, model) {
|
|
11
|
-
const apiKey = process.env.AI_HOOK_GROQ_KEY;
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing Groq API key.", "groq", "Set AI_HOOK_GROQ_KEY in your environment variables.");
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios_1.default.post(`${BASE_URL}/chat/completions`, {
|
|
17
|
-
model,
|
|
18
|
-
messages: [
|
|
19
|
-
{
|
|
20
|
-
role: "user",
|
|
21
|
-
content: prompt
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}, {
|
|
25
|
-
headers: {
|
|
26
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
27
|
-
"Content-Type": "application/json"
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const output = response.data?.choices?.[0]?.message?.content;
|
|
31
|
-
if (!output) {
|
|
32
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "Groq returned empty response", "groq", "Check your model and API key");
|
|
33
|
-
}
|
|
34
|
-
return output;
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
if (err.response) {
|
|
38
|
-
const status = err.response.status;
|
|
39
|
-
const text = err.response.data?.error
|
|
40
|
-
? JSON.stringify(err.response.data.error)
|
|
41
|
-
: err.response.statusText || "Unknown error";
|
|
42
|
-
if (status === 400)
|
|
43
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `Groq rejected the request: ${text}`, "groq", "Check your prompt and model");
|
|
44
|
-
if (status === 401)
|
|
45
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid Groq API key: ${text}`, "groq", "Verify your AI_HOOK_GROQ_KEY environment variable");
|
|
46
|
-
if (status === 429)
|
|
47
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to Groq: ${text}`, "groq", "Throttle requests or upgrade your plan");
|
|
48
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `Groq API error: ${text}`, "groq");
|
|
49
|
-
}
|
|
50
|
-
else if (err.request) {
|
|
51
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting Groq", "groq", "Check your internet connection");
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "groq");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
package/dist/providers/index.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getAvailableProviders = getAvailableProviders;
|
|
4
|
-
exports.getProvider = getProvider;
|
|
5
|
-
const errors_1 = require("../errors");
|
|
6
|
-
const openrouter_1 = require("./openrouter");
|
|
7
|
-
const groq_1 = require("./groq");
|
|
8
|
-
const openai_1 = require("./openai");
|
|
9
|
-
const gemini_1 = require("./gemini");
|
|
10
|
-
const claude_1 = require("./claude");
|
|
11
|
-
const deepkseek_1 = require("./deepkseek");
|
|
12
|
-
const xai_1 = require("./xai");
|
|
13
|
-
const perplexity_1 = require("./perplexity");
|
|
14
|
-
const mistral_1 = require("./mistral");
|
|
15
|
-
const providers = {
|
|
16
|
-
openrouter: openrouter_1.callOpenRouter,
|
|
17
|
-
groq: groq_1.callGroq,
|
|
18
|
-
openai: openai_1.callOpenAI,
|
|
19
|
-
gemini: gemini_1.callGemini,
|
|
20
|
-
claude: claude_1.callClaude,
|
|
21
|
-
deepseek: deepkseek_1.callDeepSeek,
|
|
22
|
-
xai: xai_1.callXAI,
|
|
23
|
-
perplexity: perplexity_1.callPerplexity,
|
|
24
|
-
mistral: mistral_1.callMistral,
|
|
25
|
-
mock: async (prompt, model) => `[MOCK OUTPUT] ${prompt}`
|
|
26
|
-
};
|
|
27
|
-
// Returns an array of providers whose API keys exist in environment
|
|
28
|
-
function getAvailableProviders() {
|
|
29
|
-
const available = [];
|
|
30
|
-
// Always prefer openrouter if present
|
|
31
|
-
if (process.env.AI_HOOK_OPENROUTER_KEY) {
|
|
32
|
-
available.push("openrouter");
|
|
33
|
-
}
|
|
34
|
-
// Add others in order of their presence
|
|
35
|
-
if (process.env.AI_HOOK_GROQ_KEY && !available.includes("groq")) {
|
|
36
|
-
available.push("groq");
|
|
37
|
-
}
|
|
38
|
-
if (process.env.AI_HOOK_OPENAI_KEY && !available.includes("openai")) {
|
|
39
|
-
available.push("openai");
|
|
40
|
-
}
|
|
41
|
-
if (process.env.AI_HOOK_GEMINI_KEY && !available.includes("gemini")) {
|
|
42
|
-
available.push("gemini");
|
|
43
|
-
}
|
|
44
|
-
if (process.env.AI_HOOK_CLAUDE_KEY && !available.includes("claude")) {
|
|
45
|
-
available.push("claude");
|
|
46
|
-
}
|
|
47
|
-
if (process.env.AI_HOOK_DEEPSEEK_KEY && !available.includes("deepseek")) {
|
|
48
|
-
available.push("deepseek");
|
|
49
|
-
}
|
|
50
|
-
if (process.env.AI_HOOK_XAI_KEY && !available.includes("xai")) {
|
|
51
|
-
available.push("xai");
|
|
52
|
-
}
|
|
53
|
-
if (process.env.AI_HOOK_PERPLEXITY_KEY && !available.includes("perplexity")) {
|
|
54
|
-
available.push("perplexity");
|
|
55
|
-
}
|
|
56
|
-
if (process.env.AI_HOOK_MISTRAL_KEY && !available.includes("mistral")) {
|
|
57
|
-
available.push("mistral");
|
|
58
|
-
}
|
|
59
|
-
return available;
|
|
60
|
-
}
|
|
61
|
-
// ✅ Returns both the provider function and the actual provider name
|
|
62
|
-
function getProvider(name) {
|
|
63
|
-
const available = getAvailableProviders();
|
|
64
|
-
// 1. If user specified provider and it's available
|
|
65
|
-
if (name && providers[name]) {
|
|
66
|
-
return { fn: providers[name], provider: name };
|
|
67
|
-
}
|
|
68
|
-
// 2. If at least one provider is available, pick the first one (openrouter always preferred if present)
|
|
69
|
-
if (available.length > 0) {
|
|
70
|
-
console.log(`[ai-hooks] ✅ Auto-selected provider: ${available[0]}`);
|
|
71
|
-
return { fn: providers[available[0]], provider: available[0] };
|
|
72
|
-
}
|
|
73
|
-
// 3. No valid keys found → throw error (single instruction, no fallback)
|
|
74
|
-
throw new errors_1.AIHookError("NO_PROVIDER_FOUND", "No valid AI provider API key was found.\n\nAt least one provider API key is required in your .env file.\n\nPlease add one of the following to your .env (see .env.example for details):\n - AI_HOOK_OPENAI_KEY\n - AI_HOOK_OPENROUTER_KEY\n - AI_HOOK_GROQ_KEY\n", undefined, "Reference .env.example for setup instructions.");
|
|
75
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callMistral = callMistral;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://api.mistral.ai/v1";
|
|
10
|
-
async function callMistral(prompt, model) {
|
|
11
|
-
const apiKey = process.env.AI_HOOK_MISTRAL_KEY;
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing Mistral API key.", "mistral", "Set AI_HOOK_MISTRAL_KEY in your environment variables.");
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios_1.default.post(`${BASE_URL}/chat/completions`, {
|
|
17
|
-
model,
|
|
18
|
-
messages: [
|
|
19
|
-
{
|
|
20
|
-
role: "user",
|
|
21
|
-
content: prompt
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}, {
|
|
25
|
-
headers: {
|
|
26
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
27
|
-
"Content-Type": "application/json"
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const output = response.data?.choices?.[0]?.message?.content;
|
|
31
|
-
if (!output) {
|
|
32
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "Mistral returned empty response", "mistral", "Check your model and API key");
|
|
33
|
-
}
|
|
34
|
-
return output;
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
if (err.response) {
|
|
38
|
-
const status = err.response.status;
|
|
39
|
-
const text = err.response.data?.error
|
|
40
|
-
? JSON.stringify(err.response.data.error)
|
|
41
|
-
: err.response.statusText || "Unknown error";
|
|
42
|
-
if (status === 400)
|
|
43
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `Mistral rejected the request: ${text}`, "mistral", "Check your prompt and model");
|
|
44
|
-
if (status === 401)
|
|
45
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid Mistral API key: ${text}`, "mistral", "Verify your AI_HOOK_MISTRAL_KEY environment variable");
|
|
46
|
-
if (status === 429)
|
|
47
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to Mistral: ${text}`, "mistral", "Throttle requests or upgrade your plan");
|
|
48
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `Mistral API error: ${text}`, "mistral");
|
|
49
|
-
}
|
|
50
|
-
else if (err.request) {
|
|
51
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting Mistral", "mistral", "Check your internet connection");
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "mistral");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
package/dist/providers/openai.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callOpenAI = callOpenAI;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://api.openai.com/v1";
|
|
10
|
-
async function callOpenAI(prompt, model) {
|
|
11
|
-
const apiKey = process.env.AI_HOOK_OPENAI_KEY;
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing OpenAI API key.", "openai", "Set AI_HOOK_OPENAI_KEY in your environment variables.");
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios_1.default.post(`${BASE_URL}/chat/completions`, {
|
|
17
|
-
model,
|
|
18
|
-
messages: [
|
|
19
|
-
{
|
|
20
|
-
role: "user",
|
|
21
|
-
content: prompt
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}, {
|
|
25
|
-
headers: {
|
|
26
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
27
|
-
"Content-Type": "application/json"
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const output = response.data?.choices?.[0]?.message?.content;
|
|
31
|
-
if (!output) {
|
|
32
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "OpenAI returned empty response", "openai", "Check your model and API key");
|
|
33
|
-
}
|
|
34
|
-
return output;
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
if (err.response) {
|
|
38
|
-
const status = err.response.status;
|
|
39
|
-
const text = err.response.data?.error
|
|
40
|
-
? JSON.stringify(err.response.data.error)
|
|
41
|
-
: err.response.statusText || "Unknown error";
|
|
42
|
-
if (status === 400)
|
|
43
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `OpenAI rejected the request: ${text}`, "openai", "Check your prompt and model");
|
|
44
|
-
if (status === 401)
|
|
45
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid OpenAI API key: ${text}`, "openai", "Verify your AI_HOOK_OPENAI_KEY environment variable");
|
|
46
|
-
if (status === 429)
|
|
47
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to OpenAI: ${text}`, "openai", "Throttle requests or upgrade your plan");
|
|
48
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `OpenAI API error: ${text}`, "openai");
|
|
49
|
-
}
|
|
50
|
-
else if (err.request) {
|
|
51
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting OpenAI", "openai", "Check your internet connection");
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "openai");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function callOpenRouter(prompt: string, model: string): Promise<string>;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.callOpenRouter = callOpenRouter;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const errors_1 = require("../errors");
|
|
9
|
-
const BASE_URL = "https://openrouter.ai/api/v1";
|
|
10
|
-
async function callOpenRouter(prompt, model) {
|
|
11
|
-
const apiKey = process.env.AI_HOOK_OPENROUTER_KEY;
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", "Missing OpenRouter API key.", "openrouter", "Set AI_HOOK_OPENROUTER_KEY in your environment variables.");
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios_1.default.post(`${BASE_URL}/chat/completions`, {
|
|
17
|
-
model,
|
|
18
|
-
messages: [{ role: "user", content: prompt }],
|
|
19
|
-
}, {
|
|
20
|
-
headers: {
|
|
21
|
-
Authorization: `Bearer ${apiKey}`,
|
|
22
|
-
"Content-Type": "application/json",
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
const output = response.data?.choices?.[0]?.message?.content;
|
|
26
|
-
if (!output) {
|
|
27
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", "OpenRouter returned empty response.", "openrouter", "Check that the model name is correct and your API key has access to it.");
|
|
28
|
-
}
|
|
29
|
-
return output;
|
|
30
|
-
}
|
|
31
|
-
catch (err) {
|
|
32
|
-
if (err.response) {
|
|
33
|
-
const status = err.response.status;
|
|
34
|
-
// Make sure we get a string message
|
|
35
|
-
const text = err.response.data?.error
|
|
36
|
-
? JSON.stringify(err.response.data.error)
|
|
37
|
-
: err.response.statusText || "Unknown error";
|
|
38
|
-
if (status === 400)
|
|
39
|
-
throw new errors_1.AIHookError("BAD_REQUEST", `OpenRouter rejected the request: ${text}`, "openrouter", "Check your prompt, model name, and payload format.");
|
|
40
|
-
if (status === 401)
|
|
41
|
-
throw new errors_1.AIHookError("INVALID_API_KEY", `Invalid OpenRouter API key: ${text}`, "openrouter", "Verify your AI_HOOK_OPENROUTER_KEY environment variable.");
|
|
42
|
-
if (status === 403)
|
|
43
|
-
throw new errors_1.AIHookError("MODEL_NOT_ALLOWED", `Your API key cannot access this model: ${text}`, "openrouter", "Try a different model or check API key permissions.");
|
|
44
|
-
if (status === 429)
|
|
45
|
-
throw new errors_1.AIHookError("RATE_LIMIT", `Too many requests to OpenRouter: ${text}`, "openrouter", "Consider throttling requests or upgrading your plan.");
|
|
46
|
-
throw new errors_1.AIHookError("PROVIDER_ERROR", `OpenRouter API error: ${text}`, "openrouter", "Check your model, prompt, and API key.");
|
|
47
|
-
}
|
|
48
|
-
else if (err.request) {
|
|
49
|
-
throw new errors_1.AIHookError("NETWORK_ERROR", "Network error while contacting OpenRouter.", "openrouter", "Check your internet connection.");
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
throw new errors_1.AIHookError("UNKNOWN_ERROR", err.message, "openrouter");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|