@heripo/research-radar 5.0.6 → 5.2.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 +29 -23
- package/dist/index.d.ts +154 -5
- package/dist/index.js +2162 -100
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Previously reported service metrics were $0.2–1 per issue and 15% CTR. These a
|
|
|
23
23
|
|
|
24
24
|
- Type-safe TypeScript with strict interfaces
|
|
25
25
|
- Provider pattern for swapping components (Crawling/Analysis/Content/Email)
|
|
26
|
-
-
|
|
26
|
+
- 74 active crawling targets across heritage agencies, museums, academic societies, filtered at runtime by robots.txt
|
|
27
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
|
|
|
@@ -70,7 +70,7 @@ For academic publications:
|
|
|
70
70
|
npm install @heripo/research-radar '@llm-newsletter-kit/core@~3.0.0'
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
**Requirements**: Node.js >= 24 and an ESM application. The package exports `dist/index.js` and TypeScript declarations (`dist/index.d.ts`), with a JavaScript sourcemap. The core engine is a peer dependency; the current supported range is `~3.0.0
|
|
73
|
+
**Requirements**: Node.js >= 24 and an ESM application. The package exports `dist/index.js` and TypeScript declarations (`dist/index.d.ts`), with a JavaScript sourcemap. The core engine is a peer dependency; the current supported range is `~3.0.5`. 3.0.5 is the floor because the newsletter generation prompt this package ships relies on the self-verification retry cap added there.
|
|
74
74
|
|
|
75
75
|
Article analysis requires an OpenAI API key. Content generation requires a key for the selected provider (OpenAI / Anthropic / Google); OpenAI can use the same key for both. Keys are passed explicitly to the library; load environment variables in your application.
|
|
76
76
|
|
|
@@ -136,13 +136,15 @@ Candidate selection belongs to your repository. Persist `usedArticles` associati
|
|
|
136
136
|
|
|
137
137
|
### Optional generation settings
|
|
138
138
|
|
|
139
|
-
| Option
|
|
140
|
-
|
|
|
141
|
-
| `logger`
|
|
142
|
-
| `publishDate`
|
|
143
|
-
| `customFetch`
|
|
144
|
-
| `templateOptions`
|
|
145
|
-
| `
|
|
139
|
+
| Option | Behavior |
|
|
140
|
+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
141
|
+
| `logger` | Core `AppLogger` implementation, such as `console` |
|
|
142
|
+
| `publishDate` | A real calendar date in `YYYY-MM-DD` format; invalid values throw. Defaults to the current date in `Asia/Seoul` (KST), regardless of server timezone |
|
|
143
|
+
| `customFetch` | A `typeof fetch` implementation for crawling and parser API requests, such as a proxy adapter; does not configure LLM requests |
|
|
144
|
+
| `templateOptions` | Default or KRAS newsletter branding and Markdown sections (see below) |
|
|
145
|
+
| `promptProvider` | Core `PromptProvider` overriding the package's own LLM prompts entirely; omit to use the package's prompts, which fall back to core's defaults |
|
|
146
|
+
| `excavationReportSource` | Supplies 국가유산청 발굴조사 보고서 entries from the application; that board is then never crawled. Omit to crawl it as before |
|
|
147
|
+
| `previewNewsletter` | Fetch a saved `Newsletter` and send it through a supplied core `EmailService` |
|
|
146
148
|
|
|
147
149
|
`previewNewsletter` requires `fetchNewsletterForPreview: () => Promise<Newsletter>`, `emailService` (with `send(message)`), and `emailMessage` (core `EmailMessage` without `subject`, `html`, or `text`). The core fills those three fields and skips preview delivery when no newsletter was created. Ensure the callback fetches the issue saved by this run.
|
|
148
150
|
|
|
@@ -165,16 +167,16 @@ Defaults below describe the checked-in code, not provider recommendations. This
|
|
|
165
167
|
|
|
166
168
|
| Stage | Provider | Default model |
|
|
167
169
|
| ------------------ | --------- | ------------------------ |
|
|
168
|
-
| Tag classification | OpenAI | `gpt-5-
|
|
169
|
-
| Image analysis | OpenAI | `gpt-5.
|
|
170
|
-
| Importance scoring | OpenAI | `gpt-5.
|
|
171
|
-
| Content generation | OpenAI | `gpt-5.
|
|
170
|
+
| Tag classification | OpenAI | `gpt-5.6-luna` |
|
|
171
|
+
| Image analysis | OpenAI | `gpt-5.6-terra` |
|
|
172
|
+
| Importance scoring | OpenAI | `gpt-5.6-terra` |
|
|
173
|
+
| Content generation | OpenAI | `gpt-5.6-sol` |
|
|
172
174
|
| Content generation | Anthropic | `claude-sonnet-4-6` |
|
|
173
175
|
| Content generation | Google | `gemini-3.1-pro-preview` |
|
|
174
176
|
|
|
175
177
|
Select content generation with `contentGeneration: { provider, apiKey, model? }`. `model` overrides that provider's default. Analysis models are configured in [analysis.provider.ts](./src/providers/analysis.provider.ts).
|
|
176
178
|
|
|
177
|
-
[src/config/index.ts](./src/config/index.ts) defines Korean output (`outputLanguage: '한국어'`), the cultural heritage domain (`expertField: ['문화유산']`), brand name, `subscribePageUrl`, LLM `maxRetries: 5`, chain `stopAfterAttempt: 3`, and generation `temperature: 0.3`. Publication settings are `minimumArticleCountForIssue: 5` and `priorityArticleScoreThreshold: 8`; the core engine evaluates them. In the locked core 3.0.
|
|
179
|
+
[src/config/index.ts](./src/config/index.ts) defines Korean output (`outputLanguage: '한국어'`), the cultural heritage domain (`expertField: ['문화유산']`), brand name, `subscribePageUrl`, LLM `maxRetries: 5`, chain `stopAfterAttempt: 3`, and generation `temperature: 0.3`. Publication settings are `minimumArticleCountForIssue: 5` and `priorityArticleScoreThreshold: 8`; the core engine evaluates them. In the locked core 3.0.5 implementation, the count check skips **5 or fewer** candidates unless at least one has importance score >= 8. An empty candidate list is always skipped.
|
|
178
180
|
|
|
179
181
|
## Crawling targets and parsers
|
|
180
182
|
|
|
@@ -182,16 +184,20 @@ Select content generation with `contentGeneration: { provider, apiKey, model? }`
|
|
|
182
184
|
|
|
183
185
|
| Group | Active | Commented out |
|
|
184
186
|
| ---------- | -----: | ------------: |
|
|
185
|
-
| News |
|
|
186
|
-
| Business |
|
|
187
|
-
| Employment |
|
|
188
|
-
| **Total** | **
|
|
187
|
+
| News | 57 | 1 |
|
|
188
|
+
| Business | 5 | 0 |
|
|
189
|
+
| Employment | 12 | 0 |
|
|
190
|
+
| **Total** | **74** | **1** |
|
|
189
191
|
|
|
190
|
-
|
|
192
|
+
Only the excavation status board stays commented out, as low-value fragmented data. Boards that a site's robots.txt restricts are configured normally and refused at runtime by the robots.txt check, so the configuration does not have to track each site's policy by hand. With current policies 14 of the 74 targets are refused.
|
|
193
|
+
|
|
194
|
+
Three targets are read from data.go.kr open APIs instead of scraped: 나라일터 (`PblJobService`) and 알리오 (`recruitment`) under Employment, and 나라장터 (`BidPublicInfoService`) under Business. Each is a single round of requests, and `publicDataApiKey` supplies the service key — omit it and they answer with an empty list without making a request. The boards carry every public-sector vacancy and procurement notice in the country, so both are narrowed before analysis. The job boards use `src/crawling/heritage-job-filter.ts`, whose exclusions are role nouns and hold up as patterns; roughly 2% of postings survive, about 2.6 a day. 나라장터 instead uses `src/crawling/heritage-triage.ts`, which asks a cheap model about 100 titles per request: heritage vocabulary cannot be settled by substring in Korean, and the deterministic filter remains behind it as the fallback when a batch fails.
|
|
195
|
+
|
|
196
|
+
Crawling fetches pass through that check (`src/crawling/robots.ts`) before reaching the network: a disallowed request is refused rather than sent, and a missing or unreachable robots.txt allows it. `robotsExemptOrigins` in `src/config/index.ts` lists origins exempted from the check, each with its reason.
|
|
191
197
|
|
|
192
198
|
Sources include the Korea Heritage Service, National Research Institute of Cultural Heritage, National Research Institute of Maritime Heritage, Korea Heritage Agency, Korea Association of Archaeological Heritage, archaeological societies, and national museums.
|
|
193
199
|
|
|
194
|
-
[src/parsers/](./src/parsers/) contains
|
|
200
|
+
[src/parsers/](./src/parsers/) contains 23 organization-specific parser modules plus shared date and URL utilities. List parsers return `ParsedTargetListItem[]` (title, date, detail URL, date type, and optional source ID); detail parsers return Markdown `detailContent` and attachment/image flags. Parsers can be synchronous or asynchronous. KRAS, Yeongnam Archaeological Society, and maritime heritage sources use additional API requests for client-rendered content.
|
|
195
201
|
|
|
196
202
|
`CrawlingProvider` uses a maximum concurrency of 5 and wraps the supplied fetch to route KRAS public detail URLs to its detail API, while retaining public URLs in article metadata. When constructing your own pipeline, use the provider's fetch together with its target groups.
|
|
197
203
|
|
|
@@ -203,7 +209,7 @@ import { getSourceList } from '@heripo/research-radar';
|
|
|
203
209
|
const groups = getSourceList(); // [{ id, name, sources: [{ id, name, url }] }]
|
|
204
210
|
```
|
|
205
211
|
|
|
206
|
-
`createCrawlingTargetGroups(customFetch?)`, `getSourceList()`, `contentOptions`, `newsletterConfig`, and `
|
|
212
|
+
`createCrawlingTargetGroups(customFetch?)`, `getSourceList()`, `contentOptions`, `newsletterConfig`, `llmConfig`, and `researchRadarPromptProvider` are public exports. `ExcavationReport` and `ExcavationReportSource` are exported as types. The package also exports the three provider classes, `DateService`, `TaskService`, and their public configuration/dependency types through [src/index.ts](./src/index.ts).
|
|
207
213
|
|
|
208
214
|
## Email templates
|
|
209
215
|
|
|
@@ -332,7 +338,7 @@ Use repeatable `--skip-target=<id-or-name>` or `--skip-target <id-or-name>` to e
|
|
|
332
338
|
|
|
333
339
|
**Output**: Console table summary + compact text summary for CI integrations.
|
|
334
340
|
|
|
335
|
-
**CI**: [.github/workflows/parser-health-check.yml](./.github/workflows/parser-health-check.yml) runs daily at 08:00 UTC (17:00 KST), or manually, on an `org-linux` runner with a 30-minute job timeout. It skips the two KHS excavation report/site-open targets
|
|
341
|
+
**CI**: [.github/workflows/parser-health-check.yml](./.github/workflows/parser-health-check.yml) runs daily at 08:00 UTC (17:00 KST), or manually, on an `org-linux` runner with a 30-minute job timeout. It skips the two KHS excavation report/site-open targets. The health-check composes the same fetch as production — robots.txt gate, then the KRAS detail adapter — so disallowed boards are reported as skipped rather than failed: 16 skipped and 55 checked with the current configuration. The detail check tries up to three list items, so one unreadable post at the top of a board does not fail the target. Slack notifications require the `SLACK_BOT_TOKEN` secret and `SLACK_ALERT_DEV_CHANNEL` repository variable. Forks need a matching runner and notification configuration to use this workflow unchanged. The CLI also writes GitHub Actions outputs and a job summary when their environment variables are present.
|
|
336
342
|
|
|
337
343
|
## 🤝 Contributing
|
|
338
344
|
|
|
@@ -390,7 +396,7 @@ const contentGeneration: ContentGenerationConfig = {
|
|
|
390
396
|
};
|
|
391
397
|
```
|
|
392
398
|
|
|
393
|
-
Default models: openai=`gpt-5.
|
|
399
|
+
Default models: openai=`gpt-5.6-sol`, anthropic=`claude-sonnet-4-6`, google=`gemini-3.1-pro-preview`
|
|
394
400
|
|
|
395
401
|
To change analysis providers, update both `src/providers/analysis.provider.ts` (provider type and models) and `src/newsletter-generator.ts` (provider construction), using a compatible AI SDK provider. Also adapt domain-specific minimum-score rules in the analysis provider, output language and expert fields in config, package metadata, and the GitHub Actions runner/Slack settings for your fork.
|
|
396
402
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UrlString, ParsedTarget, CrawlingTargetGroup, CrawlingTarget, UnscoredArticle, ArticleForUpdateByAnalysis, ArticleForGenerateContent, Newsletter, AppLogger, EmailService, EmailMessage, DateService as DateService$1,
|
|
1
|
+
import { UrlString, ParsedTarget, CrawlingTargetGroup, CrawlingTarget, UnscoredArticle, ArticleForUpdateByAnalysis, ArticleForGenerateContent, Newsletter, IsoDateString, AppLogger, EmailService, EmailMessage, PromptProvider, DateService as DateService$1, 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
3
|
import { LanguageModel } from 'ai';
|
|
4
4
|
|
|
@@ -54,6 +54,53 @@ interface ArticleRepository {
|
|
|
54
54
|
*/
|
|
55
55
|
findCandidatesForNewsletter(): Promise<ArticleForGenerateContent[]>;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* A single excavation report supplied by the application instead of crawled.
|
|
59
|
+
*
|
|
60
|
+
* Field names mirror what the 국가유산청 report board exposes, so an application
|
|
61
|
+
* that already stores these rows can hand them over without reshaping them.
|
|
62
|
+
*/
|
|
63
|
+
interface ExcavationReport {
|
|
64
|
+
/**
|
|
65
|
+
* The board's own identifier (`ecexmRcno`). Used both as the article's unique
|
|
66
|
+
* id and to build its public detail URL, so it must match the value the board
|
|
67
|
+
* uses — otherwise previously crawled reports are re-saved as duplicates.
|
|
68
|
+
* @example "202609157717"
|
|
69
|
+
*/
|
|
70
|
+
externalId: string;
|
|
71
|
+
/**
|
|
72
|
+
* Report title (보고서명).
|
|
73
|
+
* @example "태안 태안읍성 -남문지 및 연지-"
|
|
74
|
+
*/
|
|
75
|
+
title: string;
|
|
76
|
+
/**
|
|
77
|
+
* Submission date (제출일) in ISO format (YYYY-MM-DD).
|
|
78
|
+
* @example "2026-09-15"
|
|
79
|
+
*/
|
|
80
|
+
submittedDate: IsoDateString;
|
|
81
|
+
/**
|
|
82
|
+
* Report detail fields as label/value pairs, rendered into the article body in
|
|
83
|
+
* insertion order. Supply whatever the source holds — 허가번호, 유적명,
|
|
84
|
+
* 발간기관, 조사시도시군구, 조사기간, 유적성격/시대구분 and so on.
|
|
85
|
+
* Empty values are skipped.
|
|
86
|
+
*/
|
|
87
|
+
fields: Record<string, string | null | undefined>;
|
|
88
|
+
/**
|
|
89
|
+
* Whether the report has a downloadable file. Defaults to true, matching the
|
|
90
|
+
* crawled parser.
|
|
91
|
+
*/
|
|
92
|
+
hasAttachedFile?: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Supplies excavation reports from the application instead of crawling them.
|
|
96
|
+
*
|
|
97
|
+
* When provided, the 국가유산청 발굴조사 보고서 board is served from this
|
|
98
|
+
* function and never requested over the network; the rest of the crawl is
|
|
99
|
+
* unaffected. When omitted, the board is crawled as before.
|
|
100
|
+
*
|
|
101
|
+
* Called at most once per generation run.
|
|
102
|
+
*/
|
|
103
|
+
type ExcavationReportSource = () => Promise<ExcavationReport[]>;
|
|
57
104
|
/**
|
|
58
105
|
* Repository interface for tag management
|
|
59
106
|
*/
|
|
@@ -178,7 +225,7 @@ interface PreviewNewsletterOptions {
|
|
|
178
225
|
* Each provider uses a sensible default model that can be overridden.
|
|
179
226
|
*
|
|
180
227
|
* Default models:
|
|
181
|
-
* - openai: `gpt-5.
|
|
228
|
+
* - openai: `gpt-5.6-sol`
|
|
182
229
|
* - anthropic: `claude-sonnet-4-6`
|
|
183
230
|
* - google: `gemini-3.1-pro-preview`
|
|
184
231
|
*/
|
|
@@ -226,6 +273,30 @@ interface NewsletterGeneratorDependencies {
|
|
|
226
273
|
templateOptions?: NewsletterTemplateOptions;
|
|
227
274
|
/** Custom fetch function for crawling (e.g., proxy-based fetch). Optional. */
|
|
228
275
|
customFetch?: typeof fetch;
|
|
276
|
+
/**
|
|
277
|
+
* Supplies 국가유산청 발굴조사 보고서 entries from the application (optional).
|
|
278
|
+
*
|
|
279
|
+
* When provided, that board is read from this function and never crawled,
|
|
280
|
+
* which lets an application that already stores the reports reuse them. Omit
|
|
281
|
+
* it to keep crawling the board as before. No other target is affected.
|
|
282
|
+
*/
|
|
283
|
+
excavationReportSource?: ExcavationReportSource;
|
|
284
|
+
/**
|
|
285
|
+
* data.go.kr service key for the 나라일터 and 알리오 job boards (optional).
|
|
286
|
+
*
|
|
287
|
+
* Pass the encoded key exactly as the portal supplies it. Both boards are read
|
|
288
|
+
* through open APIs rather than scraped; omit the key and they collect
|
|
289
|
+
* nothing while every other target is unaffected.
|
|
290
|
+
*/
|
|
291
|
+
publicDataApiKey?: string;
|
|
292
|
+
/**
|
|
293
|
+
* LLM prompt overrides (optional).
|
|
294
|
+
*
|
|
295
|
+
* When provided, this replaces Research Radar's own prompt provider entirely
|
|
296
|
+
* rather than merging with it. Omit it to use the package's tuned prompts,
|
|
297
|
+
* which in turn fall back to core's defaults for any stage they do not define.
|
|
298
|
+
*/
|
|
299
|
+
promptProvider?: PromptProvider;
|
|
229
300
|
}
|
|
230
301
|
/**
|
|
231
302
|
* Newsletter generation execution function
|
|
@@ -419,6 +490,22 @@ declare class ContentGenerateProvider implements ContentGenerateProvider$1 {
|
|
|
419
490
|
}>;
|
|
420
491
|
}
|
|
421
492
|
|
|
493
|
+
type HeritageBidCandidate = {
|
|
494
|
+
/** Issuing and requesting institutions, joined. */
|
|
495
|
+
institution: string;
|
|
496
|
+
/** Notice title. */
|
|
497
|
+
title: string;
|
|
498
|
+
/** `pubPrcrmntMidClsfcNm`, when the notice carries one. */
|
|
499
|
+
classification?: string | null;
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Decides which 나라장터 notices are worth scoring, one batch at a time.
|
|
504
|
+
*
|
|
505
|
+
* Returns one verdict per candidate, in the order they were given.
|
|
506
|
+
*/
|
|
507
|
+
type HeritageBidTriage = (candidates: HeritageBidCandidate[], signal?: AbortSignal) => Promise<boolean[]>;
|
|
508
|
+
|
|
422
509
|
/**
|
|
423
510
|
* Crawling provider implementation
|
|
424
511
|
* - Defines crawling targets
|
|
@@ -433,7 +520,7 @@ declare class CrawlingProvider implements CrawlingProvider$1 {
|
|
|
433
520
|
customFetch?: typeof fetch;
|
|
434
521
|
/** Crawling target groups configuration */
|
|
435
522
|
crawlingTargetGroups: CrawlingTargetGroup[];
|
|
436
|
-
constructor(articleRepository: ArticleRepository, customFetch?: typeof fetch);
|
|
523
|
+
constructor(articleRepository: ArticleRepository, customFetch?: typeof fetch, excavationReportSource?: ExcavationReportSource, logger?: AppLogger, publicDataApiKey?: string, bidTriage?: HeritageBidTriage);
|
|
437
524
|
/**
|
|
438
525
|
* Fetch existing articles by URLs to avoid duplicate crawling
|
|
439
526
|
* @param articleUrls - URLs to check
|
|
@@ -489,6 +576,38 @@ declare const contentOptions: ContentOptions;
|
|
|
489
576
|
* Newsletter brand configuration
|
|
490
577
|
*/
|
|
491
578
|
declare const newsletterConfig: NewsletterConfig;
|
|
579
|
+
/**
|
|
580
|
+
* Maximum importance score per heritage domain (`tag1`).
|
|
581
|
+
*
|
|
582
|
+
* The newsletter is archaeology-first: archaeology and cultural heritage keep
|
|
583
|
+
* the full 1-10 range, while natural and intangible heritage are capped so they
|
|
584
|
+
* cannot crowd out archaeological coverage. `기타` — material that is not
|
|
585
|
+
* heritage at all — is capped lowest, because the scoring prompt's academic-value
|
|
586
|
+
* floor is domain-blind and would otherwise lift things like a general journal's
|
|
587
|
+
* call for papers into the top half of the scale.
|
|
588
|
+
*
|
|
589
|
+
* The cap is applied deterministically after scoring, in
|
|
590
|
+
* `AnalysisProvider.update()`, rather than asked for in the prompt, so the
|
|
591
|
+
* ceiling always holds. It never reaches 1: a score of 1 means "exclude from the
|
|
592
|
+
* newsletter" in the consuming application's candidate query, so capping to 1
|
|
593
|
+
* would delete these articles instead of demoting them.
|
|
594
|
+
*
|
|
595
|
+
* Domains absent from this map are not capped.
|
|
596
|
+
*/
|
|
597
|
+
declare const maximumImportanceScoreByDomain: Record<string, number>;
|
|
598
|
+
/**
|
|
599
|
+
* Origins exempted from the robots.txt check.
|
|
600
|
+
*
|
|
601
|
+
* Each entry deliberately overrides what the site publishes, so it needs a
|
|
602
|
+
* reason and should be revisited when that site's robots.txt changes.
|
|
603
|
+
*
|
|
604
|
+
* - `http://www.yngogo.or.kr` (영남고고학회): its board is rendered from
|
|
605
|
+
* `/module/ntt/unity/selectNttListAjax.ink`, and robots.txt carries a blanket
|
|
606
|
+
* `Disallow: /module`. The rule reads as protecting an internal path rather
|
|
607
|
+
* than the public board it happens to serve, and there is no other route to
|
|
608
|
+
* the listing, so the society's boards are collected under this exemption.
|
|
609
|
+
*/
|
|
610
|
+
declare const robotsExemptOrigins: readonly string[];
|
|
492
611
|
/**
|
|
493
612
|
* LLM configuration
|
|
494
613
|
*/
|
|
@@ -500,5 +619,35 @@ declare const llmConfig: {
|
|
|
500
619
|
};
|
|
501
620
|
};
|
|
502
621
|
|
|
503
|
-
|
|
504
|
-
|
|
622
|
+
/**
|
|
623
|
+
* Research Radar's LLM prompt overrides.
|
|
624
|
+
*
|
|
625
|
+
* Each builder here **replaces** core's built-in prompt for that stage rather
|
|
626
|
+
* than extending it — a `PromptBuilder` returns the whole prompt string. That is
|
|
627
|
+
* deliberate: core's defaults instruct the model to use emoticons, render
|
|
628
|
+
* importance as star ratings, and add share-of-coverage statistics, all of which
|
|
629
|
+
* this newsletter removes. Appending contradicting rules to those defaults
|
|
630
|
+
* degrades the output, so a replacement is written from scratch instead.
|
|
631
|
+
*
|
|
632
|
+
* **Contract a replacement must still satisfy.** Core's output schema is fixed,
|
|
633
|
+
* and `generateNewsletter` regenerates the whole newsletter whenever the model
|
|
634
|
+
* reports a failure. A replacement prompt has to steer the model toward:
|
|
635
|
+
*
|
|
636
|
+
* - `title`: 20–70 characters
|
|
637
|
+
* - `isWrittenInOutputLanguage`, `copyrightVerified`, `factAccuracy`: true
|
|
638
|
+
* - `titleContext` (KRAS mode): the phrase must appear in the title
|
|
639
|
+
*
|
|
640
|
+
* Core caps that loop at 5 attempts, so a prompt that ignores the contract costs
|
|
641
|
+
* up to 5 full generations on the most expensive model in the pipeline.
|
|
642
|
+
*
|
|
643
|
+
* Tune these against real articles with core's playground
|
|
644
|
+
* (`npm run playground:generate-newsletter` in ../llm-newsletter-kit-core) and
|
|
645
|
+
* diff them against the defaults for free with `playground:verify-prompts`.
|
|
646
|
+
* The playground loads this module from `dist`, so run `npm run build` here
|
|
647
|
+
* after every edit — its source cannot be imported directly across repos
|
|
648
|
+
* because of the `~/*` path alias.
|
|
649
|
+
*/
|
|
650
|
+
declare const researchRadarPromptProvider: PromptProvider;
|
|
651
|
+
|
|
652
|
+
export { AnalysisProvider, ContentGenerateProvider, CrawlingProvider, DateService, TaskService, contentOptions, createCrawlingTargetGroups, generateNewsletter, generateWelcomeHTML, getSourceList, llmConfig, maximumImportanceScoreByDomain, newsletterConfig, researchRadarPromptProvider, robotsExemptOrigins };
|
|
653
|
+
export type { ArticleRepository, ContentGenerationConfig, ContentOptions, ExcavationReport, ExcavationReportSource, NewsletterConfig, NewsletterGeneratorDependencies, NewsletterRepository, NewsletterTemplateOptions, PreviewNewsletterOptions, SourceGroup, SourceItem, TagRepository, TaskRepository, WelcomeTemplateOptions };
|