@hazeljs/cli 0.7.8 → 0.8.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/@template/.eslintrc.js +4 -18
- package/@template/README.md +4 -1
- package/@template-ai-native/HazelJS-AI-Native.postman_collection.json +503 -479
- package/@template-ai-native/README.md +19 -5
- package/@template-ai-native/package.json +1 -1
- package/@template-ai-native/prisma/seed.ts +16 -9
- package/@template-ai-native/src/agent/agent.controller.ts +20 -8
- package/@template-ai-native/src/agent/travel.controller.ts +29 -9
- package/@template-ai-native/src/rag/rag.controller.ts +34 -30
- package/README.md +35 -27
- package/cli-manifest.json +1 -1
- package/dist/commands/add.test.js +16 -3
- package/dist/commands/generate-app.interactive-packages.test.js +2 -1
- package/dist/commands/generate-app.js +6 -5
- package/dist/commands/generate-app.new-command.test.js +3 -1
- package/dist/commands/generate-app.skeleton.test.js +2 -1
- package/dist/commands/generate-auth.test.js +8 -9
- package/dist/commands/generate-crud.test.js +7 -9
- package/dist/commands/generate-dto.test.js +4 -4
- package/dist/commands/generate-module.test.js +10 -10
- package/dist/commands/generate-simple.js +161 -19
- package/dist/commands/generate-simple.test.js +8 -2
- package/dist/commands/info.test.js +1 -3
- package/dist/index.list.test.js +7 -1
- package/dist/index.test.js +7 -1
- package/dist/utils/generator-registry.js +17 -3
- package/dist/utils/generator.js +3 -1
- package/dist/utils/generator.test.js +3 -1
- package/dist/utils/packages-registry.js +3 -3
- package/package.json +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A complete AI-native backend application with HazelJS, featuring:
|
|
4
4
|
|
|
5
5
|
- 🤖 **AI Chat Service** - OpenAI-powered chat endpoints
|
|
6
|
-
- 🧠 **AI Agents** - Agents with tools and capabilities
|
|
6
|
+
- 🧠 **AI Agents** - Agents with tools and capabilities
|
|
7
7
|
- 📚 **RAG System** - Document ingestion and semantic search
|
|
8
8
|
- 🏥 **Health Checks** - Application monitoring
|
|
9
9
|
- 📊 **Inspector** - Development tools and debugging
|
|
@@ -13,29 +13,33 @@ A complete AI-native backend application with HazelJS, featuring:
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
15
15
|
1. **Install dependencies**
|
|
16
|
+
|
|
16
17
|
```bash
|
|
17
18
|
npm install
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
2. **Configure environment**
|
|
22
|
+
|
|
21
23
|
```bash
|
|
22
24
|
cp .env.example .env
|
|
23
25
|
# Add your OpenAI API key to .env
|
|
24
26
|
```
|
|
25
27
|
|
|
26
28
|
3. **Start development server**
|
|
29
|
+
|
|
27
30
|
```bash
|
|
28
31
|
npm run dev
|
|
29
32
|
```
|
|
30
33
|
|
|
31
34
|
4. **Visit the application**
|
|
32
35
|
- App: http://localhost:3000
|
|
33
|
-
- Inspector: http://localhost:3000
|
|
36
|
+
- Inspector: http://localhost:3000/\_\_hazel
|
|
34
37
|
- Health: http://localhost:3000/health
|
|
35
38
|
|
|
36
39
|
## Available Endpoints
|
|
37
40
|
|
|
38
41
|
### AI Chat
|
|
42
|
+
|
|
39
43
|
```bash
|
|
40
44
|
curl -X POST http://localhost:3000/chat \
|
|
41
45
|
-H "Content-Type: application/json" \
|
|
@@ -43,6 +47,7 @@ curl -X POST http://localhost:3000/chat \
|
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
### AI Agent (with tools)
|
|
50
|
+
|
|
46
51
|
```bash
|
|
47
52
|
curl -X POST http://localhost:3000/agent \
|
|
48
53
|
-H "Content-Type: application/json" \
|
|
@@ -50,6 +55,7 @@ curl -X POST http://localhost:3000/agent \
|
|
|
50
55
|
```
|
|
51
56
|
|
|
52
57
|
### RAG Document Ingestion
|
|
58
|
+
|
|
53
59
|
```bash
|
|
54
60
|
curl -X POST http://localhost:3000/rag/ingest \
|
|
55
61
|
-H "Content-Type: application/json" \
|
|
@@ -57,6 +63,7 @@ curl -X POST http://localhost:3000/rag/ingest \
|
|
|
57
63
|
```
|
|
58
64
|
|
|
59
65
|
### RAG Search
|
|
66
|
+
|
|
60
67
|
```bash
|
|
61
68
|
curl -X POST http://localhost:3000/rag/search \
|
|
62
69
|
-H "Content-Type: application/json" \
|
|
@@ -68,17 +75,20 @@ curl -X POST http://localhost:3000/rag/search \
|
|
|
68
75
|
### Using Docker Compose (Recommended)
|
|
69
76
|
|
|
70
77
|
1. **Configure environment**
|
|
78
|
+
|
|
71
79
|
```bash
|
|
72
80
|
cp .env.example .env
|
|
73
81
|
# Add your OpenAI API key
|
|
74
82
|
```
|
|
75
83
|
|
|
76
84
|
2. **Start all services**
|
|
85
|
+
|
|
77
86
|
```bash
|
|
78
87
|
docker-compose up -d
|
|
79
88
|
```
|
|
80
89
|
|
|
81
90
|
3. **View logs**
|
|
91
|
+
|
|
82
92
|
```bash
|
|
83
93
|
docker-compose logs -f hazeljs-ai-app
|
|
84
94
|
```
|
|
@@ -91,6 +101,7 @@ curl -X POST http://localhost:3000/rag/search \
|
|
|
91
101
|
### Using Docker (Standalone)
|
|
92
102
|
|
|
93
103
|
1. **Build the image**
|
|
104
|
+
|
|
94
105
|
```bash
|
|
95
106
|
docker build -t hazeljs-ai-app .
|
|
96
107
|
```
|
|
@@ -105,12 +116,13 @@ curl -X POST http://localhost:3000/rag/search \
|
|
|
105
116
|
The `docker-compose.yml` includes:
|
|
106
117
|
|
|
107
118
|
- **hazeljs-ai-app** - Main application (port 3000)
|
|
108
|
-
- **redis** - Caching and queues (port 6379)
|
|
119
|
+
- **redis** - Caching and queues (port 6379)
|
|
109
120
|
- **postgres** - Database with pgvector extension (port 5432)
|
|
110
121
|
|
|
111
122
|
## API Testing with Postman
|
|
112
123
|
|
|
113
124
|
1. **Import the collection**
|
|
125
|
+
|
|
114
126
|
```bash
|
|
115
127
|
# Import HazelJS-AI-Native.postman_collection.json into Postman
|
|
116
128
|
```
|
|
@@ -178,7 +190,7 @@ npm run db:seed
|
|
|
178
190
|
The template uses the `pgvector/pgvector` Docker image which includes the vector extension. Prisma automatically handles the vector indexes when you run `db:push`. The schema includes:
|
|
179
191
|
|
|
180
192
|
- **Vector embeddings** stored as `Float[]` for RAG search
|
|
181
|
-
- **Full-text search index** on the `content` field
|
|
193
|
+
- **Full-text search index** on the `content` field
|
|
182
194
|
- **JSONB index** on the `metadata` field
|
|
183
195
|
|
|
184
196
|
No manual SQL required - Prisma handles everything!
|
|
@@ -201,7 +213,7 @@ npm run db:generate
|
|
|
201
213
|
The template includes:
|
|
202
214
|
|
|
203
215
|
- **Documents** - RAG document storage with vector embeddings
|
|
204
|
-
- **AgentConversations** - AI agent interaction history
|
|
216
|
+
- **AgentConversations** - AI agent interaction history
|
|
205
217
|
- **ChatHistory** - AI chat session logs
|
|
206
218
|
|
|
207
219
|
### Using Docker with Database
|
|
@@ -254,6 +266,7 @@ npm run format
|
|
|
254
266
|
### Environment Setup
|
|
255
267
|
|
|
256
268
|
1. **Set production variables**
|
|
269
|
+
|
|
257
270
|
```bash
|
|
258
271
|
export NODE_ENV=production
|
|
259
272
|
export OPENAI_API_KEY=your_production_key
|
|
@@ -261,6 +274,7 @@ npm run format
|
|
|
261
274
|
```
|
|
262
275
|
|
|
263
276
|
2. **Deploy with Docker**
|
|
277
|
+
|
|
264
278
|
```bash
|
|
265
279
|
docker-compose -f docker-compose.yml up -d
|
|
266
280
|
```
|
|
@@ -15,7 +15,8 @@ async function main() {
|
|
|
15
15
|
// Sample documents for RAG demonstration
|
|
16
16
|
const sampleDocuments = [
|
|
17
17
|
{
|
|
18
|
-
content:
|
|
18
|
+
content:
|
|
19
|
+
'HazelJS is a TypeScript framework for building AI-native backend applications. It provides built-in support for AI agents, RAG (Retrieval-Augmented Generation), and seamless integration with LLM providers like OpenAI, Anthropic, and Ollama.',
|
|
19
20
|
metadata: {
|
|
20
21
|
source: 'documentation',
|
|
21
22
|
type: 'introduction',
|
|
@@ -24,7 +25,8 @@ async function main() {
|
|
|
24
25
|
},
|
|
25
26
|
},
|
|
26
27
|
{
|
|
27
|
-
content:
|
|
28
|
+
content:
|
|
29
|
+
'TypeScript decorators provide a way to add metadata and modify the behavior of classes, methods, and properties. In HazelJS, decorators like @Controller, @Get, @Post, @Service, and @Agent are used to define the application structure and routing.',
|
|
28
30
|
metadata: {
|
|
29
31
|
source: 'typescript-guide',
|
|
30
32
|
type: 'tutorial',
|
|
@@ -33,7 +35,8 @@ async function main() {
|
|
|
33
35
|
},
|
|
34
36
|
},
|
|
35
37
|
{
|
|
36
|
-
content:
|
|
38
|
+
content:
|
|
39
|
+
'AI agents in HazelJS can use tools to perform actions like API calls, database queries, or external service integrations. The @Agent decorator defines an agent, and @Tool decorator defines its capabilities.',
|
|
37
40
|
metadata: {
|
|
38
41
|
source: 'agent-guide',
|
|
39
42
|
type: 'tutorial',
|
|
@@ -42,7 +45,8 @@ async function main() {
|
|
|
42
45
|
},
|
|
43
46
|
},
|
|
44
47
|
{
|
|
45
|
-
content:
|
|
48
|
+
content:
|
|
49
|
+
'RAG (Retrieval-Augmented Generation) combines document retrieval with LLM generation to provide more accurate and context-aware responses. HazelJS provides built-in RAG services with vector similarity search.',
|
|
46
50
|
metadata: {
|
|
47
51
|
source: 'rag-guide',
|
|
48
52
|
type: 'tutorial',
|
|
@@ -51,7 +55,8 @@ async function main() {
|
|
|
51
55
|
},
|
|
52
56
|
},
|
|
53
57
|
{
|
|
54
|
-
content:
|
|
58
|
+
content:
|
|
59
|
+
'The HazelJS Inspector is a development dashboard available at /__hazel that provides real-time insights into your application, including module dependencies, request metrics, and AI agent performance.',
|
|
55
60
|
metadata: {
|
|
56
61
|
source: 'development-guide',
|
|
57
62
|
type: 'tutorial',
|
|
@@ -66,7 +71,7 @@ async function main() {
|
|
|
66
71
|
try {
|
|
67
72
|
// Generate embedding for the document
|
|
68
73
|
const embedding = await embeddings.embed(doc.content);
|
|
69
|
-
|
|
74
|
+
|
|
70
75
|
// Use raw SQL to insert document with vector embedding
|
|
71
76
|
await prisma.$executeRaw`
|
|
72
77
|
INSERT INTO documents (id, content, metadata, embedding, "createdAt", "updatedAt")
|
|
@@ -79,7 +84,7 @@ async function main() {
|
|
|
79
84
|
NOW()
|
|
80
85
|
)
|
|
81
86
|
`;
|
|
82
|
-
|
|
87
|
+
|
|
83
88
|
console.log(`✅ Created document: ${doc.metadata.source}`);
|
|
84
89
|
} catch (error) {
|
|
85
90
|
console.error(`❌ Failed to create document: ${doc.metadata.source}`, error);
|
|
@@ -128,14 +133,16 @@ async function main() {
|
|
|
128
133
|
{
|
|
129
134
|
sessionId: 'chat-session-1',
|
|
130
135
|
userMessage: 'What is HazelJS?',
|
|
131
|
-
aiResponse:
|
|
136
|
+
aiResponse:
|
|
137
|
+
'HazelJS is a TypeScript framework for building AI-native backend applications with built-in support for AI agents, RAG, and LLM integration.',
|
|
132
138
|
model: 'gpt-4',
|
|
133
139
|
tokensUsed: 156,
|
|
134
140
|
},
|
|
135
141
|
{
|
|
136
142
|
sessionId: 'chat-session-1',
|
|
137
143
|
userMessage: 'How do I create an AI agent?',
|
|
138
|
-
aiResponse:
|
|
144
|
+
aiResponse:
|
|
145
|
+
'You can create an AI agent in HazelJS using the @Agent decorator and defining tools with @Tool decorator. Here\'s an example: @Agent({name: "MyAgent"}) class MyAgent { @Tool({description: "My tool"}) async myTool() { return "result"; } }',
|
|
139
146
|
model: 'gpt-4',
|
|
140
147
|
tokensUsed: 234,
|
|
141
148
|
},
|
|
@@ -91,16 +91,26 @@ export class WeatherAgent {
|
|
|
91
91
|
let celsius: number;
|
|
92
92
|
|
|
93
93
|
switch (fromUnit.toLowerCase()) {
|
|
94
|
-
case 'fahrenheit':
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
case 'fahrenheit':
|
|
95
|
+
celsius = (value - 32) * (5 / 9);
|
|
96
|
+
break;
|
|
97
|
+
case 'kelvin':
|
|
98
|
+
celsius = value - 273.15;
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
celsius = value;
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
let result: number;
|
|
100
105
|
switch (toUnit.toLowerCase()) {
|
|
101
|
-
case 'fahrenheit':
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
case 'fahrenheit':
|
|
107
|
+
result = celsius * (9 / 5) + 32;
|
|
108
|
+
break;
|
|
109
|
+
case 'kelvin':
|
|
110
|
+
result = celsius + 273.15;
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
result = celsius;
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
return {
|
|
@@ -134,7 +144,7 @@ export class WeatherAgent {
|
|
|
134
144
|
export class AgentController {
|
|
135
145
|
constructor(
|
|
136
146
|
private readonly agent: WeatherAgent,
|
|
137
|
-
private readonly agentService: AgentService
|
|
147
|
+
private readonly agentService: AgentService
|
|
138
148
|
) {}
|
|
139
149
|
|
|
140
150
|
@Post()
|
|
@@ -160,7 +170,9 @@ export class AgentController {
|
|
|
160
170
|
if (chunk.type === 'token') {
|
|
161
171
|
res.write(`data: ${JSON.stringify({ type: 'token', content: chunk.content })}\n\n`);
|
|
162
172
|
} else if (chunk.type === 'step') {
|
|
163
|
-
res.write(
|
|
173
|
+
res.write(
|
|
174
|
+
`data: ${JSON.stringify({ type: 'step', state: chunk.step.state, tool: chunk.step.action?.toolName ?? null })}\n\n`
|
|
175
|
+
);
|
|
164
176
|
} else if (chunk.type === 'done') {
|
|
165
177
|
res.write(`data: ${JSON.stringify({ type: 'done', response: chunk.result.response })}\n\n`);
|
|
166
178
|
}
|
|
@@ -7,7 +7,8 @@ import { Agent, Tool, Delegate, AgentService } from '@hazeljs/agent';
|
|
|
7
7
|
@Agent({
|
|
8
8
|
name: 'FactsAgent',
|
|
9
9
|
description: 'Provides fun facts, cultural highlights, and travel tips about cities',
|
|
10
|
-
systemPrompt:
|
|
10
|
+
systemPrompt:
|
|
11
|
+
'You are a knowledgeable travel guide. Use your tools to provide interesting facts and tips about cities.',
|
|
11
12
|
})
|
|
12
13
|
@Service()
|
|
13
14
|
export class FactsAgent {
|
|
@@ -25,10 +26,26 @@ export class FactsAgent {
|
|
|
25
26
|
async getCityFacts(input: { city: string }) {
|
|
26
27
|
// In real app, call a travel/facts API or use a knowledge base
|
|
27
28
|
const facts: Record<string, { fact: string; tip: string; bestTime: string }> = {
|
|
28
|
-
paris:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
paris: {
|
|
30
|
+
fact: 'Paris has more than 470 parks and gardens.',
|
|
31
|
+
tip: 'Buy a Paris Museum Pass to skip long queues.',
|
|
32
|
+
bestTime: 'April–June or September–November',
|
|
33
|
+
},
|
|
34
|
+
tokyo: {
|
|
35
|
+
fact: "Tokyo has the world's busiest pedestrian crossing at Shibuya.",
|
|
36
|
+
tip: 'Get a Suica card for seamless transit across the city.',
|
|
37
|
+
bestTime: 'March–May (cherry blossom) or October–November',
|
|
38
|
+
},
|
|
39
|
+
london: {
|
|
40
|
+
fact: 'London has over 170 museums, most of which are free.',
|
|
41
|
+
tip: 'The Oyster card gives the cheapest fares on public transport.',
|
|
42
|
+
bestTime: 'May–September for mild weather',
|
|
43
|
+
},
|
|
44
|
+
newyork: {
|
|
45
|
+
fact: 'New York City has 468 subway stations — the most in the world.',
|
|
46
|
+
tip: 'Walk the High Line for great views and free art installations.',
|
|
47
|
+
bestTime: 'April–June or September–November',
|
|
48
|
+
},
|
|
32
49
|
};
|
|
33
50
|
|
|
34
51
|
const key = input.city.toLowerCase().replace(/\s+/g, '');
|
|
@@ -49,7 +66,8 @@ export class FactsAgent {
|
|
|
49
66
|
@Agent({
|
|
50
67
|
name: 'TravelAgent',
|
|
51
68
|
description: 'Travel planning assistant that checks weather and provides itinerary advice',
|
|
52
|
-
systemPrompt:
|
|
69
|
+
systemPrompt:
|
|
70
|
+
'You are a travel planner. Use your tools to check weather and forecasts for cities, then provide helpful travel advice based on the conditions.',
|
|
53
71
|
})
|
|
54
72
|
@Service()
|
|
55
73
|
export class TravelAgent {
|
|
@@ -59,7 +77,8 @@ export class TravelAgent {
|
|
|
59
77
|
// The LLM sees it as a regular tool — agent-to-agent is completely transparent.
|
|
60
78
|
@Delegate({
|
|
61
79
|
agent: 'WeatherAgent',
|
|
62
|
-
description:
|
|
80
|
+
description:
|
|
81
|
+
'Check weather conditions and forecasts for a city to inform travel recommendations',
|
|
63
82
|
inputField: 'input',
|
|
64
83
|
})
|
|
65
84
|
async checkWeather(input: string): Promise<string> {
|
|
@@ -87,7 +106,7 @@ export class TravelAgent {
|
|
|
87
106
|
export class TravelController {
|
|
88
107
|
constructor(
|
|
89
108
|
private readonly travelAgent: TravelAgent,
|
|
90
|
-
private readonly agentService: AgentService
|
|
109
|
+
private readonly agentService: AgentService
|
|
91
110
|
) {}
|
|
92
111
|
|
|
93
112
|
// Feature: Agent Delegation — TravelAgent delegates to WeatherAgent via @Delegate
|
|
@@ -107,7 +126,8 @@ export class TravelController {
|
|
|
107
126
|
const supervisor = runtime.createSupervisor({
|
|
108
127
|
name: 'travel-supervisor',
|
|
109
128
|
workers: ['WeatherAgent', 'FactsAgent'],
|
|
110
|
-
systemPrompt:
|
|
129
|
+
systemPrompt:
|
|
130
|
+
'You are a travel planning supervisor. Route requests to WeatherAgent for weather/forecast questions and to FactsAgent for city facts, tips, and general travel advice. Combine results when both are relevant.',
|
|
111
131
|
maxRounds: 6,
|
|
112
132
|
});
|
|
113
133
|
|
|
@@ -13,7 +13,7 @@ export class RAGService {
|
|
|
13
13
|
apiKey: process.env.OPENAI_API_KEY!,
|
|
14
14
|
model: 'text-embedding-3-small',
|
|
15
15
|
});
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
// Initialize Prisma for PostgreSQL storage
|
|
18
18
|
this.prisma = new PrismaClient();
|
|
19
19
|
}
|
|
@@ -23,17 +23,17 @@ export class RAGService {
|
|
|
23
23
|
const count = await this.prisma.document.count();
|
|
24
24
|
console.log(`RAG Service initialized - PostgreSQL vector store ready with ${count} documents`);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
async onModuleDestroy() {
|
|
28
28
|
await this.prisma.$disconnect();
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async ingestDocument(content: string, metadata?: any) {
|
|
32
32
|
console.log(`Ingesting document, content length: ${content.length}`);
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
// Generate embedding for the document
|
|
35
35
|
const embedding = await this.embeddings.embed(content);
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
// Store in PostgreSQL
|
|
38
38
|
const document = await this.prisma.document.create({
|
|
39
39
|
data: {
|
|
@@ -46,32 +46,36 @@ export class RAGService {
|
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
const totalDocuments = await this.prisma.document.count();
|
|
51
|
-
console.log(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
console.log(
|
|
52
|
+
`Document ingested successfully. ID: ${document.id}, Total documents: ${totalDocuments}`
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
id: document.id,
|
|
55
57
|
message: 'Document ingested successfully and stored in PostgreSQL',
|
|
56
|
-
totalDocuments
|
|
58
|
+
totalDocuments,
|
|
57
59
|
};
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
async search(query: string, topK = 5) {
|
|
61
63
|
const totalDocuments = await this.prisma.document.count();
|
|
62
64
|
console.log(`RAG search requested for: "${query}". Total documents: ${totalDocuments}`);
|
|
63
|
-
|
|
65
|
+
|
|
64
66
|
// Generate embedding for the query
|
|
65
67
|
const queryVector = await this.embeddings.embed(query);
|
|
66
|
-
|
|
68
|
+
|
|
67
69
|
// Perform vector similarity search using raw SQL for cosine similarity
|
|
68
70
|
// Note: We don't select the embedding column to avoid deserialization issues
|
|
69
|
-
const results = await this.prisma.$queryRaw<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const results = await this.prisma.$queryRaw<
|
|
72
|
+
Array<{
|
|
73
|
+
id: string;
|
|
74
|
+
content: string;
|
|
75
|
+
metadata: any;
|
|
76
|
+
similarity: number;
|
|
77
|
+
}>
|
|
78
|
+
>`
|
|
75
79
|
SELECT
|
|
76
80
|
id,
|
|
77
81
|
content,
|
|
@@ -81,22 +85,22 @@ export class RAGService {
|
|
|
81
85
|
ORDER BY embedding <=> ${queryVector}::vector
|
|
82
86
|
LIMIT ${topK}
|
|
83
87
|
`;
|
|
84
|
-
|
|
88
|
+
|
|
85
89
|
console.log(`RAG search for "${query}" returned ${results.length} results`);
|
|
86
|
-
|
|
87
|
-
return results.map(result => ({
|
|
90
|
+
|
|
91
|
+
return results.map((result) => ({
|
|
88
92
|
id: result.id,
|
|
89
93
|
content: result.content,
|
|
90
94
|
score: result.similarity,
|
|
91
95
|
metadata: result.metadata,
|
|
92
96
|
}));
|
|
93
97
|
}
|
|
94
|
-
|
|
98
|
+
|
|
95
99
|
async getDocumentCount() {
|
|
96
100
|
const totalDocuments = await this.prisma.document.count();
|
|
97
101
|
return { totalDocuments };
|
|
98
102
|
}
|
|
99
|
-
|
|
103
|
+
|
|
100
104
|
async getAllDocuments() {
|
|
101
105
|
const documents = await this.prisma.document.findMany({
|
|
102
106
|
select: {
|
|
@@ -132,29 +136,29 @@ export class RAGController {
|
|
|
132
136
|
@Get('documents')
|
|
133
137
|
async getDocuments() {
|
|
134
138
|
const stats = await this.ragService.getDocumentCount();
|
|
135
|
-
return {
|
|
139
|
+
return {
|
|
136
140
|
message: 'RAG service is ready - PostgreSQL vector store with persistent storage',
|
|
137
141
|
...stats,
|
|
138
142
|
endpoints: {
|
|
139
143
|
ingest: 'POST /rag/ingest - Add documents to PostgreSQL',
|
|
140
144
|
search: 'POST /rag/search - Search documents with vector similarity',
|
|
141
145
|
stats: 'GET /rag/stats - Get document count',
|
|
142
|
-
list: 'GET /rag/list - List all documents'
|
|
143
|
-
}
|
|
146
|
+
list: 'GET /rag/list - List all documents',
|
|
147
|
+
},
|
|
144
148
|
};
|
|
145
149
|
}
|
|
146
|
-
|
|
150
|
+
|
|
147
151
|
@Get('stats')
|
|
148
152
|
async getStats() {
|
|
149
153
|
return this.ragService.getDocumentCount();
|
|
150
154
|
}
|
|
151
|
-
|
|
155
|
+
|
|
152
156
|
@Get('list')
|
|
153
157
|
async listDocuments() {
|
|
154
158
|
const documents = await this.ragService.getAllDocuments();
|
|
155
|
-
return {
|
|
159
|
+
return {
|
|
156
160
|
documents,
|
|
157
|
-
total: documents.length
|
|
161
|
+
total: documents.length,
|
|
158
162
|
};
|
|
159
163
|
}
|
|
160
164
|
}
|
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ npm install --save-dev @hazeljs/cli
|
|
|
37
37
|
### Create a New Application
|
|
38
38
|
|
|
39
39
|
**AI-Native Application (Recommended for AI Projects):**
|
|
40
|
+
|
|
40
41
|
```bash
|
|
41
42
|
hazel g app my-ai-app --template=ai-native
|
|
42
43
|
cd my-ai-app && npm install && cp .env.example .env && docker-compose up -d && npm run dev
|
|
@@ -45,17 +46,20 @@ cd my-ai-app && npm install && cp .env.example .env && docker-compose up -d && n
|
|
|
45
46
|
Creates a complete AI-powered application with agents, RAG (PostgreSQL + pgvector), Redis, and Docker.
|
|
46
47
|
|
|
47
48
|
**Skeleton app (quick start):**
|
|
49
|
+
|
|
48
50
|
```bash
|
|
49
51
|
hazel g app my-app
|
|
50
52
|
cd my-app && npm install && npm run dev
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
**Full setup with interactive package selection:**
|
|
56
|
+
|
|
54
57
|
```bash
|
|
55
58
|
hazel new my-app -i
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
**Options:**
|
|
62
|
+
|
|
59
63
|
- `-d, --dest <path>` - Destination path (default: current directory)
|
|
60
64
|
- `-i, --interactive` - Interactive setup with package selection
|
|
61
65
|
- `--template <template>` - Template to use (`ai-native` or `default`)
|
|
@@ -79,6 +83,7 @@ hazel add [package] [--setup] [--dev]
|
|
|
79
83
|
Install a HazelJS package and show usage hints. Use `--setup` to also generate a minimal starter file.
|
|
80
84
|
|
|
81
85
|
**Examples:**
|
|
86
|
+
|
|
82
87
|
```bash
|
|
83
88
|
hazel add # Interactive package selection
|
|
84
89
|
hazel add ai # Install @hazeljs/ai
|
|
@@ -95,46 +100,48 @@ hazel g <type> <name> [--path <path>] [--dry-run] [--json]
|
|
|
95
100
|
```
|
|
96
101
|
|
|
97
102
|
**Discover generators:**
|
|
103
|
+
|
|
98
104
|
```bash
|
|
99
105
|
hazel g --list # Human-readable list
|
|
100
106
|
hazel g --list --list-json # JSON output
|
|
101
107
|
```
|
|
102
108
|
|
|
103
109
|
**Common options** (work the same for every generator):
|
|
110
|
+
|
|
104
111
|
- `-p, --path <path>` - Where to generate (default: `src`)
|
|
105
112
|
- `--dry-run` - Preview files without writing them
|
|
106
113
|
- `--json` - Output result as JSON (`{ ok, created, nextSteps }`)
|
|
107
114
|
|
|
108
115
|
#### Multi-File Generators
|
|
109
116
|
|
|
110
|
-
| Generator
|
|
111
|
-
|
|
112
|
-
| `crud <name>`
|
|
113
|
-
| `module <name>` | `m`
|
|
114
|
-
| `dto <name>`
|
|
115
|
-
| `auth`
|
|
117
|
+
| Generator | Alias | Description | Creates |
|
|
118
|
+
| --------------- | ----- | ---------------------- | --------------------------------------- |
|
|
119
|
+
| `crud <name>` | — | Complete CRUD resource | controller + service + module + DTOs |
|
|
120
|
+
| `module <name>` | `m` | Feature module | module + controller + service + DTOs |
|
|
121
|
+
| `dto <name>` | `d` | Create & update DTOs | two DTO files |
|
|
122
|
+
| `auth` | — | Auth module | JWT guard + service + controller + DTOs |
|
|
116
123
|
|
|
117
124
|
#### Single-File Generators
|
|
118
125
|
|
|
119
|
-
| Generator
|
|
120
|
-
|
|
121
|
-
| `controller <name>`
|
|
122
|
-
| `service <name>`
|
|
123
|
-
| `guard <name>`
|
|
124
|
-
| `interceptor <name>` | `i`
|
|
125
|
-
| `middleware <name>`
|
|
126
|
-
| `pipe <name>`
|
|
127
|
-
| `filter <name>`
|
|
128
|
-
| `repository <name>`
|
|
129
|
-
| `gateway <name>`
|
|
130
|
-
| `ai-service <name>`
|
|
131
|
-
| `agent <name>`
|
|
132
|
-
| `cache <name>`
|
|
133
|
-
| `cron <name>`
|
|
134
|
-
| `rag <name>`
|
|
135
|
-
| `discovery <name>`
|
|
136
|
-
| `config`
|
|
137
|
-
| `serverless <name>`
|
|
126
|
+
| Generator | Alias | Description |
|
|
127
|
+
| -------------------- | ------ | ------------------------------------------ |
|
|
128
|
+
| `controller <name>` | `c` | REST controller with CRUD methods |
|
|
129
|
+
| `service <name>` | `s` | Injectable service class |
|
|
130
|
+
| `guard <name>` | `gu` | Route guard (e.g. auth) |
|
|
131
|
+
| `interceptor <name>` | `i` | Request/response interceptor |
|
|
132
|
+
| `middleware <name>` | `mw` | Express-style middleware |
|
|
133
|
+
| `pipe <name>` | — | Validation/transform pipe |
|
|
134
|
+
| `filter <name>` | `f` | Exception filter |
|
|
135
|
+
| `repository <name>` | `repo` | Prisma repository |
|
|
136
|
+
| `gateway <name>` | `ws` | WebSocket gateway |
|
|
137
|
+
| `ai-service <name>` | `ai` | AI service with decorators |
|
|
138
|
+
| `agent <name>` | — | AI agent with @Agent and @Tool |
|
|
139
|
+
| `cache <name>` | — | Cache service with decorators |
|
|
140
|
+
| `cron <name>` | `job` | Cron/scheduled job service |
|
|
141
|
+
| `rag <name>` | — | RAG service |
|
|
142
|
+
| `discovery <name>` | — | Service discovery setup |
|
|
143
|
+
| `config` | — | Config module setup |
|
|
144
|
+
| `serverless <name>` | `sls` | Serverless handler (Lambda/Cloud Function) |
|
|
138
145
|
|
|
139
146
|
**Serverless** also accepts `--platform <lambda|cloud-function>` (default: `lambda`).
|
|
140
147
|
|
|
@@ -302,8 +309,9 @@ hazel g service users --json
|
|
|
302
309
|
```
|
|
303
310
|
|
|
304
311
|
The manifest is automatically generated during build and always reflects the current package version. It includes:
|
|
312
|
+
|
|
305
313
|
- Complete command schemas with options and arguments
|
|
306
|
-
- All available generators with their capabilities
|
|
314
|
+
- All available generators with their capabilities
|
|
307
315
|
- Package registry for `hazel add` commands
|
|
308
316
|
- JSON schema validation for agent tool-use
|
|
309
317
|
|
|
@@ -316,4 +324,4 @@ Apache-2.0 © [HazelJS](https://hazeljs.ai)
|
|
|
316
324
|
- [Documentation](https://hazeljs.ai/docs/packages/cli)
|
|
317
325
|
- [GitHub](https://github.com/hazel-js/hazeljs)
|
|
318
326
|
- [Issues](https://github.com/hazel-js/hazeljs/issues)
|
|
319
|
-
- [Discord](https://discord.
|
|
327
|
+
- [Discord](https://discord.gg/PxNBPzvQk7)
|
package/cli-manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Machine-readable manifest of all CLI commands and options for LLM agent tool-use",
|
|
5
5
|
"cli": {
|
|
6
6
|
"name": "hazel",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.8.0",
|
|
8
8
|
"description": "CLI for generating HazelJS components and applications"
|
|
9
9
|
},
|
|
10
10
|
"commands": [
|