movie-agent 1.0.0 → 1.1.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 (48) hide show
  1. package/README.md +319 -39
  2. package/bin/movie-agent +33 -8
  3. package/dist/agent.d.ts +31 -4
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +109 -16
  6. package/dist/agent.js.map +1 -1
  7. package/dist/cache.d.ts +40 -5
  8. package/dist/cache.d.ts.map +1 -1
  9. package/dist/cache.js +95 -11
  10. package/dist/cache.js.map +1 -1
  11. package/dist/factory.d.ts.map +1 -1
  12. package/dist/factory.js +23 -1
  13. package/dist/factory.js.map +1 -1
  14. package/dist/format.d.ts +14 -1
  15. package/dist/format.d.ts.map +1 -1
  16. package/dist/format.js +22 -1
  17. package/dist/format.js.map +1 -1
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/llm.d.ts +33 -0
  23. package/dist/llm.d.ts.map +1 -0
  24. package/dist/llm.js +221 -0
  25. package/dist/llm.js.map +1 -0
  26. package/dist/providers.d.ts +9 -1
  27. package/dist/providers.d.ts.map +1 -1
  28. package/dist/providers.js +27 -0
  29. package/dist/providers.js.map +1 -1
  30. package/dist/rateLimiter.d.ts +59 -0
  31. package/dist/rateLimiter.d.ts.map +1 -0
  32. package/dist/rateLimiter.js +99 -0
  33. package/dist/rateLimiter.js.map +1 -0
  34. package/dist/sanitize.d.ts +24 -0
  35. package/dist/sanitize.d.ts.map +1 -0
  36. package/dist/sanitize.js +137 -0
  37. package/dist/sanitize.js.map +1 -0
  38. package/dist/tmdbApi.d.ts +37 -1
  39. package/dist/tmdbApi.d.ts.map +1 -1
  40. package/dist/tmdbApi.js +70 -22
  41. package/dist/tmdbApi.js.map +1 -1
  42. package/dist/types.d.ts +2 -0
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/validate.d.ts +5 -0
  45. package/dist/validate.d.ts.map +1 -1
  46. package/dist/validate.js +38 -1
  47. package/dist/validate.js.map +1 -1
  48. package/package.json +9 -3
package/README.md CHANGED
@@ -5,15 +5,21 @@ An intelligent movie recommendation system that helps users discover movies base
5
5
  ## Features
6
6
 
7
7
  - šŸŽ¬ Personalized movie recommendations based on mood, genre, and preferences
8
+ - šŸ¤– AI-powered output formatting with LangChain and Google Gemini
9
+ - 🌊 Streaming and non-streaming output modes
8
10
  - šŸ“ŗ Real-time streaming availability for Canadian platforms
9
11
  - ⚔ Fast responses using TMDb API
10
12
  - šŸŽÆ Smart filtering by runtime, release year, and streaming platforms
11
13
  - šŸ“¦ Easy integration into web applications and APIs
14
+ - šŸ”’ Multi-tenant cache isolation for secure deployments (see [Cache Isolation Guide](docs/CACHE_ISOLATION.md))
12
15
 
13
16
  ## Prerequisites
14
17
 
15
18
  - Node.js (v18 or higher)
16
19
  - TMDb API key ([Get one here](https://www.themoviedb.org/settings/api))
20
+ - LLM API key for AI formatting (optional):
21
+ - Google Gemini API key - [Get one here](https://aistudio.google.com/app/apikey)
22
+ - **OR** Azure OpenAI credentials - [Learn more](https://azure.microsoft.com/en-us/products/ai-services/openai-service)
17
23
 
18
24
  ## Installation
19
25
 
@@ -23,55 +29,186 @@ npm install movie-agent
23
29
 
24
30
  ## Quick Start
25
31
 
26
- ### Option 1: Using MovieAgentFactory.create() with explicit config (Recommended)
32
+ ### Basic Usage - Get Structured Data
33
+
34
+ ```typescript
35
+ import { MovieAgent } from 'movie-agent';
36
+
37
+ // Create agent
38
+ const agent = new MovieAgent();
39
+
40
+ // Get structured recommendations
41
+ const response = await agent.getRecommendations({
42
+ mood: 'excited',
43
+ platforms: ['Netflix', 'Prime Video'],
44
+ });
45
+
46
+ console.log(response.recommendations);
47
+ ```
48
+
49
+ ### AI-Formatted Output - Invoke Mode (Waits for complete response)
50
+
51
+ ```typescript
52
+ import { MovieAgent } from 'movie-agent';
53
+
54
+ const agent = new MovieAgent();
55
+
56
+ // Get AI-formatted markdown output
57
+ const output = await agent.invoke({
58
+ mood: 'happy',
59
+ platforms: ['Netflix'],
60
+ });
61
+
62
+ console.log(output); // Formatted markdown string
63
+ ```
64
+
65
+ ### AI-Formatted Output - Stream Mode (Real-time streaming)
66
+
67
+ ```typescript
68
+ import { MovieAgent } from 'movie-agent';
69
+
70
+ const agent = new MovieAgent();
71
+
72
+ // Stream AI-formatted output in real-time
73
+ await agent.stream({
74
+ mood: 'excited',
75
+ platforms: ['Netflix'],
76
+ }, (chunk) => {
77
+ process.stdout.write(chunk); // or update your UI
78
+ });
79
+ ```
80
+
81
+ ### Using with MovieAgentFactory
27
82
 
28
83
  ```typescript
29
84
  import { MovieAgentFactory } from 'movie-agent';
30
85
 
31
- // Create agent with explicit configuration
86
+ // Create agent with explicit configuration (Gemini)
32
87
  const agent = MovieAgentFactory.create({
33
88
  tmdbApiKey: process.env.TMDB_API_KEY!,
34
89
  tmdbRegion: 'CA',
35
- debug: true, // Enable debug logging
90
+ llmProvider: 'gemini',
91
+ geminiApiKey: process.env.GEMINI_API_KEY,
92
+ debug: true,
36
93
  });
37
94
 
38
- // Get recommendations
39
- const recommendations = await agent.getRecommendations({
40
- mood: 'excited',
41
- genre: 'Action',
42
- platforms: ['Netflix', 'Prime Video'],
95
+ // Or use Azure OpenAI
96
+ const agentWithAzure = MovieAgentFactory.create({
97
+ tmdbApiKey: process.env.TMDB_API_KEY!,
98
+ tmdbRegion: 'CA',
99
+ llmProvider: 'azure',
100
+ azureOpenAiApiKey: process.env.AZURE_OPENAI_API_KEY,
101
+ azureOpenAiEndpoint: process.env.AZURE_OPENAI_ENDPOINT,
102
+ azureOpenAiDeployment: process.env.AZURE_OPENAI_DEPLOYMENT,
103
+ debug: true,
43
104
  });
44
105
 
45
- console.log(recommendations);
106
+ // All three methods available: getRecommendations, invoke, stream
107
+ const structured = await agent.getRecommendations({ mood: 'happy' });
108
+ const formatted = await agent.invoke({ mood: 'happy' });
109
+ await agent.stream({ mood: 'happy' }, (chunk) => console.log(chunk));
46
110
  ```
47
111
 
48
- ### Option 2: Using MovieAgentFactory.fromEnv() convenience method
112
+ ## API Reference
113
+
114
+ ### MovieAgent Methods
115
+
116
+ #### `getRecommendations(input: UserInput): Promise<AgentResponse | ErrorResponse>`
117
+ Returns structured movie recommendations with metadata.
49
118
 
50
119
  ```typescript
51
- import { MovieAgentFactory } from 'movie-agent';
52
- import dotenv from 'dotenv';
120
+ const response = await agent.getRecommendations({
121
+ mood: 'happy',
122
+ platforms: ['Netflix']
123
+ });
124
+ // Returns: { recommendations: [...], metadata: {...} }
125
+ ```
53
126
 
54
- // Load your .env file BEFORE creating the agent
55
- dotenv.config();
127
+ #### `invoke(input: UserInput): Promise<string | ErrorResponse>`
128
+ Returns AI-formatted markdown output (non-streaming). Waits for complete response before returning.
56
129
 
57
- // Create agent from environment variables
58
- const agent = MovieAgentFactory.fromEnv(true); // true = enable debug logging
130
+ ```typescript
131
+ const output = await agent.invoke({
132
+ mood: 'excited',
133
+ platforms: ['Netflix']
134
+ });
135
+ // Returns: Formatted markdown string
136
+ ```
59
137
 
60
- // Get recommendations
61
- const recommendations = await agent.getRecommendations({
138
+ #### `stream(input: UserInput, onChunk: (chunk: string) => void): Promise<void | ErrorResponse>`
139
+ Streams AI-formatted output in real-time. Best for interactive UIs.
140
+
141
+ ```typescript
142
+ await agent.stream({
62
143
  mood: 'relaxed',
63
- genre: ['Comedy', 'Romance'],
64
- runtime: { max: 120 },
144
+ platforms: ['Netflix']
145
+ }, (chunk) => {
146
+ process.stdout.write(chunk);
65
147
  });
66
148
  ```
67
149
 
150
+ ## Input Parameters
151
+
152
+ ```typescript
153
+ interface UserInput {
154
+ mood?: string; // e.g., 'excited', 'relaxed', 'thoughtful', 'happy', 'scared'
155
+ genre?: string | string[]; // e.g., 'Action' or ['Action', 'Thriller']
156
+ platforms?: string[]; // e.g., ['Netflix', 'Prime Video', 'Disney+']
157
+ runtime?: {
158
+ min?: number; // Minimum runtime in minutes
159
+ max?: number; // Maximum runtime in minutes
160
+ };
161
+ releaseYear?: number | { // Single year or range
162
+ from?: number;
163
+ to?: number;
164
+ };
165
+ }
166
+ ```
167
+
168
+ ## Output Comparison
169
+
170
+ ### `getRecommendations()` - Structured Data
171
+ ```json
172
+ {
173
+ "recommendations": [
174
+ {
175
+ "tmdbId": 123,
176
+ "title": "Movie Title",
177
+ "releaseYear": "2024",
178
+ "runtime": 120,
179
+ "genres": ["Action", "Adventure"],
180
+ "description": "...",
181
+ "streamingPlatforms": [...],
182
+ "matchReason": "...",
183
+ "posterUrl": "https://image.tmdb.org/t/p/w500/abc123.jpg"
184
+ }
185
+ ],
186
+ "metadata": {...}
187
+ }
188
+ ```
189
+
190
+ ### `invoke()` / `stream()` - AI-Formatted Markdown
191
+ ```markdown
192
+ Hey there! šŸ‘‹ Looking for some action-packed thrills? Here are your recommendations:
193
+
194
+ ### **Movie Title (2024)** - 120 minutes
195
+ *Genres: Action, Adventure*
196
+ A compelling description...
197
+ šŸ“ŗ Available on: Netflix
198
+ ✨ Why: Perfect for your excited mood with thrilling action!
199
+ ```
200
+
68
201
  ## API Examples
69
202
 
70
203
  ```typescript
71
204
  // Simple mood-based search
72
- await agent.getRecommendations({
73
- mood: 'happy'
74
- });
205
+ await agent.getRecommendations({ mood: 'happy' });
206
+
207
+ // AI-formatted output
208
+ await agent.invoke({ mood: 'happy' });
209
+
210
+ // Streaming output
211
+ await agent.stream({ mood: 'happy' }, (chunk) => console.log(chunk));
75
212
 
76
213
  // Genre-specific with platform filter
77
214
  await agent.getRecommendations({
@@ -97,17 +234,14 @@ await agent.getRecommendations({
97
234
 
98
235
  ## Integration Examples
99
236
 
100
- ### Next.js API Route
237
+ ### Next.js API Route (Structured Data)
101
238
 
102
239
  ```typescript
103
240
  // pages/api/recommendations.ts
104
- import { MovieAgentFactory } from 'movie-agent';
241
+ import { MovieAgent } from 'movie-agent';
105
242
  import type { NextApiRequest, NextApiResponse } from 'next';
106
243
 
107
- const agent = MovieAgentFactory.create({
108
- tmdbApiKey: process.env.TMDB_API_KEY!,
109
- tmdbRegion: 'CA',
110
- });
244
+ const agent = new MovieAgent();
111
245
 
112
246
  export default async function handler(req: NextApiRequest, res: NextApiResponse) {
113
247
  if (req.method !== 'POST') {
@@ -125,23 +259,50 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
125
259
  }
126
260
  ```
127
261
 
128
- ### Express Server
262
+ ### Next.js API Route (AI-Formatted Streaming)
129
263
 
130
264
  ```typescript
131
- import express from 'express';
132
- import { MovieAgentFactory } from 'movie-agent';
133
- import dotenv from 'dotenv';
265
+ // pages/api/recommendations-stream.ts
266
+ import { MovieAgent } from 'movie-agent';
267
+ import type { NextApiRequest, NextApiResponse } from 'next';
268
+
269
+ const agent = new MovieAgent();
134
270
 
135
- dotenv.config();
271
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
272
+ if (req.method !== 'POST') {
273
+ return res.status(405).json({ error: 'Method not allowed' });
274
+ }
275
+
276
+ try {
277
+ const { mood, genre, platforms } = req.body;
278
+
279
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
280
+ res.setHeader('Transfer-Encoding', 'chunked');
281
+
282
+ await agent.stream({ mood, genre, platforms }, (chunk) => {
283
+ res.write(chunk);
284
+ });
285
+
286
+ res.end();
287
+ } catch (error) {
288
+ console.error('Error streaming recommendations:', error);
289
+ res.status(500).json({ error: 'Failed to stream recommendations' });
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Express Server (Streaming)
295
+
296
+ ```typescript
297
+ import express from 'express';
298
+ import { MovieAgent } from 'movie-agent';
136
299
 
137
300
  const app = express();
138
301
  app.use(express.json());
139
302
 
140
- const agent = MovieAgentFactory.create({
141
- tmdbApiKey: process.env.TMDB_API_KEY!,
142
- tmdbRegion: 'CA',
143
- });
303
+ const agent = new MovieAgent();
144
304
 
305
+ // Structured data endpoint
145
306
  app.post('/api/recommendations', async (req, res) => {
146
307
  try {
147
308
  const recommendations = await agent.getRecommendations(req.body);
@@ -152,11 +313,72 @@ app.post('/api/recommendations', async (req, res) => {
152
313
  }
153
314
  });
154
315
 
316
+ // Streaming endpoint
317
+ app.post('/api/recommendations/stream', async (req, res) => {
318
+ try {
319
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
320
+ res.setHeader('Transfer-Encoding', 'chunked');
321
+
322
+ await agent.stream(req.body, (chunk) => {
323
+ res.write(chunk);
324
+ });
325
+
326
+ res.end();
327
+ } catch (error) {
328
+ console.error(error);
329
+ res.status(500).json({ error: 'Failed to stream recommendations' });
330
+ }
331
+ });
332
+
155
333
  app.listen(3000, () => {
156
334
  console.log('Server running on http://localhost:3000');
157
335
  });
158
336
  ```
159
337
 
338
+ ### React Component with Streaming
339
+
340
+ ```typescript
341
+ import { useState } from 'react';
342
+
343
+ function MovieRecommendations() {
344
+ const [output, setOutput] = useState('');
345
+ const [loading, setLoading] = useState(false);
346
+
347
+ const getRecommendations = async () => {
348
+ setLoading(true);
349
+ setOutput('');
350
+
351
+ const response = await fetch('/api/recommendations/stream', {
352
+ method: 'POST',
353
+ headers: { 'Content-Type': 'application/json' },
354
+ body: JSON.stringify({ mood: 'happy', platforms: ['Netflix'] }),
355
+ });
356
+
357
+ const reader = response.body?.getReader();
358
+ const decoder = new TextDecoder();
359
+
360
+ while (true) {
361
+ const { done, value } = await reader.read();
362
+ if (done) break;
363
+
364
+ const chunk = decoder.decode(value);
365
+ setOutput(prev => prev + chunk);
366
+ }
367
+
368
+ setLoading(false);
369
+ };
370
+
371
+ return (
372
+ <div>
373
+ <button onClick={getRecommendations} disabled={loading}>
374
+ Get Recommendations
375
+ </button>
376
+ <div style={{ whiteSpace: 'pre-wrap' }}>{output}</div>
377
+ </div>
378
+ );
379
+ }
380
+ ```
381
+
160
382
  ## Configuration
161
383
 
162
384
  ### Environment Variables
@@ -165,6 +387,17 @@ app.listen(3000, () => {
165
387
  # Required
166
388
  TMDB_API_KEY=your_tmdb_api_key_here
167
389
 
390
+ # LLM Provider Selection (optional)
391
+ LLM_PROVIDER=gemini # Options: gemini, azure
392
+
393
+ # Option 1: Google Gemini (for AI-formatted output)
394
+ GEMINI_API_KEY=your_gemini_api_key_here
395
+
396
+ # Option 2: Azure OpenAI (for AI-formatted output)
397
+ AZURE_OPENAI_API_KEY=your_azure_openai_api_key_here
398
+ AZURE_OPENAI_ENDPOINT=https://your-resource-name.openai.azure.com/
399
+ AZURE_OPENAI_DEPLOYMENT=your_deployment_name
400
+
168
401
  # Optional
169
402
  TMDB_REGION=CA
170
403
  CACHE_TTL=86400
@@ -172,6 +405,46 @@ MAX_RECOMMENDATIONS=5
172
405
  MIN_RECOMMENDATIONS=3
173
406
  ```
174
407
 
408
+ **Note:** If no LLM API key is provided, the `invoke()` and `stream()` methods will use a fallback formatter.
409
+
410
+ ### LLM Provider Configuration
411
+
412
+ The package supports multiple LLM providers for AI-formatted output:
413
+
414
+ #### Google Gemini (Default)
415
+ ```typescript
416
+ const agent = MovieAgentFactory.create({
417
+ tmdbApiKey: 'your-tmdb-key',
418
+ llmProvider: 'gemini',
419
+ geminiApiKey: 'your-gemini-key',
420
+ });
421
+ ```
422
+
423
+ #### Azure OpenAI
424
+ ```typescript
425
+ const agent = MovieAgentFactory.create({
426
+ tmdbApiKey: 'your-tmdb-key',
427
+ llmProvider: 'azure',
428
+ azureOpenAiApiKey: 'your-azure-key',
429
+ azureOpenAiEndpoint: 'https://your-resource.openai.azure.com/',
430
+ azureOpenAiDeployment: 'your-deployment-name',
431
+ });
432
+ ```
433
+
434
+ #### Using Environment Variables
435
+ ```bash
436
+ # Set LLM_PROVIDER in .env
437
+ LLM_PROVIDER=azure
438
+ AZURE_OPENAI_API_KEY=your_key
439
+ AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
440
+ AZURE_OPENAI_DEPLOYMENT=gpt-4
441
+ ```
442
+
443
+ ```typescript
444
+ // Automatically uses Azure OpenAI from environment
445
+ const agent = MovieAgentFactory.fromEnv();
446
+ ```
447
+
175
448
  ### Input Parameters
176
449
 
177
450
  ```typescript
@@ -236,7 +509,13 @@ import {
236
509
  AgentResponse,
237
510
  MovieRecommendation,
238
511
  ErrorResponse,
512
+ buildPosterUrl, // Utility to build poster URLs with different sizes
513
+ TMDB_IMAGE_BASE_URL, // Base URL for TMDb images
239
514
  } from 'movie-agent';
515
+
516
+ // Build poster URL with custom size (default is w500)
517
+ const smallPoster = buildPosterUrl('/abc123.jpg', 'w185');
518
+ // => "https://image.tmdb.org/t/p/w185/abc123.jpg"
240
519
  ```
241
520
 
242
521
  ## Response Format
@@ -261,6 +540,7 @@ interface MovieRecommendation {
261
540
  overview: string;
262
541
  streamingPlatforms: StreamingPlatform[];
263
542
  matchReason: string;
543
+ posterUrl: string | null; // Full URL to movie poster image (w500 size)
264
544
  }
265
545
  ```
266
546
 
@@ -461,4 +741,4 @@ MIT
461
741
 
462
742
  - [The Movie Database (TMDb)](https://www.themoviedb.org/) for movie data and streaming availability
463
743
  - [LangChain.js](https://js.langchain.com/) for agent framework
464
- - [OpenAI](https://openai.com/) for LLM capabilities
744
+ - [Google Gemini](https://ai.google.dev/) and [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) for LLM capabilities
package/bin/movie-agent CHANGED
@@ -10,6 +10,7 @@ const fs = require('fs');
10
10
  function parseArgs() {
11
11
  const args = process.argv.slice(2);
12
12
  const input = {};
13
+ let useStreaming = false;
13
14
 
14
15
  for (let i = 0; i < args.length; i++) {
15
16
  const arg = args[i];
@@ -75,13 +76,15 @@ function parseArgs() {
75
76
  printUsage();
76
77
  process.exit(1);
77
78
  }
79
+ } else if (arg === '--stream') {
80
+ useStreaming = true;
78
81
  } else if (arg === '--help' || arg === '-h') {
79
82
  printUsage();
80
83
  process.exit(0);
81
84
  }
82
85
  }
83
86
 
84
- return input;
87
+ return { input, useStreaming };
85
88
  }
86
89
 
87
90
  /**
@@ -100,11 +103,12 @@ Options:
100
103
  --year <number> Specific release year
101
104
  --yearFrom <number> Release year range start
102
105
  --yearTo <number> Release year range end
106
+ --stream Enable streaming output (real-time generation)
103
107
  --help, -h Show this help message
104
108
 
105
109
  Examples:
106
110
  movie-agent --mood excited --platforms Netflix
107
- movie-agent --genre Action,Thriller --runtimeMax 120
111
+ movie-agent --genre Action,Thriller --runtimeMax 120 --stream
108
112
  movie-agent --mood relaxed --yearFrom 2020 --yearTo 2023
109
113
  `);
110
114
  }
@@ -173,10 +177,15 @@ Or create a .env.development file with:
173
177
  process.exit(1);
174
178
  }
175
179
 
180
+ // Check for Gemini API key (optional, agent will work without it)
181
+ if (!process.env.GEMINI_API_KEY) {
182
+ console.warn(`\nāš ļø Warning: Gemini API key not found. Using fallback formatting.\n`);
183
+ }
184
+
176
185
  // Now it's safe to load the agent module
177
186
  const { MovieAgent } = require('../dist/agent');
178
187
 
179
- const input = parseArgs();
188
+ const { input, useStreaming } = parseArgs();
180
189
 
181
190
  // Show help if no arguments provided
182
191
  if (Object.keys(input).length === 0) {
@@ -184,19 +193,35 @@ Or create a .env.development file with:
184
193
  process.exit(0);
185
194
  }
186
195
 
187
- console.log('\nšŸ” Finding movie recommendations...\n');
196
+ console.log('\\nšŸ” Finding movie recommendations...\\n');
188
197
 
189
198
  const agent = new MovieAgent();
190
- const response = await agent.getRecommendations(input);
191
199
 
192
- const output = formatOutput(response);
193
- console.log(output);
200
+ if (useStreaming) {
201
+ // Use streaming output
202
+ const result = await agent.stream(input, (chunk) => {
203
+ process.stdout.write(chunk);
204
+ });
205
+
206
+ if (result && 'error' in result) {
207
+ throw new Error(result.message);
208
+ }
209
+ } else {
210
+ // Use non-streaming output
211
+ const output = await agent.invoke(input);
212
+
213
+ if (typeof output === 'object' && 'error' in output) {
214
+ throw new Error(output.message);
215
+ }
216
+
217
+ console.log(output);
218
+ }
194
219
 
195
220
  } catch (error) {
196
221
  console.error('\nāŒ Error:', error.message);
197
222
 
198
223
  if (error.message.includes('API') || error.message.includes('network')) {
199
- console.error('\nPlease check your internet connection and TMDb API key.');
224
+ console.error('\nPlease check your internet connection and API keys.');
200
225
  } else if (error.message.includes('Invalid') || error.message.includes('validation')) {
201
226
  console.error('\nPlease check your input parameters and try again.');
202
227
  console.error('Use --help for usage information.');
package/dist/agent.d.ts CHANGED
@@ -6,12 +6,22 @@ import TmdbApiClient from './tmdbApi';
6
6
  export declare class MovieAgent {
7
7
  private tmdbClient;
8
8
  private logger;
9
+ private llmService;
10
+ private debug;
9
11
  /**
10
12
  * Creates a new MovieAgent instance
11
13
  * @param tmdbClient - Optional TMDb API client for testing
12
14
  * @param logger - Optional logger function for debugging
15
+ * @param enableLLM - Whether to enable LLM formatting (default: true if GEMINI_API_KEY is set)
16
+ * @param llmProvider - LLM provider to use ('gemini' or 'azure')
17
+ * @param llmApiKey - API key for the LLM provider
18
+ * @param azureConfig - Azure OpenAI configuration (endpoint and deployment)
19
+ * @param debug - Whether to include detailed error information in responses (default: false for production safety)
13
20
  */
14
- constructor(tmdbClient?: TmdbApiClient, logger?: (message: string) => void);
21
+ constructor(tmdbClient?: TmdbApiClient, logger?: (message: string) => void, enableLLM?: boolean, llmProvider?: 'gemini' | 'azure', llmApiKey?: string, azureConfig?: {
22
+ endpoint?: string;
23
+ deployment?: string;
24
+ }, debug?: boolean);
15
25
  /**
16
26
  * Gets movie recommendations based on user input
17
27
  * @param input - User input with mood, platforms, genres, runtime, and year preferences
@@ -52,11 +62,11 @@ export declare class MovieAgent {
52
62
  */
53
63
  private discoverCandidates;
54
64
  /**
55
- * Fetches watch providers for each candidate movie
56
- * @param candidates - Array of movie details
65
+ * Extracts watch providers from movie details and filters to those with providers
66
+ * @param candidates - Array of movie details with embedded providers
57
67
  * @returns Array of movies with platform information
58
68
  */
59
- private fetchWatchProviders;
69
+ private extractWatchProviders;
60
70
  /**
61
71
  * Applies user-specified filters to movies
62
72
  * @param movies - Movies with provider information
@@ -78,6 +88,23 @@ export declare class MovieAgent {
78
88
  * @returns Array of formatted recommendations
79
89
  */
80
90
  private formatRecommendations;
91
+ /**
92
+ * Get recommendations with AI-formatted output (invoke mode)
93
+ * @param input - User input with mood, platforms, genres, runtime, and year preferences
94
+ * @returns Promise resolving to AI-formatted string output or error response
95
+ */
96
+ invoke(input: UserInput): Promise<string | ErrorResponse>;
97
+ /**
98
+ * Get recommendations with AI-formatted streaming output
99
+ * @param input - User input with mood, platforms, genres, runtime, and year preferences
100
+ * @param onChunk - Callback function called for each chunk of streamed content
101
+ * @returns Promise resolving when streaming is complete, or error response
102
+ */
103
+ stream(input: UserInput, onChunk: (chunk: string) => void): Promise<void | ErrorResponse>;
104
+ /**
105
+ * Fallback formatting when LLM is not available
106
+ */
107
+ private fallbackFormat;
81
108
  /**
82
109
  * Generates a match reason for a movie
83
110
  * @param movie - Movie to explain
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,aAAa,EAGb,aAAa,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,aAA+B,MAAM,WAAW,CAAC;AAaxD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,MAAM,CAA4B;IAE1C;;;;OAIG;gBACS,UAAU,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAM1E;;;;OAIG;IACG,kBAAkB,CACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,aAAa,GAAG,aAAa,CAAC;IAgEzC;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAmEnB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAqBrB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAerB;;;;;OAKG;YACW,kBAAkB;IA0ChC;;;;OAIG;YACW,mBAAmB;IAgCjC;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IA+BpB;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAoCrB;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAiC7B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;CAuC5B"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,aAAa,EAGb,aAAa,EACd,MAAM,SAAS,CAAC;AAWjB,OAAO,aAGN,MAAM,WAAW,CAAC;AAcnB;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,KAAK,CAAU;IAEvB;;;;;;;;;OASG;gBAED,UAAU,CAAC,EAAE,aAAa,EAC1B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,SAAS,CAAC,EAAE,OAAO,EACnB,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,EAChC,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EACxD,KAAK,CAAC,EAAE,OAAO;IAgBjB;;;;OAIG;IACG,kBAAkB,CACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,aAAa,GAAG,aAAa,CAAC;IAkEzC;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAmEnB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IA+BrB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAerB;;;;;OAKG;YACW,kBAAkB;IA2ChC;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IA+BpB;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAoCrB;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAkC7B;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,aAAa,CAAC;IAoB/D;;;;;OAKG;IACG,MAAM,CACV,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAC/B,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC;IAwBhC;;OAEG;IACH,OAAO,CAAC,cAAc;IAsBtB;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;CAuC5B"}