npm-ai-hooks 2.0.0 → 2.0.2

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.
@@ -0,0 +1,91 @@
1
+ // Provider display names
2
+ export const PROVIDER_NAMES = {
3
+ openai: "OpenAI",
4
+ claude: "Claude",
5
+ gemini: "Gemini",
6
+ groq: "Groq",
7
+ deepseek: "DeepSeek",
8
+ xai: "xAI",
9
+ mistral: "Mistral",
10
+ perplexity: "Perplexity",
11
+ openrouter: "OpenRouter"
12
+ };
13
+ // Get all available models for a provider
14
+ export function getProviderModels(provider) {
15
+ // These are the actual model types from the library
16
+ const modelMap = {
17
+ openai: [
18
+ "gpt-4.1",
19
+ "gpt-4.1-mini",
20
+ "gpt-4o",
21
+ "gpt-4o-mini",
22
+ "gpt-4-turbo",
23
+ "gpt-4",
24
+ "gpt-3.5-turbo"
25
+ ],
26
+ claude: [
27
+ "claude-3-5-sonnet-20241022",
28
+ "claude-3-5-haiku-20241022",
29
+ "claude-3-opus-20240229",
30
+ "claude-3-sonnet-20240229",
31
+ "claude-3-haiku-20240307"
32
+ ],
33
+ gemini: [
34
+ "gemini-2.0-flash-exp",
35
+ "gemini-2.0-flash-thinking-exp-01-21",
36
+ "gemini-exp-1206",
37
+ "gemini-1.5-pro",
38
+ "gemini-1.5-flash",
39
+ "gemini-1.5-flash-8b"
40
+ ],
41
+ groq: [
42
+ "llama-3.3-70b-versatile",
43
+ "llama-3.1-8b-instant",
44
+ "gemma2-9b-it"
45
+ ],
46
+ deepseek: [
47
+ "deepseek-chat",
48
+ "deepseek-reasoner"
49
+ ],
50
+ xai: [
51
+ "grok-4-0131",
52
+ "grok-beta",
53
+ "grok-2-1212"
54
+ ],
55
+ mistral: [
56
+ "mistral-large-latest",
57
+ "mistral-small-latest",
58
+ "pixtral-large-latest",
59
+ "ministral-8b-latest",
60
+ "mistral-nemo"
61
+ ],
62
+ perplexity: [
63
+ "llama-3.1-sonar-large-128k-online",
64
+ "llama-3.1-sonar-small-128k-online",
65
+ "llama-3.1-sonar-large-128k-chat",
66
+ "llama-3.1-sonar-small-128k-chat"
67
+ ],
68
+ openrouter: [
69
+ "openai/gpt-4o",
70
+ "anthropic/claude-3.5-sonnet",
71
+ "google/gemini-2.0-flash-exp",
72
+ "meta-llama/llama-3.3-70b-instruct",
73
+ "deepseek/deepseek-chat"
74
+ ]
75
+ };
76
+ return modelMap[provider] || [];
77
+ }
78
+ // Get all supported providers
79
+ export function getAllProviders() {
80
+ return Object.keys(PROVIDER_NAMES);
81
+ }
82
+ export function getProviderInfo(provider) {
83
+ return {
84
+ key: provider,
85
+ name: PROVIDER_NAMES[provider],
86
+ models: getProviderModels(provider)
87
+ };
88
+ }
89
+ export function getAllProviderInfo() {
90
+ return getAllProviders().map(getProviderInfo);
91
+ }
package/dist/esm/wrap.js CHANGED
@@ -31,16 +31,43 @@ export function wrap(fn, options) {
31
31
  }
32
32
  return async (...args) => {
33
33
  try {
34
- const input = fn(...args);
34
+ // Await the function result to handle both sync and async functions
35
+ const rawInput = fn(...args);
36
+ const input = rawInput instanceof Promise ? await rawInput : rawInput;
37
+ // Check if input is multimodal
38
+ const isMultimodal = typeof input === 'object' && input !== null && ('image' in input || 'file' in input);
39
+ const textInput = isMultimodal ? input.text || '' : String(input);
40
+ const imageData = isMultimodal ? input.image : undefined;
41
+ const fileData = isMultimodal ? input.file : undefined;
35
42
  // Step 1: get provider function and the actual provider name
36
43
  const { fn: providerFn, provider: providerKey } = getProvider(options.provider);
37
44
  // Step 2: pick model: passed model or provider-specific default
38
45
  const model = options.model || (providerKey in DEFAULT_MODEL ? DEFAULT_MODEL[providerKey] : undefined);
39
46
  if (!model) {
40
- throw new 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.");
47
+ throw new 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 - OPENAI_KEY\n - OPENROUTER_KEY\n - GROQ_KEY\n", options.provider, "Reference .env.example for setup instructions.");
48
+ }
49
+ // Step 3: build prompt with multimodal support
50
+ let prompt;
51
+ if (options.customPrompt) {
52
+ // Use custom prompt if provided
53
+ prompt = `${options.customPrompt}\n\n${textInput}`;
54
+ if (imageData) {
55
+ prompt = `${prompt}\n\n[Image attached]`;
56
+ }
57
+ if (fileData) {
58
+ prompt = `${prompt}\n\n[File: ${fileData.name}]`;
59
+ }
60
+ }
61
+ else {
62
+ // Use built-in task prompt
63
+ prompt = buildPrompt(options.task, textInput, options.targetLanguage);
64
+ if (imageData) {
65
+ prompt = `${prompt}\n\n[Image attached]`;
66
+ }
67
+ if (fileData) {
68
+ prompt = `${prompt}\n\n[File: ${fileData.name}]`;
69
+ }
41
70
  }
42
- // Step 3: build prompt
43
- const prompt = buildPrompt(options.task, input, options.targetLanguage);
44
71
  const startTime = Date.now();
45
72
  let output;
46
73
  try {
package/dist/index.d.ts CHANGED
@@ -1,2 +1,7 @@
1
1
  export { wrap } from "./wrap";
2
+ export type { MultimodalInput } from "./wrap";
2
3
  export { initAIHooks, addProvider, removeProvider, getAvailableProviders, getProvider, isInitialized, reset } from "./providers";
4
+ export type { Provider, ProviderModels, TaskType } from "./types";
5
+ export type { OpenAIModel, ClaudeModel, GeminiModel, GroqModel, DeepSeekModel, XAIModel, MistralModel, PerplexityModel, OpenRouterModel } from "./types";
6
+ export { PROVIDER_NAMES, getProviderModels, getAllProviders, getProviderInfo, getAllProviderInfo, type ProviderInfo } from "./utils/providerInfo";
7
+ export { validateApiKey, validateApiKeys, quickValidateKeyFormat, type KeyValidationResult } from "./utils/keyValidator";
@@ -9,7 +9,7 @@ export declare class GeminiProvider extends BaseProvider {
9
9
  protected buildRequestConfig(prompt: string, model: string, apiKey: string): {
10
10
  url: string;
11
11
  headers: {};
12
- method?: import("axios").Method | string;
12
+ method?: (string & {}) | import("axios").Method;
13
13
  baseURL?: string;
14
14
  allowAbsoluteUrls?: boolean;
15
15
  transformRequest?: import("axios").AxiosRequestTransformer | import("axios").AxiosRequestTransformer[];
@@ -20,10 +20,10 @@ export declare class GeminiProvider extends BaseProvider {
20
20
  timeout?: number;
21
21
  timeoutErrorMessage?: string;
22
22
  withCredentials?: boolean;
23
- adapter?: (import("axios").AxiosAdapter | ("fetch" | "xhr" | "http" | (string & {}))) | (import("axios").AxiosAdapter | ("fetch" | "xhr" | "http" | (string & {})))[];
23
+ adapter?: (import("axios").AxiosAdapter | ((string & {}) | "xhr" | "http" | "fetch")) | (import("axios").AxiosAdapter | ((string & {}) | "xhr" | "http" | "fetch"))[];
24
24
  auth?: import("axios").AxiosBasicCredentials;
25
25
  responseType?: import("axios").ResponseType;
26
- responseEncoding?: import("axios").responseEncoding | string;
26
+ responseEncoding?: (string & {}) | import("axios").responseEncoding;
27
27
  xsrfCookieName?: string;
28
28
  xsrfHeaderName?: string;
29
29
  onUploadProgress?: (progressEvent: import("axios").AxiosProgressEvent) => void;
@@ -36,13 +36,18 @@ export declare class GeminiProvider extends BaseProvider {
36
36
  beforeRedirect?: (options: Record<string, any>, responseDetails: {
37
37
  headers: Record<string, string>;
38
38
  statusCode: import("axios").HttpStatusCode;
39
+ }, requestDetails: {
40
+ headers: Record<string, string>;
41
+ url: string;
42
+ method: string;
39
43
  }) => void;
40
44
  socketPath?: string | null;
45
+ allowedSocketPaths?: string | string[] | null;
41
46
  transport?: any;
42
47
  httpAgent?: any;
43
48
  httpsAgent?: any;
44
49
  proxy?: import("axios").AxiosProxyConfig | false;
45
- cancelToken?: import("axios").CancelToken;
50
+ cancelToken?: import("axios").CancelToken | undefined;
46
51
  decompress?: boolean;
47
52
  transitional?: import("axios").TransitionalOptions;
48
53
  signal?: import("axios").GenericAbortSignal;
@@ -57,8 +62,16 @@ export declare class GeminiProvider extends BaseProvider {
57
62
  family?: import("axios").AddressFamily;
58
63
  lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: import("axios").LookupAddress | import("axios").LookupAddress[], family?: import("axios").AddressFamily) => void) => void) | ((hostname: string, options: object) => Promise<[address: import("axios").LookupAddressEntry | import("axios").LookupAddressEntry[], family?: import("axios").AddressFamily] | import("axios").LookupAddress>);
59
64
  withXSRFToken?: boolean | ((config: import("axios").InternalAxiosRequestConfig) => boolean | undefined);
60
- parseReviver?: (this: any, key: string, value: any) => any;
65
+ parseReviver?: (this: any, key: string, value: any, context?: {
66
+ source?: string;
67
+ }) => any;
61
68
  fetchOptions?: Omit<RequestInit, "body" | "headers" | "method" | "signal"> | Record<string, any>;
69
+ httpVersion?: 1 | 2;
70
+ http2Options?: Record<string, any> & {
71
+ sessionTimeout?: number;
72
+ };
73
+ formDataHeaderPolicy?: "legacy" | "content-only";
74
+ redact?: string[];
62
75
  };
63
76
  protected buildAuthHeaders(): Record<string, string>;
64
77
  }
@@ -7,6 +7,15 @@ import { DeepSeekModel } from "./deepseek";
7
7
  import { XAIModel } from "./xai";
8
8
  import { PerplexityModel } from "./perplexity";
9
9
  import { MistralModel } from "./mistral";
10
+ export type { OpenAIModel } from "./openai";
11
+ export type { OpenRouterModel } from "./openrouter";
12
+ export type { GroqModel } from "./groq";
13
+ export type { GeminiModel } from "./gemini";
14
+ export type { ClaudeModel } from "./claude";
15
+ export type { DeepSeekModel } from "./deepseek";
16
+ export type { XAIModel } from "./xai";
17
+ export type { PerplexityModel } from "./perplexity";
18
+ export type { MistralModel } from "./mistral";
10
19
  export type Provider = "openrouter" | "groq" | "openai" | "gemini" | "claude" | "deepseek" | "xai" | "perplexity" | "mistral";
11
20
  export type ProviderModels = {
12
21
  openrouter: OpenRouterModel;
@@ -26,11 +35,13 @@ export type TaskType = "summarize" | "translate" | "explain" | "rewrite" | "sent
26
35
  export type WrapOptions<P extends Provider | undefined = undefined> = {
27
36
  provider: P extends Provider ? P : never;
28
37
  model?: P extends Provider ? ProviderModels[P] : never;
29
- task: TaskType;
38
+ task?: TaskType;
30
39
  targetLanguage?: string;
40
+ customPrompt?: string;
31
41
  } | {
32
42
  provider?: never;
33
43
  model?: never;
34
- task: TaskType;
44
+ task?: TaskType;
35
45
  targetLanguage?: string;
46
+ customPrompt?: string;
36
47
  };
@@ -0,0 +1,19 @@
1
+ import type { Provider } from "../types";
2
+ export interface KeyValidationResult {
3
+ valid: boolean;
4
+ provider: Provider;
5
+ error?: string;
6
+ message: string;
7
+ }
8
+ /**
9
+ * Validates an API key by making a minimal test request to the provider
10
+ */
11
+ export declare function validateApiKey(provider: Provider, apiKey: string): Promise<KeyValidationResult>;
12
+ /**
13
+ * Validates multiple API keys
14
+ */
15
+ export declare function validateApiKeys(keys: Record<Provider, string>): Promise<Record<Provider, KeyValidationResult>>;
16
+ /**
17
+ * Quick check if API key format looks valid (doesn't make API call)
18
+ */
19
+ export declare function quickValidateKeyFormat(provider: Provider, apiKey: string): KeyValidationResult;
@@ -0,0 +1,11 @@
1
+ import type { Provider } from "../types";
2
+ export declare const PROVIDER_NAMES: Record<Provider, string>;
3
+ export declare function getProviderModels(provider: Provider): string[];
4
+ export declare function getAllProviders(): Provider[];
5
+ export interface ProviderInfo {
6
+ key: Provider;
7
+ name: string;
8
+ models: string[];
9
+ }
10
+ export declare function getProviderInfo(provider: Provider): ProviderInfo;
11
+ export declare function getAllProviderInfo(): ProviderInfo[];
package/dist/wrap.d.ts CHANGED
@@ -1,4 +1,13 @@
1
1
  import { WrapOptions, Provider } from "./types";
2
+ export interface MultimodalInput {
3
+ text?: string;
4
+ image?: string;
5
+ file?: {
6
+ name: string;
7
+ data: string;
8
+ type: string;
9
+ };
10
+ }
2
11
  export declare function wrap<T extends (...args: any[]) => any, P extends Provider | undefined = undefined>(fn: T, options: WrapOptions<P>): (...args: Parameters<T>) => Promise<{
3
12
  output: string;
4
13
  meta: any;
package/package.json CHANGED
@@ -1,107 +1,94 @@
1
- {
2
- "name": "npm-ai-hooks",
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",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/esm/index.js",
12
- "require": "./dist/cjs/index.js"
13
- }
14
- },
15
- "files": [
16
- "dist",
17
- "Readme.md",
18
- "LICENSE"
19
- ],
20
- "scripts": {
21
- "dev": "ts-node src/index.ts",
22
- "clean": "rimraf dist",
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",
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",
37
- "lint": "eslint . --ext .ts",
38
- "format": "prettier --write .",
39
- "prepare": "npm run build",
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"
44
- },
45
- "keywords": [
46
- "ai",
47
- "hooks",
48
- "llm",
49
- "nodejs",
50
- "typescript",
51
- "openai",
52
- "gemini",
53
- "claude",
54
- "deepseek",
55
- "groq",
56
- "mistral"
57
- ],
58
- "author": "AteebNoOne <ateebnoone@gmail.com>",
59
- "repository": {
60
- "type": "git",
61
- "url": "https://github.com/iTeebot/npm-ai-hooks.git"
62
- },
63
- "license": "MIT",
64
- "dependencies": {
65
- "axios": "^1.12.2"
66
- },
67
- "devDependencies": {
68
- "@types/jest": "^30.0.0",
69
- "@types/node": "^24.7.0",
70
- "dotenv": "^17.2.3",
71
- "eslint": "^9.37.0",
72
- "jest": "^30.2.0",
73
- "prettier": "^3.6.2",
74
- "rimraf": "^6.0.1",
75
- "ts-jest": "^29.4.4",
76
- "ts-node": "^10.9.2",
77
- "typescript": "^5.9.3"
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
- ],
101
- "engines": {
102
- "node": ">=18"
103
- },
104
- "publishConfig": {
105
- "access": "public"
106
- }
107
- }
1
+ {
2
+ "name": "npm-ai-hooks",
3
+ "version": "2.0.2",
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",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/esm/index.js",
12
+ "require": "./dist/cjs/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "Readme.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "dev": "ts-node src/index.ts",
22
+ "clean": "rimraf dist",
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",
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",
37
+ "lint": "eslint . --ext .ts",
38
+ "format": "prettier --write .",
39
+ "prepare": "npm run build",
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"
44
+ },
45
+ "author": "AteebNoOne <ateebnoone@gmail.com>",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/iTeebot/npm-ai-hooks.git"
49
+ },
50
+ "license": "MIT",
51
+ "dependencies": {
52
+ "axios": "^1.12.2"
53
+ },
54
+ "devDependencies": {
55
+ "@types/jest": "^30.0.0",
56
+ "@types/node": "^24.7.0",
57
+ "dotenv": "^17.2.3",
58
+ "eslint": "^9.37.0",
59
+ "jest": "^30.2.0",
60
+ "prettier": "^3.6.2",
61
+ "rimraf": "^6.0.1",
62
+ "ts-jest": "^29.4.4",
63
+ "ts-node": "^10.9.2",
64
+ "typescript": "^5.9.3"
65
+ },
66
+ "keywords": [
67
+ "ai",
68
+ "llm",
69
+ "openai",
70
+ "claude",
71
+ "gemini",
72
+ "groq",
73
+ "openrouter",
74
+ "deepseek",
75
+ "mistral",
76
+ "xai",
77
+ "perplexity",
78
+ "react",
79
+ "vite",
80
+ "express",
81
+ "nodejs",
82
+ "typescript",
83
+ "hooks",
84
+ "wrapper",
85
+ "universal",
86
+ "cross-platform"
87
+ ],
88
+ "engines": {
89
+ "node": ">=18"
90
+ },
91
+ "publishConfig": {
92
+ "access": "public"
93
+ }
94
+ }