@hazeljs/ai 0.2.0-beta.1

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.
Files changed (53) hide show
  1. package/README.md +496 -0
  2. package/dist/ai-enhanced.service.d.ts +108 -0
  3. package/dist/ai-enhanced.service.d.ts.map +1 -0
  4. package/dist/ai-enhanced.service.js +345 -0
  5. package/dist/ai-enhanced.types.d.ts +269 -0
  6. package/dist/ai-enhanced.types.d.ts.map +1 -0
  7. package/dist/ai-enhanced.types.js +2 -0
  8. package/dist/ai.decorator.d.ts +4 -0
  9. package/dist/ai.decorator.d.ts.map +1 -0
  10. package/dist/ai.decorator.js +57 -0
  11. package/dist/ai.module.d.ts +12 -0
  12. package/dist/ai.module.d.ts.map +1 -0
  13. package/dist/ai.module.js +44 -0
  14. package/dist/ai.service.d.ts +10 -0
  15. package/dist/ai.service.d.ts.map +1 -0
  16. package/dist/ai.service.js +261 -0
  17. package/dist/ai.types.d.ts +30 -0
  18. package/dist/ai.types.d.ts.map +1 -0
  19. package/dist/ai.types.js +2 -0
  20. package/dist/context/context.manager.d.ts +69 -0
  21. package/dist/context/context.manager.d.ts.map +1 -0
  22. package/dist/context/context.manager.js +168 -0
  23. package/dist/decorators/ai-function.decorator.d.ts +42 -0
  24. package/dist/decorators/ai-function.decorator.d.ts.map +1 -0
  25. package/dist/decorators/ai-function.decorator.js +80 -0
  26. package/dist/decorators/ai-validate.decorator.d.ts +46 -0
  27. package/dist/decorators/ai-validate.decorator.d.ts.map +1 -0
  28. package/dist/decorators/ai-validate.decorator.js +83 -0
  29. package/dist/index.d.ts +17 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +38 -0
  32. package/dist/providers/anthropic.provider.d.ts +48 -0
  33. package/dist/providers/anthropic.provider.d.ts.map +1 -0
  34. package/dist/providers/anthropic.provider.js +194 -0
  35. package/dist/providers/cohere.provider.d.ts +57 -0
  36. package/dist/providers/cohere.provider.d.ts.map +1 -0
  37. package/dist/providers/cohere.provider.js +230 -0
  38. package/dist/providers/gemini.provider.d.ts +45 -0
  39. package/dist/providers/gemini.provider.d.ts.map +1 -0
  40. package/dist/providers/gemini.provider.js +180 -0
  41. package/dist/providers/ollama.provider.d.ts +45 -0
  42. package/dist/providers/ollama.provider.d.ts.map +1 -0
  43. package/dist/providers/ollama.provider.js +232 -0
  44. package/dist/providers/openai.provider.d.ts +47 -0
  45. package/dist/providers/openai.provider.d.ts.map +1 -0
  46. package/dist/providers/openai.provider.js +273 -0
  47. package/dist/tracking/token.tracker.d.ts +72 -0
  48. package/dist/tracking/token.tracker.d.ts.map +1 -0
  49. package/dist/tracking/token.tracker.js +222 -0
  50. package/dist/vector/vector.service.d.ts +50 -0
  51. package/dist/vector/vector.service.d.ts.map +1 -0
  52. package/dist/vector/vector.service.js +163 -0
  53. package/package.json +52 -0
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TokenTracker = void 0;
16
+ const core_1 = require("@hazeljs/core");
17
+ const core_2 = __importDefault(require("@hazeljs/core"));
18
+ /**
19
+ * Token Usage Tracker
20
+ * Tracks and limits token usage per user/request
21
+ */
22
+ let TokenTracker = class TokenTracker {
23
+ constructor(config) {
24
+ this.usageHistory = [];
25
+ this.userUsage = new Map();
26
+ // Token costs per 1K tokens (as of 2024)
27
+ this.TOKEN_COSTS = {
28
+ 'gpt-4-turbo-preview': { prompt: 0.01, completion: 0.03 },
29
+ 'gpt-4': { prompt: 0.03, completion: 0.06 },
30
+ 'gpt-3.5-turbo': { prompt: 0.0005, completion: 0.0015 },
31
+ 'claude-3-opus': { prompt: 0.015, completion: 0.075 },
32
+ 'claude-3-sonnet': { prompt: 0.003, completion: 0.015 },
33
+ 'claude-3-haiku': { prompt: 0.00025, completion: 0.00125 },
34
+ };
35
+ this.config = {
36
+ maxTokensPerRequest: config?.maxTokensPerRequest || 4096,
37
+ maxTokensPerDay: config?.maxTokensPerDay || 100000,
38
+ maxTokensPerMonth: config?.maxTokensPerMonth || 1000000,
39
+ costPerToken: config?.costPerToken,
40
+ };
41
+ core_2.default.info('Token Tracker initialized', this.config);
42
+ }
43
+ /**
44
+ * Track token usage
45
+ */
46
+ track(usage, model) {
47
+ // Calculate cost if not provided
48
+ if (!usage.cost && model) {
49
+ usage.cost = this.calculateCost(usage, model);
50
+ }
51
+ this.usageHistory.push(usage);
52
+ // Track per user if userId provided
53
+ if (usage.userId) {
54
+ const userHistory = this.userUsage.get(usage.userId) || [];
55
+ userHistory.push(usage);
56
+ this.userUsage.set(usage.userId, userHistory);
57
+ }
58
+ core_2.default.debug('Token usage tracked', {
59
+ userId: usage.userId,
60
+ totalTokens: usage.totalTokens,
61
+ cost: usage.cost,
62
+ });
63
+ }
64
+ /**
65
+ * Check if request is within limits
66
+ */
67
+ async checkLimits(userId, requestTokens) {
68
+ // Check request token limit
69
+ if (requestTokens && requestTokens > this.config.maxTokensPerRequest) {
70
+ return {
71
+ allowed: false,
72
+ reason: `Request exceeds token limit (${requestTokens} > ${this.config.maxTokensPerRequest})`,
73
+ };
74
+ }
75
+ if (!userId) {
76
+ return { allowed: true };
77
+ }
78
+ const now = Date.now();
79
+ const oneDayAgo = now - 24 * 60 * 60 * 1000;
80
+ const oneMonthAgo = now - 30 * 24 * 60 * 60 * 1000;
81
+ const userHistory = this.userUsage.get(userId) || [];
82
+ // Calculate daily usage
83
+ const dailyUsage = userHistory
84
+ .filter((u) => u.timestamp > oneDayAgo)
85
+ .reduce((sum, u) => sum + u.totalTokens, 0);
86
+ // Calculate monthly usage
87
+ const monthlyUsage = userHistory
88
+ .filter((u) => u.timestamp > oneMonthAgo)
89
+ .reduce((sum, u) => sum + u.totalTokens, 0);
90
+ const usage = {
91
+ today: dailyUsage,
92
+ month: monthlyUsage,
93
+ limit: {
94
+ daily: this.config.maxTokensPerDay,
95
+ monthly: this.config.maxTokensPerMonth,
96
+ },
97
+ };
98
+ // Check daily limit
99
+ if (dailyUsage >= this.config.maxTokensPerDay) {
100
+ return {
101
+ allowed: false,
102
+ reason: 'Daily token limit exceeded',
103
+ usage,
104
+ };
105
+ }
106
+ // Check monthly limit
107
+ if (monthlyUsage >= this.config.maxTokensPerMonth) {
108
+ return {
109
+ allowed: false,
110
+ reason: 'Monthly token limit exceeded',
111
+ usage,
112
+ };
113
+ }
114
+ return { allowed: true, usage };
115
+ }
116
+ /**
117
+ * Calculate cost for token usage
118
+ */
119
+ calculateCost(usage, model) {
120
+ const costs = this.TOKEN_COSTS[model];
121
+ if (!costs) {
122
+ core_2.default.warn(`Unknown model for cost calculation: ${model}`);
123
+ return 0;
124
+ }
125
+ const promptCost = (usage.promptTokens / 1000) * costs.prompt;
126
+ const completionCost = (usage.completionTokens / 1000) * costs.completion;
127
+ return promptCost + completionCost;
128
+ }
129
+ /**
130
+ * Get usage statistics for a user
131
+ */
132
+ getUserStats(userId, days = 30) {
133
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
134
+ const userHistory = (this.userUsage.get(userId) || []).filter((u) => u.timestamp > cutoff);
135
+ const totalTokens = userHistory.reduce((sum, u) => sum + u.totalTokens, 0);
136
+ const totalCost = userHistory.reduce((sum, u) => sum + (u.cost || 0), 0);
137
+ const requestCount = userHistory.length;
138
+ return {
139
+ totalTokens,
140
+ totalCost,
141
+ requestCount,
142
+ averageTokensPerRequest: requestCount > 0 ? Math.round(totalTokens / requestCount) : 0,
143
+ dailyAverage: Math.round(totalTokens / days),
144
+ };
145
+ }
146
+ /**
147
+ * Get global statistics
148
+ */
149
+ getGlobalStats(days = 30) {
150
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
151
+ const recentUsage = this.usageHistory.filter((u) => u.timestamp > cutoff);
152
+ const totalTokens = recentUsage.reduce((sum, u) => sum + u.totalTokens, 0);
153
+ const totalCost = recentUsage.reduce((sum, u) => sum + (u.cost || 0), 0);
154
+ const requestCount = recentUsage.length;
155
+ // Calculate per-user stats
156
+ const userStats = new Map();
157
+ recentUsage.forEach((u) => {
158
+ if (u.userId) {
159
+ const stats = userStats.get(u.userId) || { tokens: 0, cost: 0 };
160
+ stats.tokens += u.totalTokens;
161
+ stats.cost += u.cost || 0;
162
+ userStats.set(u.userId, stats);
163
+ }
164
+ });
165
+ // Get top users
166
+ const topUsers = Array.from(userStats.entries())
167
+ .map(([userId, stats]) => ({
168
+ userId,
169
+ tokens: stats.tokens,
170
+ cost: stats.cost,
171
+ }))
172
+ .sort((a, b) => b.tokens - a.tokens)
173
+ .slice(0, 10);
174
+ return {
175
+ totalTokens,
176
+ totalCost,
177
+ requestCount,
178
+ uniqueUsers: userStats.size,
179
+ topUsers,
180
+ };
181
+ }
182
+ /**
183
+ * Clear old usage data
184
+ */
185
+ cleanup(daysToKeep = 90) {
186
+ const cutoff = Date.now() - daysToKeep * 24 * 60 * 60 * 1000;
187
+ // Clean global history
188
+ this.usageHistory = this.usageHistory.filter((u) => u.timestamp > cutoff);
189
+ // Clean per-user history
190
+ for (const [userId, history] of this.userUsage.entries()) {
191
+ const filtered = history.filter((u) => u.timestamp > cutoff);
192
+ if (filtered.length === 0) {
193
+ this.userUsage.delete(userId);
194
+ }
195
+ else {
196
+ this.userUsage.set(userId, filtered);
197
+ }
198
+ }
199
+ core_2.default.info(`Cleaned up usage data older than ${daysToKeep} days`);
200
+ }
201
+ /**
202
+ * Export usage data
203
+ */
204
+ exportData(userId) {
205
+ if (userId) {
206
+ return this.userUsage.get(userId) || [];
207
+ }
208
+ return [...this.usageHistory];
209
+ }
210
+ /**
211
+ * Update configuration
212
+ */
213
+ updateConfig(config) {
214
+ this.config = { ...this.config, ...config };
215
+ core_2.default.info('Token tracker configuration updated', this.config);
216
+ }
217
+ };
218
+ exports.TokenTracker = TokenTracker;
219
+ exports.TokenTracker = TokenTracker = __decorate([
220
+ (0, core_1.Injectable)(),
221
+ __metadata("design:paramtypes", [Object])
222
+ ], TokenTracker);
@@ -0,0 +1,50 @@
1
+ import { VectorStoreConfig, VectorDocument, VectorSearchRequest, VectorSearchResult, VectorDatabase } from '../ai-enhanced.types';
2
+ /**
3
+ * Vector database service
4
+ *
5
+ * Note: This is a mock implementation. In production, you would use actual vector database clients:
6
+ * - Pinecone: npm install @pinecone-database/pinecone
7
+ * - Weaviate: npm install weaviate-ts-client
8
+ * - Qdrant: npm install @qdrant/js-client-rest
9
+ * - Chroma: npm install chromadb
10
+ */
11
+ export declare class VectorService {
12
+ private config?;
13
+ private documents;
14
+ /**
15
+ * Initialize vector store
16
+ */
17
+ initialize(config: VectorStoreConfig): Promise<void>;
18
+ /**
19
+ * Upsert documents
20
+ */
21
+ upsert(documents: VectorDocument[]): Promise<void>;
22
+ /**
23
+ * Search for similar documents
24
+ */
25
+ search(request: VectorSearchRequest): Promise<VectorSearchResult[]>;
26
+ /**
27
+ * Delete documents
28
+ */
29
+ delete(ids: string[]): Promise<void>;
30
+ /**
31
+ * Get document by ID
32
+ */
33
+ get(id: string): Promise<VectorDocument | null>;
34
+ /**
35
+ * Clear all documents
36
+ */
37
+ clear(): Promise<void>;
38
+ /**
39
+ * Get statistics
40
+ */
41
+ getStats(): Promise<{
42
+ count: number;
43
+ database: VectorDatabase;
44
+ }>;
45
+ /**
46
+ * Calculate cosine similarity between two vectors
47
+ */
48
+ private cosineSimilarity;
49
+ }
50
+ //# sourceMappingURL=vector.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector.service.d.ts","sourceRoot":"","sources":["../../src/vector/vector.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACf,MAAM,sBAAsB,CAAC;AAI9B;;;;;;;;GAQG;AACH,qBACa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,CAAoB;IACnC,OAAO,CAAC,SAAS,CAA0C;IAE3D;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB1D;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBxD;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAoCzE;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1C;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAQrD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAA;KAAE,CAAC;IAWtE;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAiBzB"}
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.VectorService = void 0;
13
+ const core_1 = require("@hazeljs/core");
14
+ const core_2 = __importDefault(require("@hazeljs/core"));
15
+ /**
16
+ * Vector database service
17
+ *
18
+ * Note: This is a mock implementation. In production, you would use actual vector database clients:
19
+ * - Pinecone: npm install @pinecone-database/pinecone
20
+ * - Weaviate: npm install weaviate-ts-client
21
+ * - Qdrant: npm install @qdrant/js-client-rest
22
+ * - Chroma: npm install chromadb
23
+ */
24
+ let VectorService = class VectorService {
25
+ constructor() {
26
+ this.documents = new Map();
27
+ }
28
+ /**
29
+ * Initialize vector store
30
+ */
31
+ async initialize(config) {
32
+ this.config = config;
33
+ core_2.default.info(`Vector store initialized: ${config.database}`);
34
+ // In production, initialize the actual vector database client
35
+ // switch (config.database) {
36
+ // case 'pinecone':
37
+ // this.client = new PineconeClient();
38
+ // await this.client.init({ apiKey: config.apiKey });
39
+ // break;
40
+ // case 'weaviate':
41
+ // this.client = weaviate.client({ scheme: 'https', host: config.endpoint });
42
+ // break;
43
+ // // ... other databases
44
+ // }
45
+ }
46
+ /**
47
+ * Upsert documents
48
+ */
49
+ async upsert(documents) {
50
+ core_2.default.debug(`Upserting ${documents.length} documents`);
51
+ for (const doc of documents) {
52
+ // Generate mock embedding if not provided
53
+ if (!doc.embedding) {
54
+ doc.embedding = Array.from({ length: 1536 }, () => Math.random() * 2 - 1);
55
+ }
56
+ this.documents.set(doc.id, doc);
57
+ }
58
+ // In production:
59
+ // await this.client.upsert({
60
+ // vectors: documents.map(doc => ({
61
+ // id: doc.id,
62
+ // values: doc.embedding,
63
+ // metadata: { content: doc.content, ...doc.metadata },
64
+ // })),
65
+ // });
66
+ core_2.default.info(`Upserted ${documents.length} documents`);
67
+ }
68
+ /**
69
+ * Search for similar documents
70
+ */
71
+ async search(request) {
72
+ core_2.default.debug(`Searching for: ${request.query}`);
73
+ // Mock implementation - generate random query embedding
74
+ const queryEmbedding = Array.from({ length: 1536 }, () => Math.random() * 2 - 1);
75
+ // Calculate cosine similarity for all documents
76
+ const results = [];
77
+ for (const [id, doc] of this.documents) {
78
+ if (doc.embedding) {
79
+ const score = this.cosineSimilarity(queryEmbedding, doc.embedding);
80
+ results.push({
81
+ id,
82
+ content: doc.content,
83
+ score,
84
+ metadata: doc.metadata,
85
+ });
86
+ }
87
+ }
88
+ // Sort by score and return top K
89
+ results.sort((a, b) => b.score - a.score);
90
+ const topK = request.topK || 10;
91
+ // In production:
92
+ // const response = await this.client.query({
93
+ // vector: queryEmbedding,
94
+ // topK: request.topK || 10,
95
+ // filter: request.filter,
96
+ // });
97
+ core_2.default.info(`Found ${results.length} results`);
98
+ return results.slice(0, topK);
99
+ }
100
+ /**
101
+ * Delete documents
102
+ */
103
+ async delete(ids) {
104
+ core_2.default.debug(`Deleting ${ids.length} documents`);
105
+ for (const id of ids) {
106
+ this.documents.delete(id);
107
+ }
108
+ // In production:
109
+ // await this.client.delete({ ids });
110
+ core_2.default.info(`Deleted ${ids.length} documents`);
111
+ }
112
+ /**
113
+ * Get document by ID
114
+ */
115
+ async get(id) {
116
+ return this.documents.get(id) || null;
117
+ // In production:
118
+ // const response = await this.client.fetch({ ids: [id] });
119
+ // return response.vectors[id];
120
+ }
121
+ /**
122
+ * Clear all documents
123
+ */
124
+ async clear() {
125
+ this.documents.clear();
126
+ core_2.default.info('All documents cleared');
127
+ // In production:
128
+ // await this.client.deleteAll();
129
+ }
130
+ /**
131
+ * Get statistics
132
+ */
133
+ async getStats() {
134
+ return {
135
+ count: this.documents.size,
136
+ database: this.config?.database || 'pinecone',
137
+ };
138
+ // In production:
139
+ // const stats = await this.client.describeIndexStats();
140
+ // return { count: stats.totalVectorCount, database: this.config.database };
141
+ }
142
+ /**
143
+ * Calculate cosine similarity between two vectors
144
+ */
145
+ cosineSimilarity(a, b) {
146
+ if (a.length !== b.length) {
147
+ throw new Error('Vectors must have the same length');
148
+ }
149
+ let dotProduct = 0;
150
+ let normA = 0;
151
+ let normB = 0;
152
+ for (let i = 0; i < a.length; i++) {
153
+ dotProduct += a[i] * b[i];
154
+ normA += a[i] * a[i];
155
+ normB += b[i] * b[i];
156
+ }
157
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
158
+ }
159
+ };
160
+ exports.VectorService = VectorService;
161
+ exports.VectorService = VectorService = __decorate([
162
+ (0, core_1.Injectable)()
163
+ ], VectorService);
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@hazeljs/ai",
3
+ "version": "0.2.0-beta.1",
4
+ "description": "AI integration module for HazelJS framework",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc --skipLibCheck",
12
+ "test": "jest --coverage --maxWorkers=1",
13
+ "lint": "eslint \"src/**/*.ts\"",
14
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "dependencies": {
18
+ "@anthropic-ai/sdk": "^0.71.2",
19
+ "@google/generative-ai": "^0.24.1",
20
+ "@hazeljs/cache": "file:../cache",
21
+ "@hazeljs/core": "file:../core",
22
+ "cohere-ai": "^7.14.0",
23
+ "openai": "^6.15.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.17.50",
27
+ "@typescript-eslint/eslint-plugin": "^8.18.2",
28
+ "@typescript-eslint/parser": "^8.18.2",
29
+ "eslint": "^8.56.0",
30
+ "jest": "^29.7.0",
31
+ "ts-jest": "^29.1.2",
32
+ "typescript": "^5.3.3"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/hazel-js/hazeljs.git",
40
+ "directory": "packages/ai"
41
+ },
42
+ "keywords": [
43
+ "hazeljs",
44
+ "ai",
45
+ "openai",
46
+ "anthropic",
47
+ "gemini",
48
+ "llm"
49
+ ],
50
+ "author": "Muhammad Arslan <marslan@hazeljs.com>",
51
+ "license": "MIT"
52
+ }