npm-ai-hooks 1.0.0-beta.0 → 1.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/dist/errors.d.ts +8 -0
- package/dist/errors.js +21 -0
- package/{src/index.ts → dist/index.d.ts} +1 -2
- package/dist/index.js +6 -0
- package/dist/providers/groq.d.ts +2 -0
- package/dist/providers/groq.js +57 -0
- package/dist/providers/index.d.ts +7 -0
- package/{src/providers/index.ts → dist/providers/index.js} +45 -54
- package/dist/providers/openai.d.ts +1 -0
- package/dist/providers/openai.js +19 -0
- package/dist/providers/openrouter.d.ts +1 -0
- package/dist/providers/openrouter.js +55 -0
- package/{src/types/core/providers.ts → dist/types/core/providers.d.ts} +10 -13
- package/dist/types/core/providers.js +2 -0
- package/dist/types/groq.d.ts +2 -0
- package/dist/types/groq.js +4 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.js +11 -0
- package/{src/types/openai.ts → dist/types/openai.d.ts} +2 -3
- package/dist/types/openai.js +4 -0
- package/dist/types/openrouter.d.ts +2 -0
- package/dist/types/openrouter.js +4 -0
- package/dist/wrap.d.ts +5 -0
- package/dist/wrap.js +85 -0
- package/package.json +15 -4
- package/.env.example +0 -14
- package/CODE_OF_CONDUCT.md +0 -35
- package/CONTRIBUTING.md +0 -88
- package/EXAMPLES.md +0 -53
- package/ROADMAP.md +0 -22
- package/SECURITY.md +0 -30
- package/examples/basic/explain.ts +0 -18
- package/examples/basic/rewrite.ts +0 -10
- package/examples/basic/sentiment.ts +0 -10
- package/examples/basic/summarize.ts +0 -10
- package/examples/basic/translate.ts +0 -10
- package/examples/demo.ts +0 -16
- package/examples/model-switch/groq-default.ts +0 -10
- package/examples/model-switch/groq-text2.ts +0 -10
- package/examples/model-switch/openrouter-default.ts +0 -10
- package/examples/model-switch/openrouter-gpt5.ts +0 -10
- package/examples/model-switch/wrong-models.ts +0 -21
- package/examples/openrouter/summarize-switch-model-demo.ts +0 -25
- package/examples/openrouter/translate-switch-model-demo.ts +0 -24
- package/examples/openrouter/translate-to-urdu-demo.ts +0 -19
- package/examples/openrouter-openai/gpt5-demo.ts +0 -25
- package/jest.config.js +0 -11
- package/src/errors.ts +0 -23
- package/src/providers/groq.ts +0 -98
- package/src/providers/openai.ts +0 -19
- package/src/providers/openrouter.ts +0 -100
- package/src/types/groq.ts +0 -20
- package/src/types/index.ts +0 -37
- package/src/types/openrouter.ts +0 -52
- package/src/wrap.ts +0 -93
- package/tsconfig.json +0 -11
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AIHookError = void 0;
|
|
4
|
+
class AIHookError extends Error {
|
|
5
|
+
constructor(code, message, provider, suggestion) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.provider = provider;
|
|
9
|
+
this.suggestion = suggestion;
|
|
10
|
+
// Do NOT print pretty message in constructor
|
|
11
|
+
}
|
|
12
|
+
pretty() {
|
|
13
|
+
return `\n❌ AI-HOOK ERROR: ${this.message}` +
|
|
14
|
+
(this.provider ? `\n Provider: ${this.provider}` : "") +
|
|
15
|
+
(this.suggestion ? `\n Suggestion: ${this.suggestion}\n` : "");
|
|
16
|
+
}
|
|
17
|
+
toString() {
|
|
18
|
+
return this.pretty();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.AIHookError = AIHookError;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { wrap } from "./wrap";
|
|
1
|
+
export { wrap } from "./wrap";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Provider } from "../types";
|
|
2
|
+
import { ProviderFunction } from "../types/core/providers";
|
|
3
|
+
export declare function getAvailableProviders(): Provider[];
|
|
4
|
+
export declare function getProvider(name?: Provider): {
|
|
5
|
+
fn: ProviderFunction<any>;
|
|
6
|
+
provider: Provider | "mock";
|
|
7
|
+
};
|
|
@@ -1,54 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Returns an array of providers whose API keys exist in environment
|
|
16
|
-
|
|
17
|
-
const available
|
|
18
|
-
// Always prefer openrouter if present
|
|
19
|
-
if (process.env.AI_HOOK_OPENROUTER_KEY) {
|
|
20
|
-
available.push("openrouter");
|
|
21
|
-
}
|
|
22
|
-
// Add others in order of their presence
|
|
23
|
-
if (process.env.AI_HOOK_GROQ_KEY && !available.includes("groq")) {
|
|
24
|
-
available.push("groq");
|
|
25
|
-
}
|
|
26
|
-
if (process.env.AI_HOOK_OPENAI_KEY && !available.includes("openai")) {
|
|
27
|
-
available.push("openai");
|
|
28
|
-
}
|
|
29
|
-
return available;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// 3. No valid keys found → throw error (single instruction, no fallback)
|
|
48
|
-
throw new AIHookError(
|
|
49
|
-
"NO_PROVIDER_FOUND",
|
|
50
|
-
"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",
|
|
51
|
-
undefined,
|
|
52
|
-
"Reference .env.example for setup instructions."
|
|
53
|
-
);
|
|
54
|
-
}
|
|
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 openai_1 = require("./openai");
|
|
7
|
+
const openrouter_1 = require("./openrouter");
|
|
8
|
+
const groq_1 = require("./groq");
|
|
9
|
+
const providers = {
|
|
10
|
+
openai: openai_1.callOpenAI,
|
|
11
|
+
openrouter: openrouter_1.callOpenRouter,
|
|
12
|
+
groq: groq_1.callGroq,
|
|
13
|
+
mock: async (prompt, model) => `[MOCK OUTPUT] ${prompt}`
|
|
14
|
+
};
|
|
15
|
+
// Returns an array of providers whose API keys exist in environment
|
|
16
|
+
function getAvailableProviders() {
|
|
17
|
+
const available = [];
|
|
18
|
+
// Always prefer openrouter if present
|
|
19
|
+
if (process.env.AI_HOOK_OPENROUTER_KEY) {
|
|
20
|
+
available.push("openrouter");
|
|
21
|
+
}
|
|
22
|
+
// Add others in order of their presence
|
|
23
|
+
if (process.env.AI_HOOK_GROQ_KEY && !available.includes("groq")) {
|
|
24
|
+
available.push("groq");
|
|
25
|
+
}
|
|
26
|
+
if (process.env.AI_HOOK_OPENAI_KEY && !available.includes("openai")) {
|
|
27
|
+
available.push("openai");
|
|
28
|
+
}
|
|
29
|
+
return available;
|
|
30
|
+
}
|
|
31
|
+
// ✅ Returns both the provider function and the actual provider name
|
|
32
|
+
function getProvider(name) {
|
|
33
|
+
const available = getAvailableProviders();
|
|
34
|
+
// 1. If user specified provider and it's available
|
|
35
|
+
if (name && providers[name]) {
|
|
36
|
+
return { fn: providers[name], provider: name };
|
|
37
|
+
}
|
|
38
|
+
// 2. If at least one provider is available, pick the first one (openrouter always preferred if present)
|
|
39
|
+
if (available.length > 0) {
|
|
40
|
+
console.log(`[ai-hooks] ✅ Auto-selected provider: ${available[0]}`);
|
|
41
|
+
return { fn: providers[available[0]], provider: available[0] };
|
|
42
|
+
}
|
|
43
|
+
// 3. No valid keys found → throw error (single instruction, no fallback)
|
|
44
|
+
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.");
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function callOpenAI(prompt: string, model: string): Promise<any>;
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
async function callOpenAI(prompt, model) {
|
|
9
|
+
const key = process.env.AI_HOOK_OPENAI_KEY;
|
|
10
|
+
if (!key)
|
|
11
|
+
throw new Error("Missing AI_HOOK_OPENAI_KEY");
|
|
12
|
+
const response = await axios_1.default.post("https://api.openai.com/v1/chat/completions", {
|
|
13
|
+
model,
|
|
14
|
+
messages: [{ role: "user", content: prompt }]
|
|
15
|
+
}, {
|
|
16
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
17
|
+
});
|
|
18
|
+
return response.data.choices[0].message.content;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function callOpenRouter(prompt: string, model: string): Promise<string>;
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { Provider, ProviderModels } from "../index";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
mock: ProviderFunction<any>; // generic fallback for mock
|
|
12
|
-
}
|
|
13
|
-
|
|
1
|
+
import { Provider, ProviderModels } from "../index";
|
|
2
|
+
export interface ProviderFunction<P extends Provider = Provider> {
|
|
3
|
+
(prompt: string, model: ProviderModels[P]): Promise<string>;
|
|
4
|
+
}
|
|
5
|
+
export interface ProviderMap {
|
|
6
|
+
openai: ProviderFunction<"openai">;
|
|
7
|
+
openrouter: ProviderFunction<"openrouter">;
|
|
8
|
+
groq: ProviderFunction<"groq">;
|
|
9
|
+
mock: ProviderFunction<any>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type GroqModel = "allam-2-7b" | "deepseek-r1-distill-llama-70b" | "gemma2-9b-it" | "groq/compound" | "groq/compound-mini" | "llama-3.1-8b-instant" | "llama-3.3-70b-versatile" | "meta-llama/llama-4-maverick-17b-128e-instruct" | "meta-llama/llama-4-scout-17b-16e-instruct" | "meta-llama/llama-guard-4-12b" | "meta-llama/llama-prompt-guard-2-22m" | "meta-llama/llama-prompt-guard-2-86m" | "moonshotai/kimi-k2-instruct" | "moonshotai/kimi-k2-instruct-0905" | "openai/gpt-oss-120b" | "openai/gpt-oss-20b" | "qwen/qwen3-32b";
|
|
2
|
+
export declare const GroqDefaultModel: GroqModel;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { OpenAIModel } from "./openai";
|
|
2
|
+
import { OpenRouterModel } from "./openrouter";
|
|
3
|
+
import { GroqModel } from "./groq";
|
|
4
|
+
export type Provider = "openai" | "openrouter" | "groq";
|
|
5
|
+
export type ProviderModels = {
|
|
6
|
+
openai: OpenAIModel;
|
|
7
|
+
openrouter: OpenRouterModel;
|
|
8
|
+
groq: GroqModel;
|
|
9
|
+
};
|
|
10
|
+
export declare const DEFAULT_MODEL: {
|
|
11
|
+
[P in Provider]: ProviderModels[P];
|
|
12
|
+
};
|
|
13
|
+
export type TaskType = "summarize" | "translate" | "explain" | "rewrite" | "sentiment" | "codeReview";
|
|
14
|
+
export type WrapOptions<P extends Provider | undefined = undefined> = {
|
|
15
|
+
provider: P extends Provider ? P : never;
|
|
16
|
+
model?: P extends Provider ? ProviderModels[P] : never;
|
|
17
|
+
task: TaskType;
|
|
18
|
+
targetLanguage?: string;
|
|
19
|
+
} | {
|
|
20
|
+
provider?: never;
|
|
21
|
+
model?: never;
|
|
22
|
+
task: TaskType;
|
|
23
|
+
targetLanguage?: string;
|
|
24
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_MODEL = void 0;
|
|
4
|
+
const openai_1 = require("./openai");
|
|
5
|
+
const openrouter_1 = require("./openrouter");
|
|
6
|
+
const groq_1 = require("./groq");
|
|
7
|
+
exports.DEFAULT_MODEL = {
|
|
8
|
+
openai: openai_1.OpenAIDefaultModel,
|
|
9
|
+
openrouter: openrouter_1.OpenRouterDefaultModel,
|
|
10
|
+
groq: groq_1.GroqDefaultModel,
|
|
11
|
+
};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export type OpenAIModel = "gpt-4" | "gpt-4o" | "gpt-3.5-turbo";
|
|
2
|
-
|
|
3
|
-
export const OpenAIDefaultModel: OpenAIModel = "gpt-4";
|
|
1
|
+
export type OpenAIModel = "gpt-4" | "gpt-4o" | "gpt-3.5-turbo";
|
|
2
|
+
export declare const OpenAIDefaultModel: OpenAIModel;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type OpenRouterModel = "openai/gpt-oss-20b:free" | "openai/gpt-4.1" | "openai/gpt-5-pro" | "openai/gpt-5-codex" | "openai/gpt-5-chat" | "openai/gpt-5" | "openai/gpt-5-mini" | "openai/gpt-5-nano" | "openai/gpt-oss-120b" | "openai/gpt-oss-20b" | "openai/o3-pro" | "openai/codex-mini" | "openai/o3" | "openai/o4-mini" | "openai/gpt-4.1-mini" | "openai/gpt-4.1-nano" | "openai/o1-pro" | "openai/gpt-4o-mini-search-preview" | "openai/gpt-4o-search-preview" | "openai/o3-mini-high" | "openai/o3-mini" | "openai/o1" | "openai/gpt-4o-2024-11-20" | "openai/o1-mini" | "openai/o1-mini-2024-09-12" | "openai/chatgpt-4o-latest" | "openai/gpt-4o-2024-08-06" | "openai/gpt-4o-mini" | "openai/gpt-4o-mini-2024-07-18" | "openai/gpt-4o" | "openai/gpt-4o:extended" | "openai/gpt-4o-2024-05-13" | "openai/gpt-4-turbo" | "openai/gpt-3.5-turbo-0613" | "openai/gpt-4-turbo-preview" | "openai/gpt-4-1106-preview" | "openai/gpt-3.5-turbo-instruct" | "openai/gpt-3.5-turbo-16k" | "openai/gpt-3.5-turbo" | "openai/gpt-4" | "openai/gpt-4-0314" | "openai/gpt-4.5-preview" | "openai/o1-preview" | "openai/o1-preview-2024-09-12" | "openai/gpt-4-vision-preview" | "openai/gpt-3.5-turbo-1106" | "openai/gpt-4-32k" | "openai/gpt-4-32k-0314" | "openai/gpt-3.5-turbo-0301" | "openai/gpt-3.5-turbo-0125";
|
|
2
|
+
export declare const OpenRouterDefaultModel: OpenRouterModel;
|
package/dist/wrap.d.ts
ADDED
package/dist/wrap.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
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.wrap = wrap;
|
|
7
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
dotenv_1.default.config();
|
|
9
|
+
const providers_1 = require("./providers");
|
|
10
|
+
const types_1 = require("./types");
|
|
11
|
+
function handleError(err) {
|
|
12
|
+
if (err && typeof err === "object" && "pretty" in err && typeof err.pretty === "function") {
|
|
13
|
+
// Print pretty message and exit
|
|
14
|
+
console.error(err.pretty());
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
console.error(err);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
throw new Error("Process exited due to AIHookError"); // for TS never
|
|
22
|
+
}
|
|
23
|
+
function wrap(fn, options) {
|
|
24
|
+
return async (...args) => {
|
|
25
|
+
try {
|
|
26
|
+
const input = fn(...args);
|
|
27
|
+
// Step 1: get provider function and the actual provider name
|
|
28
|
+
const { fn: providerFn, provider: providerKey } = (0, providers_1.getProvider)(options.provider);
|
|
29
|
+
// Step 2: pick model: passed model or provider-specific default
|
|
30
|
+
const model = options.model || (providerKey in types_1.DEFAULT_MODEL ? types_1.DEFAULT_MODEL[providerKey] : undefined);
|
|
31
|
+
if (!model) {
|
|
32
|
+
throw new (require('./errors').AIHookError)("NO_MODEL_FOUND", "No model found: You must specify a provider or pass a valid model.\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", options.provider, "Reference .env.example for setup instructions.");
|
|
33
|
+
}
|
|
34
|
+
// Step 3: build prompt
|
|
35
|
+
const prompt = buildPrompt(options.task, input, options.targetLanguage);
|
|
36
|
+
const startTime = Date.now();
|
|
37
|
+
let output;
|
|
38
|
+
try {
|
|
39
|
+
output = await providerFn(prompt, model);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (err instanceof require('./errors').AIHookError) {
|
|
43
|
+
handleError(err);
|
|
44
|
+
}
|
|
45
|
+
if (err instanceof Error) {
|
|
46
|
+
throw new Error(`[ai-hooks] Unknown error calling provider: ${err.message}`);
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`[ai-hooks] Unknown non-error thrown by provider: ${String(err)}`);
|
|
49
|
+
}
|
|
50
|
+
const endTime = Date.now();
|
|
51
|
+
return {
|
|
52
|
+
output,
|
|
53
|
+
meta: {
|
|
54
|
+
provider: providerKey,
|
|
55
|
+
model,
|
|
56
|
+
cached: false,
|
|
57
|
+
estimatedCostUSD: 0.0,
|
|
58
|
+
latencyMs: endTime - startTime
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
handleError(err);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function buildPrompt(task, text, targetLanguage) {
|
|
68
|
+
switch (task) {
|
|
69
|
+
case "summarize":
|
|
70
|
+
return `Summarize the following text:\n${text}`;
|
|
71
|
+
case "translate":
|
|
72
|
+
const language = targetLanguage || "English"; // default to English
|
|
73
|
+
return `Translate this text into ${language}:\n${text}`;
|
|
74
|
+
case "explain":
|
|
75
|
+
return `Explain this clearly:\n${text}`;
|
|
76
|
+
case "rewrite":
|
|
77
|
+
return `Rewrite this text with better clarity:\n${text}`;
|
|
78
|
+
case "sentiment":
|
|
79
|
+
return `Analyze the sentiment of this text:\n${text}`;
|
|
80
|
+
case "codeReview":
|
|
81
|
+
return `Review this code and suggest improvements:\n${text}`;
|
|
82
|
+
default:
|
|
83
|
+
return text;
|
|
84
|
+
}
|
|
85
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npm-ai-hooks",
|
|
3
|
-
"version": "1.0.0
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "index.js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Universal AI Hook Layer for Node.js – one wrapper for all AI providers.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/**/*"
|
|
16
|
+
],
|
|
6
17
|
"scripts": {
|
|
7
18
|
"dev": "ts-node src/index.ts",
|
|
8
19
|
"build:clean": "rimraf dist && tsc",
|
|
@@ -12,7 +23,7 @@
|
|
|
12
23
|
"demo": "npx ts-node examples/demo.ts"
|
|
13
24
|
},
|
|
14
25
|
"keywords": [],
|
|
15
|
-
"author": "",
|
|
26
|
+
"author": "AteebNoOne",
|
|
16
27
|
"license": "ISC",
|
|
17
28
|
"dependencies": {
|
|
18
29
|
"axios": "^1.12.2",
|
package/.env.example
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# OpenAI API key (for OpenRouter OpenAI models or standalone OpenAI)
|
|
2
|
-
AI_HOOK_OPENAI_KEY=your_openai_api_key_here
|
|
3
|
-
|
|
4
|
-
# OpenRouter API key
|
|
5
|
-
AI_HOOK_OPENROUTER_KEY=your_openrouter_api_key_here
|
|
6
|
-
|
|
7
|
-
# Groq API key
|
|
8
|
-
AI_HOOK_GROQ_KEY=your_groq_api_key_here
|
|
9
|
-
|
|
10
|
-
# Default provider (optional)
|
|
11
|
-
# AI_HOOK_DEFAULT_PROVIDER=openrouter
|
|
12
|
-
|
|
13
|
-
# Default model is handled by code, so no need to set it here
|
|
14
|
-
# AI_HOOK_DEFAULT_MODEL=
|
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
---
|
|
3
|
-
|
|
4
|
-
## 3. `CODE_OF_CONDUCT.md`
|
|
5
|
-
|
|
6
|
-
```md
|
|
7
|
-
# Contributor Covenant Code of Conduct
|
|
8
|
-
|
|
9
|
-
## Our Pledge
|
|
10
|
-
|
|
11
|
-
We as members, contributors, and maintainers pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
12
|
-
|
|
13
|
-
## Our Standards
|
|
14
|
-
|
|
15
|
-
Examples of behavior that contributes to a positive environment include:
|
|
16
|
-
|
|
17
|
-
- Using welcoming and inclusive language
|
|
18
|
-
- Being respectful of differing viewpoints and experiences
|
|
19
|
-
- Gracefully accepting constructive criticism
|
|
20
|
-
- Focusing on what is best for the community
|
|
21
|
-
- Showing empathy towards other community members
|
|
22
|
-
|
|
23
|
-
Examples of unacceptable behavior include:
|
|
24
|
-
|
|
25
|
-
- Harassment of public or private forms
|
|
26
|
-
- Trolling, insulting/derogatory comments
|
|
27
|
-
- Publishing others’ private information without permission
|
|
28
|
-
- Other conduct which could reasonably be considered inappropriate
|
|
29
|
-
|
|
30
|
-
## Enforcement
|
|
31
|
-
|
|
32
|
-
Instances of abusive behavior may be reported to the maintainers via [issues](https://github.com/RealTeebot/npm-ai-hooks/issues).
|
|
33
|
-
All complaints will be reviewed and addressed appropriately.
|
|
34
|
-
|
|
35
|
-
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/).
|