@llm-newsletter-kit/core 3.0.2 → 3.0.3

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
@@ -107,16 +107,16 @@ const config: GenerateNewsletterConfig<string> = {
107
107
  },
108
108
  analysisProvider: {
109
109
  // Configure LLM models for analysis
110
- classifyTagOptions: { model: openai('gpt-5-mini') },
111
- analyzeImagesOptions: { model: openai('gpt-5.1') },
112
- determineScoreOptions: { model: openai('gpt-5.1') },
110
+ classifyTagOptions: { model: openai('gpt-5.4-nano') },
111
+ analyzeImagesOptions: { model: openai('gpt-5.4-nano') },
112
+ determineScoreOptions: { model: openai('gpt-5.4-nano') },
113
113
  fetchUnscoredArticles: async () => [/* ... */],
114
114
  fetchTags: async () => [/* ... */],
115
115
  update: async (article) => {},
116
116
  },
117
117
  contentGenerateProvider: {
118
118
  // Configure content generation
119
- model: openai('gpt-5.1'),
119
+ model: openai('gpt-5.4-nano'),
120
120
  issueOrder: 1,
121
121
  newsletterBrandName: 'Tech Insight Weekly',
122
122
  publicationCriteria: { minimumArticleCountForIssue: 5 },
@@ -281,21 +281,77 @@ Playground scripts let you run individual LLM query classes in isolation — no
281
281
  ```
282
282
 
283
283
  3. Edit `playground/data/config.json` with your OpenAI API key and options.
284
- 4. Edit `playground/data/articles.json` with your target articles.
284
+ 4. Edit `playground/data/articles.json` with your target articles. Both camelCase field names (`detailContent`, `targetUrl`, …) and snake_case DB dumps (`detail_content`, `target_url`, …) are accepted — snake_case records are normalized automatically.
285
285
  5. (Optional) Replace `playground/data/template.html` with your actual email template.
286
286
 
287
+ ### Custom Prompts (optional)
288
+
289
+ To test custom LLM prompts per pipeline stage (the `PromptProvider` interface), copy the example prompt module and edit it:
290
+
291
+ ```bash
292
+ cp playground/data-examples/prompts.example.ts playground/data/prompts.ts
293
+ ```
294
+
295
+ Every builder in `prompts.ts` is optional — delete the ones you don't want to override and those stages fall back to the built-in default prompts. Each playground script logs whether it is running with custom or default prompts.
296
+
297
+ Prompt builders receive their values (`expertFields`, `outputLanguage`, `targetArticle`, `dateService`, …) as arguments rather than reading config directly, so a prompt module written this way works unchanged across different configurations. Those argument values come from `config.json` and `articles.json`.
298
+
299
+ ### Per-stage models (optional)
300
+
301
+ Production pipelines often mix providers — a cheap model for tagging, a multimodal one for images, a stronger one for the final newsletter. Add a `models` block to override any stage; omitted fields fall back to the top-level `provider` / `apiKey` / `model`:
302
+
303
+ ```json
304
+ {
305
+ "provider": "openai",
306
+ "apiKey": "sk-...",
307
+ "model": "gpt-5.4-nano",
308
+ "models": {
309
+ "analyzeImages": { "model": "gpt-5.4-nano" },
310
+ "generateNewsletter": {
311
+ "provider": "anthropic",
312
+ "apiKey": "sk-ant-...",
313
+ "model": "claude-sonnet-4-6"
314
+ }
315
+ }
316
+ }
317
+ ```
318
+
319
+ ### Generation options (optional)
320
+
321
+ Sampling and output limits for the newsletter generation stage. Omitted values use the core defaults (`temperature: 0.3`, everything else unset):
322
+
323
+ ```json
324
+ {
325
+ "generation": {
326
+ "temperature": 0.3,
327
+ "maxOutputTokens": 32000
328
+ }
329
+ }
330
+ ```
331
+
332
+ Set `maxOutputTokens` when generating long newsletters — the generation query throws if the model stops on the token limit (`finishReason: "length"`).
333
+
287
334
  ### Run
288
335
 
336
+ Each pipeline stage can be run in isolation:
337
+
289
338
  ```bash
290
- npm run playground:generate-newsletter
339
+ npm run playground:classify-tags # ❶ Tag classification
340
+ npm run playground:analyze-images # ❷ Image analysis (multimodal model required)
341
+ npm run playground:determine-importance # ❸ Importance scoring
342
+ npm run playground:generate-newsletter # ❹ Newsletter generation
291
343
  ```
292
344
 
293
345
  ### Output
294
346
 
295
347
  Results are saved to `playground/output/` (git-ignored):
296
348
 
349
+ - `classify-tags.md` — Assigned tags per article
350
+ - `analyze-images.md` — Image analysis context per article
351
+ - `determine-importance.md` — Importance score table
297
352
  - `newsletter.md` — Generated markdown with title in frontmatter
298
353
  - `newsletter.html` — Rendered HTML with CSS inlined (juice)
354
+ - `usage.md` — Token usage report (newsletter generation)
299
355
 
300
356
  ### Data Management
301
357
 
package/dist/index.d.ts CHANGED
@@ -445,7 +445,7 @@ interface DateService {
445
445
  /**
446
446
  * Return a localized display string of the newsletter publication date
447
447
  * for use in newsletter content.
448
- * @example "10월 15일"
448
+ * @example "October 15"
449
449
  */
450
450
  getPublicationDisplayDateString: () => string;
451
451
  }
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": "@llm-newsletter-kit/core",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "3.0.2",
5
+ "version": "3.0.3",
6
6
  "description": "An extensible framework to automate your entire newsletter workflow. Handles data collection, LLM-based content analysis, and email generation, letting you focus on your unique domain logic.",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
@@ -42,41 +42,45 @@
42
42
  "format": "prettier --write \"**/*.{ts,tsx,js,jsx,mjs,json,md,mdx}\"",
43
43
  "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mjs,json,md,mdx}\"",
44
44
  "playground": "tsx",
45
+ "playground:verify-prompts": "tsx playground/verify-prompts.ts",
46
+ "playground:classify-tags": "tsx playground/classify-tags.ts",
47
+ "playground:analyze-images": "tsx playground/analyze-images.ts",
48
+ "playground:determine-importance": "tsx playground/determine-importance.ts",
45
49
  "playground:generate-newsletter": "tsx playground/generate-newsletter.ts"
46
50
  },
47
51
  "author": "kimhongyeon",
48
52
  "license": "Apache-2.0",
49
53
  "dependencies": {
50
- "@langchain/core": "^1.2.5",
51
- "ai": "^7.0.57",
52
- "es-toolkit": "^1.50.0",
54
+ "@langchain/core": "^1.2.9",
55
+ "ai": "^7.0.92",
56
+ "es-toolkit": "^1.52.0",
53
57
  "jsdom": "^30.0.1",
54
58
  "juice": "^12.1.2",
55
- "safe-markdown2html": "^1.0.11",
56
- "zod": "^4.4.3"
59
+ "safe-markdown2html": "^1.0.12",
60
+ "zod": "^4.5.4"
57
61
  },
58
62
  "devDependencies": {
59
- "@ai-sdk/anthropic": "^4.0.35",
60
- "@ai-sdk/google": "^4.0.38",
61
- "@ai-sdk/openai": "^4.0.35",
62
- "@ai-sdk/togetherai": "^3.0.27",
63
+ "@ai-sdk/anthropic": "^4.0.49",
64
+ "@ai-sdk/google": "^4.0.63",
65
+ "@ai-sdk/openai": "^4.0.58",
66
+ "@ai-sdk/togetherai": "^3.0.44",
63
67
  "@eslint/js": "^10.0.1",
64
68
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",
65
69
  "@types/jsdom": "^30.0.0",
66
- "@types/node": "^26.2.0",
67
- "@vitest/coverage-v8": "^4.1.10",
68
- "@vitest/expect": "^4.1.10",
69
- "eslint": "^10.8.1",
70
+ "@types/node": "^26.4.1",
71
+ "@vitest/coverage-v8": "^5.0.0",
72
+ "@vitest/expect": "^5.0.0",
73
+ "eslint": "^10.9.1",
70
74
  "eslint-plugin-unused-imports": "^4.4.1",
71
75
  "prettier": "^3.9.6",
72
76
  "rimraf": "^6.1.3",
73
- "rollup": "^4.62.4",
77
+ "rollup": "^4.63.1",
74
78
  "rollup-plugin-dts": "^6.5.1",
75
79
  "rollup-plugin-typescript2": "^0.37.0",
76
- "tsx": "^4.23.11",
80
+ "tsx": "^4.23.13",
77
81
  "typescript": "^6.0.3",
78
- "typescript-eslint": "^8.66.0",
79
- "vitest": "^4.1.10"
82
+ "typescript-eslint": "^8.69.0",
83
+ "vitest": "^5.0.0"
80
84
  },
81
85
  "repository": {
82
86
  "type": "git",