@heripo/research-radar 2.3.6 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ An AI-powered newsletter service for Korean cultural heritage. Built on [`@llm-n
24
24
  - Type-safe TypeScript with strict interfaces
25
25
  - Provider pattern for swapping components (Crawling/Analysis/Content/Email)
26
26
  - 66 crawling targets across heritage agencies, museums, academic societies
27
- - Dual LLM providers: OpenAI GPT-5 (analysis) + Google Gemini (content generation)
27
+ - Multi LLM providers: OpenAI GPT-5 (analysis) + selectable content generation (OpenAI / Anthropic / Google)
28
28
  - Built-in retries, chain options, preview emails
29
29
 
30
30
  **Links**: [Live service](https://heripo.com/research-radar/subscribe) • [Newsletter example](https://heripo.com/research-radar-newsletter-example.html) • [Core engine](https://github.com/heripo-lab/llm-newsletter-kit-core)
@@ -69,7 +69,7 @@ For academic publications:
69
69
  npm install @heripo/research-radar @llm-newsletter-kit/core
70
70
  ```
71
71
 
72
- **Requirements**: Node.js >= 24, OpenAI API key, Google Generative AI API key
72
+ **Requirements**: Node.js >= 24, OpenAI API key, content generation API key (OpenAI / Anthropic / Google)
73
73
 
74
74
  **Note**: `@llm-newsletter-kit/core` is a peer dependency and must be installed separately.
75
75
 
@@ -80,7 +80,11 @@ import { generateNewsletter } from '@heripo/research-radar';
80
80
 
81
81
  const newsletterId = await generateNewsletter({
82
82
  openAIApiKey: process.env.OPENAI_API_KEY,
83
- googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
83
+ contentGeneration: {
84
+ provider: 'anthropic', // 'openai' | 'anthropic' | 'google'
85
+ apiKey: process.env.ANTHROPIC_API_KEY,
86
+ // model: 'claude-sonnet-4-6', // optional, uses sensible default
87
+ },
84
88
 
85
89
  // Implement these repository interfaces (see src/types/dependencies.ts)
86
90
  taskRepository: {
@@ -237,16 +241,21 @@ subscribeUrl: 'https://yourdomain.com/subscribe'
237
241
  - Replace Korean heritage sites with your domain sources
238
242
  - Implement parsers in `src/parsers/`
239
243
 
240
- **4. Switch LLM provider** (optional):
244
+ **4. Switch content generation LLM provider** (optional):
241
245
 
242
- Currently uses dual providers: **OpenAI** (analysis) + **Google Gemini** (content generation). To change:
243
- - `src/newsletter-generator.ts`: Change `createOpenAI()` / `createGoogleGenerativeAI()` to your provider
244
- - `src/providers/analysis.provider.ts`: Update model names (currently `gpt-5-mini`, `gpt-5.1`)
245
- - `src/providers/content-generate.provider.ts`: Update model name (currently `gemini-3-pro-preview`)
246
+ Content generation supports **3 built-in providers** just change `contentGeneration.provider`:
247
+ ```typescript
248
+ contentGeneration: {
249
+ provider: 'google', // 'openai' | 'anthropic' | 'google'
250
+ apiKey: process.env.GOOGLE_API_KEY,
251
+ model: 'gemini-3.1-pro-preview', // optional, each provider has a default
252
+ }
253
+ ```
254
+ Default models: openai=`gpt-5.1`, anthropic=`claude-sonnet-4-6`, google=`gemini-3.1-pro-preview`
246
255
 
247
- Any [Vercel AI SDK provider](https://sdk.vercel.ai/providers) works.
256
+ Analysis provider (OpenAI) can be changed by modifying `src/providers/analysis.provider.ts`. Any [Vercel AI SDK provider](https://sdk.vercel.ai/providers) works.
248
257
 
249
- **Search keywords**: `heripo`, `kimhongyeon`, `#D2691E`, `openai`, `gpt-5`, `google`, `GoogleGenerativeAI`, `gemini`, `createGoogleGenerativeAI`
258
+ **Search keywords**: `heripo`, `kimhongyeon`, `#D2691E`, `openai`, `gpt-5`, `contentGeneration`
250
259
 
251
260
  ## Why Code-Based?
252
261
 
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var anthropic = require('@ai-sdk/anthropic');
3
4
  var google = require('@ai-sdk/google');
4
5
  var openai = require('@ai-sdk/openai');
5
6
  var core = require('@llm-newsletter-kit/core');
@@ -2361,12 +2362,11 @@ ${poweredByFooterHtml()}
2361
2362
 
2362
2363
  /**
2363
2364
  * Content generation provider implementation
2364
- * - LLM-based newsletter content generation (Google Generative AI)
2365
+ * - LLM-based newsletter content generation
2365
2366
  * - HTML template provisioning
2366
2367
  * - Newsletter persistence
2367
2368
  */
2368
2369
  class ContentGenerateProvider {
2369
- google;
2370
2370
  articleRepository;
2371
2371
  newsletterRepository;
2372
2372
  _issueOrder = null;
@@ -2375,11 +2375,10 @@ class ContentGenerateProvider {
2375
2375
  htmlTemplate;
2376
2376
  /** Newsletter brand name (defaults to config, can be overridden via constructor) */
2377
2377
  newsletterBrandName;
2378
- constructor(google, articleRepository, newsletterRepository, templateOptions, brandName) {
2379
- this.google = google;
2378
+ constructor(model, articleRepository, newsletterRepository, templateOptions, brandName) {
2380
2379
  this.articleRepository = articleRepository;
2381
2380
  this.newsletterRepository = newsletterRepository;
2382
- this.model = this.google('gemini-3-pro-preview');
2381
+ this.model = model;
2383
2382
  this.newsletterBrandName = brandName ?? newsletterConfig.brandName;
2384
2383
  this.htmlTemplate = {
2385
2384
  html: createNewsletterHtmlTemplate(createCrawlingTargetGroups().flatMap((group) => group.targets), templateOptions),
@@ -2575,7 +2574,10 @@ class TaskService {
2575
2574
  * ```typescript
2576
2575
  * const generator = createNewsletterGenerator({
2577
2576
  * openAIApiKey: process.env.OPENAI_API_KEY,
2578
- * googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
2577
+ * contentGeneration: {
2578
+ * provider: 'anthropic',
2579
+ * apiKey: process.env.ANTHROPIC_API_KEY,
2580
+ * },
2579
2581
  * taskRepository: new PrismaTaskRepository(prisma),
2580
2582
  * articleRepository: new PrismaArticleRepository(prisma),
2581
2583
  * tagRepository: new PrismaTagRepository(prisma),
@@ -2591,13 +2593,26 @@ class TaskService {
2591
2593
  * const newsletterId = await generator.generate();
2592
2594
  * ```
2593
2595
  */
2596
+ function createContentGenerationModel(config) {
2597
+ switch (config.provider) {
2598
+ case 'openai': {
2599
+ const provider = openai.createOpenAI({ apiKey: config.apiKey });
2600
+ return provider(config.model ?? 'gpt-5.4');
2601
+ }
2602
+ case 'anthropic': {
2603
+ const provider = anthropic.createAnthropic({ apiKey: config.apiKey });
2604
+ return provider(config.model ?? 'claude-sonnet-4-6');
2605
+ }
2606
+ case 'google': {
2607
+ const provider = google.createGoogleGenerativeAI({ apiKey: config.apiKey });
2608
+ return provider(config.model ?? 'gemini-3.1-pro-preview');
2609
+ }
2610
+ }
2611
+ }
2594
2612
  function createNewsletterGenerator(dependencies) {
2595
2613
  const openai$1 = openai.createOpenAI({
2596
2614
  apiKey: dependencies.openAIApiKey,
2597
2615
  });
2598
- const google$1 = google.createGoogleGenerativeAI({
2599
- apiKey: dependencies.googleGenerativeAIApiKey,
2600
- });
2601
2616
  const dateService = new DateService(dependencies.publishDate);
2602
2617
  const taskService = new TaskService(dependencies.taskRepository);
2603
2618
  const crawlingProvider = new CrawlingProvider(dependencies.articleRepository, dependencies.customFetch);
@@ -2620,7 +2635,8 @@ function createNewsletterGenerator(dependencies) {
2620
2635
  };
2621
2636
  resolvedBrandName = '한국고고학회 뉴스레터';
2622
2637
  }
2623
- const contentGenerateProvider = new ContentGenerateProvider(google$1, dependencies.articleRepository, dependencies.newsletterRepository, templateOptions, resolvedBrandName);
2638
+ const contentModel = createContentGenerationModel(dependencies.contentGeneration);
2639
+ const contentGenerateProvider = new ContentGenerateProvider(contentModel, dependencies.articleRepository, dependencies.newsletterRepository, templateOptions, resolvedBrandName);
2624
2640
  return new core.GenerateNewsletter({
2625
2641
  contentOptions: resolvedContentOptions,
2626
2642
  dateService,
@@ -2650,7 +2666,10 @@ function createNewsletterGenerator(dependencies) {
2650
2666
  * ```typescript
2651
2667
  * const newsletterId = await generateNewsletter({
2652
2668
  * openAIApiKey: process.env.OPENAI_API_KEY,
2653
- * googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
2669
+ * contentGeneration: {
2670
+ * provider: 'anthropic',
2671
+ * apiKey: process.env.ANTHROPIC_API_KEY,
2672
+ * },
2654
2673
  * taskRepository: new PrismaTaskRepository(prisma),
2655
2674
  * articleRepository: new PrismaArticleRepository(prisma),
2656
2675
  * tagRepository: new PrismaTagRepository(prisma),
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { UrlString, ParsedTarget, CrawlingTargetGroup, CrawlingTarget, UnscoredArticle, ArticleForUpdateByAnalysis, ArticleForGenerateContent, Newsletter, AppLogger, EmailService, EmailMessage, DateService as DateService$1, IsoDateString, TaskService as TaskService$1, AnalysisProvider as AnalysisProvider$1, ContentGenerateProvider as ContentGenerateProvider$1, HtmlTemplate, CrawlingProvider as CrawlingProvider$1, GenerateNewsletterConfig } from '@llm-newsletter-kit/core';
2
2
  import { OpenAIProvider } from '@ai-sdk/openai';
3
- import { GoogleGenerativeAIProvider } from '@ai-sdk/google';
3
+ import { LanguageModel } from 'ai';
4
4
 
5
5
  /**
6
6
  * Repository interface for task management
@@ -151,12 +151,9 @@ interface NewsletterRepository {
151
151
  }
152
152
 
153
153
  /**
154
- * Uses two LLM providers:
155
- * - OpenAI (gpt-5-mini, gpt-5.1): Article analysis (tag classification, image analysis, importance scoring)
156
- * - Google Generative AI (gemini-3-pro-preview): Newsletter content generation
154
+ * Uses OpenAI for article analysis and a configurable provider (OpenAI / Anthropic / Google) for content generation.
157
155
  *
158
- * For details on switching providers, see README.md section:
159
- * "⚠️ Fork하여 나만의 뉴스레터 만들기 > 4. LLM 프로바이더 변경"
156
+ * Content generation provider is selected via `contentGeneration.provider` in dependencies.
160
157
  */
161
158
 
162
159
  /**
@@ -170,14 +167,37 @@ interface PreviewNewsletterOptions {
170
167
  /** Email message configuration (subject, html, text are auto-generated) */
171
168
  emailMessage: Omit<EmailMessage, 'subject' | 'html' | 'text'>;
172
169
  }
170
+ /**
171
+ * Content generation LLM provider configuration.
172
+ * Choose one of the three supported providers and supply the API key.
173
+ * Each provider uses a sensible default model that can be overridden.
174
+ *
175
+ * Default models:
176
+ * - openai: `gpt-5.4`
177
+ * - anthropic: `claude-sonnet-4-6`
178
+ * - google: `gemini-3.1-pro-preview`
179
+ */
180
+ type ContentGenerationConfig = {
181
+ provider: 'openai';
182
+ apiKey: string;
183
+ model?: string;
184
+ } | {
185
+ provider: 'anthropic';
186
+ apiKey: string;
187
+ model?: string;
188
+ } | {
189
+ provider: 'google';
190
+ apiKey: string;
191
+ model?: string;
192
+ };
173
193
  /**
174
194
  * Newsletter generator dependencies interface
175
195
  */
176
196
  interface NewsletterGeneratorDependencies {
177
197
  /** OpenAI API key (used for article analysis: tag classification, image analysis, importance scoring) */
178
198
  openAIApiKey: string;
179
- /** Google Generative AI API key (used for newsletter content generation) */
180
- googleGenerativeAIApiKey: string;
199
+ /** Content generation LLM configuration (provider + API key + optional model) */
200
+ contentGeneration: ContentGenerationConfig;
181
201
  /** Task management repository */
182
202
  taskRepository: TaskRepository;
183
203
  /** Article management repository */
@@ -212,7 +232,10 @@ interface NewsletterGeneratorDependencies {
212
232
  * ```typescript
213
233
  * const newsletterId = await generateNewsletter({
214
234
  * openAIApiKey: process.env.OPENAI_API_KEY,
215
- * googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
235
+ * contentGeneration: {
236
+ * provider: 'anthropic',
237
+ * apiKey: process.env.ANTHROPIC_API_KEY,
238
+ * },
216
239
  * taskRepository: new PrismaTaskRepository(prisma),
217
240
  * articleRepository: new PrismaArticleRepository(prisma),
218
241
  * tagRepository: new PrismaTagRepository(prisma),
@@ -338,21 +361,20 @@ declare class AnalysisProvider implements AnalysisProvider$1 {
338
361
 
339
362
  /**
340
363
  * Content generation provider implementation
341
- * - LLM-based newsletter content generation (Google Generative AI)
364
+ * - LLM-based newsletter content generation
342
365
  * - HTML template provisioning
343
366
  * - Newsletter persistence
344
367
  */
345
368
  declare class ContentGenerateProvider implements ContentGenerateProvider$1 {
346
- private readonly google;
347
369
  private readonly articleRepository;
348
370
  private readonly newsletterRepository;
349
371
  private _issueOrder;
350
- model: ReturnType<GoogleGenerativeAIProvider>;
372
+ readonly model: LanguageModel;
351
373
  /** HTML template with markers for title and content injection */
352
374
  htmlTemplate: HtmlTemplate;
353
375
  /** Newsletter brand name (defaults to config, can be overridden via constructor) */
354
376
  newsletterBrandName: string;
355
- constructor(google: GoogleGenerativeAIProvider, articleRepository: ArticleRepository, newsletterRepository: NewsletterRepository, templateOptions?: NewsletterTemplateOptions, brandName?: string);
377
+ constructor(model: LanguageModel, articleRepository: ArticleRepository, newsletterRepository: NewsletterRepository, templateOptions?: NewsletterTemplateOptions, brandName?: string);
356
378
  /** LLM temperature setting for content generation */
357
379
  temperature: number;
358
380
  /** Subscribe page URL */
@@ -460,4 +482,4 @@ declare const llmConfig: {
460
482
  };
461
483
 
462
484
  export { AnalysisProvider, ContentGenerateProvider, CrawlingProvider, DateService, TaskService, contentOptions, createCrawlingTargetGroups, generateNewsletter, generateWelcomeHTML, llmConfig, newsletterConfig };
463
- export type { ArticleRepository, ContentOptions, NewsletterConfig, NewsletterGeneratorDependencies, NewsletterRepository, NewsletterTemplateOptions, PreviewNewsletterOptions, TagRepository, TaskRepository, WelcomeTemplateOptions };
485
+ export type { ArticleRepository, ContentGenerationConfig, ContentOptions, NewsletterConfig, NewsletterGeneratorDependencies, NewsletterRepository, NewsletterTemplateOptions, PreviewNewsletterOptions, TagRepository, TaskRepository, WelcomeTemplateOptions };
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createAnthropic } from '@ai-sdk/anthropic';
1
2
  import { createGoogleGenerativeAI } from '@ai-sdk/google';
2
3
  import { createOpenAI } from '@ai-sdk/openai';
3
4
  import { DateType, GenerateNewsletter } from '@llm-newsletter-kit/core';
@@ -2340,12 +2341,11 @@ ${poweredByFooterHtml()}
2340
2341
 
2341
2342
  /**
2342
2343
  * Content generation provider implementation
2343
- * - LLM-based newsletter content generation (Google Generative AI)
2344
+ * - LLM-based newsletter content generation
2344
2345
  * - HTML template provisioning
2345
2346
  * - Newsletter persistence
2346
2347
  */
2347
2348
  class ContentGenerateProvider {
2348
- google;
2349
2349
  articleRepository;
2350
2350
  newsletterRepository;
2351
2351
  _issueOrder = null;
@@ -2354,11 +2354,10 @@ class ContentGenerateProvider {
2354
2354
  htmlTemplate;
2355
2355
  /** Newsletter brand name (defaults to config, can be overridden via constructor) */
2356
2356
  newsletterBrandName;
2357
- constructor(google, articleRepository, newsletterRepository, templateOptions, brandName) {
2358
- this.google = google;
2357
+ constructor(model, articleRepository, newsletterRepository, templateOptions, brandName) {
2359
2358
  this.articleRepository = articleRepository;
2360
2359
  this.newsletterRepository = newsletterRepository;
2361
- this.model = this.google('gemini-3-pro-preview');
2360
+ this.model = model;
2362
2361
  this.newsletterBrandName = brandName ?? newsletterConfig.brandName;
2363
2362
  this.htmlTemplate = {
2364
2363
  html: createNewsletterHtmlTemplate(createCrawlingTargetGroups().flatMap((group) => group.targets), templateOptions),
@@ -2554,7 +2553,10 @@ class TaskService {
2554
2553
  * ```typescript
2555
2554
  * const generator = createNewsletterGenerator({
2556
2555
  * openAIApiKey: process.env.OPENAI_API_KEY,
2557
- * googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
2556
+ * contentGeneration: {
2557
+ * provider: 'anthropic',
2558
+ * apiKey: process.env.ANTHROPIC_API_KEY,
2559
+ * },
2558
2560
  * taskRepository: new PrismaTaskRepository(prisma),
2559
2561
  * articleRepository: new PrismaArticleRepository(prisma),
2560
2562
  * tagRepository: new PrismaTagRepository(prisma),
@@ -2570,13 +2572,26 @@ class TaskService {
2570
2572
  * const newsletterId = await generator.generate();
2571
2573
  * ```
2572
2574
  */
2575
+ function createContentGenerationModel(config) {
2576
+ switch (config.provider) {
2577
+ case 'openai': {
2578
+ const provider = createOpenAI({ apiKey: config.apiKey });
2579
+ return provider(config.model ?? 'gpt-5.4');
2580
+ }
2581
+ case 'anthropic': {
2582
+ const provider = createAnthropic({ apiKey: config.apiKey });
2583
+ return provider(config.model ?? 'claude-sonnet-4-6');
2584
+ }
2585
+ case 'google': {
2586
+ const provider = createGoogleGenerativeAI({ apiKey: config.apiKey });
2587
+ return provider(config.model ?? 'gemini-3.1-pro-preview');
2588
+ }
2589
+ }
2590
+ }
2573
2591
  function createNewsletterGenerator(dependencies) {
2574
2592
  const openai = createOpenAI({
2575
2593
  apiKey: dependencies.openAIApiKey,
2576
2594
  });
2577
- const google = createGoogleGenerativeAI({
2578
- apiKey: dependencies.googleGenerativeAIApiKey,
2579
- });
2580
2595
  const dateService = new DateService(dependencies.publishDate);
2581
2596
  const taskService = new TaskService(dependencies.taskRepository);
2582
2597
  const crawlingProvider = new CrawlingProvider(dependencies.articleRepository, dependencies.customFetch);
@@ -2599,7 +2614,8 @@ function createNewsletterGenerator(dependencies) {
2599
2614
  };
2600
2615
  resolvedBrandName = '한국고고학회 뉴스레터';
2601
2616
  }
2602
- const contentGenerateProvider = new ContentGenerateProvider(google, dependencies.articleRepository, dependencies.newsletterRepository, templateOptions, resolvedBrandName);
2617
+ const contentModel = createContentGenerationModel(dependencies.contentGeneration);
2618
+ const contentGenerateProvider = new ContentGenerateProvider(contentModel, dependencies.articleRepository, dependencies.newsletterRepository, templateOptions, resolvedBrandName);
2603
2619
  return new GenerateNewsletter({
2604
2620
  contentOptions: resolvedContentOptions,
2605
2621
  dateService,
@@ -2629,7 +2645,10 @@ function createNewsletterGenerator(dependencies) {
2629
2645
  * ```typescript
2630
2646
  * const newsletterId = await generateNewsletter({
2631
2647
  * openAIApiKey: process.env.OPENAI_API_KEY,
2632
- * googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
2648
+ * contentGeneration: {
2649
+ * provider: 'anthropic',
2650
+ * apiKey: process.env.ANTHROPIC_API_KEY,
2651
+ * },
2633
2652
  * taskRepository: new PrismaTaskRepository(prisma),
2634
2653
  * articleRepository: new PrismaArticleRepository(prisma),
2635
2654
  * tagRepository: new PrismaTagRepository(prisma),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@heripo/research-radar",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "2.3.6",
5
+ "version": "3.0.0",
6
6
  "description": "AI-driven intelligence for Korean cultural heritage. This package serves as both a ready-to-use newsletter service and a practical implementation example for the LLM-Newsletter-Kit.",
7
7
  "main": "dist/index.cjs",
8
8
  "module": "dist/index.js",
@@ -47,13 +47,14 @@
47
47
  "author": "kimhongyeon",
48
48
  "license": "Apache-2.0",
49
49
  "dependencies": {
50
- "@ai-sdk/google": "^3.0.34",
51
- "@ai-sdk/openai": "^3.0.37",
50
+ "@ai-sdk/anthropic": "^3.0.58",
51
+ "@ai-sdk/google": "^3.0.43",
52
+ "@ai-sdk/openai": "^3.0.41",
52
53
  "cheerio": "^1.2.0",
53
- "dompurify": "^3.3.1",
54
+ "dompurify": "^3.3.2",
54
55
  "jsdom": "^28.1.0",
55
56
  "juice": "^11.1.1",
56
- "safe-markdown2html": "^1.0.0",
57
+ "safe-markdown2html": "^1.0.1",
57
58
  "turndown": "^7.2.2"
58
59
  },
59
60
  "peerDependencies": {
@@ -61,13 +62,13 @@
61
62
  },
62
63
  "devDependencies": {
63
64
  "@eslint/js": "^10.0.1",
64
- "@llm-newsletter-kit/core": "^1.3.4",
65
+ "@llm-newsletter-kit/core": "^1.3.5",
65
66
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",
66
67
  "@types/express": "^5.0.6",
67
68
  "@types/jsdom": "^28.0.0",
68
- "@types/node": "^25.3.3",
69
+ "@types/node": "^25.3.5",
69
70
  "@types/turndown": "^5.0.6",
70
- "eslint": "^10.0.2",
71
+ "eslint": "^10.0.3",
71
72
  "eslint-plugin-unused-imports": "^4.4.1",
72
73
  "express": "^5.2.1",
73
74
  "prettier": "^3.8.1",