mdcontext 0.0.1 → 0.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/.changeset/README.md +28 -0
- package/.changeset/config.json +11 -0
- package/.claude/settings.local.json +25 -0
- package/.github/workflows/ci.yml +83 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +85 -0
- package/.github/workflows/release.yml +113 -0
- package/.tldrignore +112 -0
- package/BACKLOG.md +338 -0
- package/CONTRIBUTING.md +186 -0
- package/NOTES/NOTES +44 -0
- package/README.md +434 -11
- package/biome.json +36 -0
- package/cspell.config.yaml +14 -0
- package/dist/chunk-23UPXDNL.js +3044 -0
- package/dist/chunk-2W7MO2DL.js +1366 -0
- package/dist/chunk-3NUAZGMA.js +1689 -0
- package/dist/chunk-7TOWB2XB.js +366 -0
- package/dist/chunk-7XOTOADQ.js +3065 -0
- package/dist/chunk-AH2PDM2K.js +3042 -0
- package/dist/chunk-BNXWSZ63.js +3742 -0
- package/dist/chunk-BTL5DJVU.js +3222 -0
- package/dist/chunk-HDHYG7E4.js +104 -0
- package/dist/chunk-HLR4KZBP.js +3234 -0
- package/dist/chunk-IP3FRFEB.js +1045 -0
- package/dist/chunk-KHU56VDO.js +3042 -0
- package/dist/chunk-KRYIFLQR.js +88 -0
- package/dist/chunk-LBSDNLEM.js +287 -0
- package/dist/chunk-MNTQ7HCP.js +2643 -0
- package/dist/chunk-MUJELQQ6.js +1387 -0
- package/dist/chunk-MXJGMSLV.js +2199 -0
- package/dist/chunk-N6QJGC3Z.js +2636 -0
- package/dist/chunk-OBELGBPM.js +1713 -0
- package/dist/chunk-OT7R5XTA.js +3192 -0
- package/dist/chunk-P7X4RA2T.js +106 -0
- package/dist/chunk-PIDUQNC2.js +3185 -0
- package/dist/chunk-POGCDIH4.js +3187 -0
- package/dist/chunk-PSIEOQGZ.js +3043 -0
- package/dist/chunk-PVRT3IHA.js +3238 -0
- package/dist/chunk-QNN4TT23.js +1430 -0
- package/dist/chunk-RE3R45RJ.js +3042 -0
- package/dist/chunk-S7E6TFX6.js +803 -0
- package/dist/chunk-SG6GLU4U.js +1378 -0
- package/dist/chunk-SJCDV2ST.js +274 -0
- package/dist/chunk-SYE5XLF3.js +104 -0
- package/dist/chunk-T5VLYBZD.js +103 -0
- package/dist/chunk-TOQB7VWU.js +3238 -0
- package/dist/chunk-VFNMZ4ZQ.js +3228 -0
- package/dist/chunk-VVTGZNBT.js +1629 -0
- package/dist/chunk-W7Q4RFEV.js +104 -0
- package/dist/chunk-XTYYVRLO.js +3190 -0
- package/dist/chunk-Y6MDYVJD.js +3063 -0
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +5458 -0
- package/dist/index.d.ts +653 -0
- package/dist/index.js +79 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +472 -0
- package/dist/schema-BAWSG7KY.js +22 -0
- package/dist/schema-E3QUPL26.js +20 -0
- package/dist/schema-EHL7WUT6.js +20 -0
- package/docs/019-USAGE.md +625 -0
- package/docs/020-current-implementation.md +364 -0
- package/docs/021-DOGFOODING-FINDINGS.md +175 -0
- package/docs/BACKLOG.md +80 -0
- package/docs/CONFIG.md +1123 -0
- package/docs/DESIGN.md +439 -0
- package/docs/ERRORS.md +383 -0
- package/docs/PROJECT.md +88 -0
- package/docs/ROADMAP.md +407 -0
- package/docs/summarization.md +320 -0
- package/docs/test-links.md +9 -0
- package/justfile +40 -0
- package/package.json +74 -9
- package/pnpm-workspace.yaml +5 -0
- package/research/INDEX.md +315 -0
- package/research/code-review/README.md +90 -0
- package/research/code-review/cli-error-handling-review.md +979 -0
- package/research/code-review/code-review-validation-report.md +464 -0
- package/research/code-review/main-ts-review.md +1128 -0
- package/research/config-analysis/01-current-implementation.md +470 -0
- package/research/config-analysis/02-strategy-recommendation.md +428 -0
- package/research/config-analysis/03-task-candidates.md +715 -0
- package/research/config-analysis/033-research-configuration-management.md +828 -0
- package/research/config-analysis/034-research-effect-cli-config.md +1504 -0
- package/research/config-analysis/04-consolidated-task-candidates.md +277 -0
- package/research/config-docs/SUMMARY.md +357 -0
- package/research/config-docs/TEST-RESULTS.md +776 -0
- package/research/config-docs/TODO.md +542 -0
- package/research/config-docs/analysis.md +744 -0
- package/research/config-docs/fix-validation.md +502 -0
- package/research/config-docs/help-audit.md +264 -0
- package/research/config-docs/help-system-analysis.md +890 -0
- package/research/dogfood/consolidated-tool-evaluation.md +373 -0
- package/research/dogfood/strategy-a/a-synthesis.md +184 -0
- package/research/dogfood/strategy-a/a1-docs.md +226 -0
- package/research/dogfood/strategy-a/a2-amorphic.md +156 -0
- package/research/dogfood/strategy-a/a3-llm.md +164 -0
- package/research/dogfood/strategy-b/b-synthesis.md +228 -0
- package/research/dogfood/strategy-b/b1-architecture.md +207 -0
- package/research/dogfood/strategy-b/b2-gaps.md +258 -0
- package/research/dogfood/strategy-b/b3-workflows.md +250 -0
- package/research/dogfood/strategy-c/c-synthesis.md +451 -0
- package/research/dogfood/strategy-c/c1-explorer.md +192 -0
- package/research/dogfood/strategy-c/c2-diver-memory.md +145 -0
- package/research/dogfood/strategy-c/c3-diver-control.md +148 -0
- package/research/dogfood/strategy-c/c4-diver-failure.md +151 -0
- package/research/dogfood/strategy-c/c5-diver-execution.md +221 -0
- package/research/dogfood/strategy-c/c6-diver-org.md +221 -0
- package/research/effect-cli-error-handling.md +845 -0
- package/research/effect-errors-as-values.md +943 -0
- package/research/errors-task-analysis/00-consolidated-tasks.md +207 -0
- package/research/errors-task-analysis/cli-commands-analysis.md +909 -0
- package/research/errors-task-analysis/embeddings-analysis.md +709 -0
- package/research/errors-task-analysis/index-search-analysis.md +812 -0
- package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
- package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
- package/research/issue-review.md +603 -0
- package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
- package/research/llm-summarization/alternative-providers-2026.md +1428 -0
- package/research/llm-summarization/anthropic-2026.md +367 -0
- package/research/llm-summarization/claude-cli-integration.md +1706 -0
- package/research/llm-summarization/cli-integration-patterns.md +3155 -0
- package/research/llm-summarization/openai-2026.md +473 -0
- package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
- package/research/llm-summarization/opencode-cli-integration.md +1552 -0
- package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
- package/research/llm-summarization/prototype-results.md +56 -0
- package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
- package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
- package/research/mdcontext-error-analysis.md +521 -0
- package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
- package/research/mdcontext-pudding/01-index-embed.md +956 -0
- package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
- package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
- package/research/mdcontext-pudding/02-search.md +970 -0
- package/research/mdcontext-pudding/03-context.md +779 -0
- package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
- package/research/mdcontext-pudding/04-tree.md +704 -0
- package/research/mdcontext-pudding/05-config.md +1038 -0
- package/research/mdcontext-pudding/06-links-summary.txt +87 -0
- package/research/mdcontext-pudding/06-links.md +679 -0
- package/research/mdcontext-pudding/07-stats.md +693 -0
- package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
- package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
- package/research/mdcontext-pudding/README.md +168 -0
- package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
- package/research/npm_publish/011-npm-workflow-research-agent2.md +792 -0
- package/research/npm_publish/012-npm-workflow-research-agent1.md +530 -0
- package/research/npm_publish/013-npm-workflow-research-agent3.md +722 -0
- package/research/npm_publish/014-npm-workflow-synthesis.md +556 -0
- package/research/npm_publish/031-npm-workflow-task-analysis.md +134 -0
- package/research/research-quality-review.md +834 -0
- package/research/semantic-search/002-research-embedding-models.md +490 -0
- package/research/semantic-search/003-research-rag-alternatives.md +523 -0
- package/research/semantic-search/004-research-vector-search.md +841 -0
- package/research/semantic-search/032-research-semantic-search.md +427 -0
- package/research/semantic-search/embedding-text-analysis.md +156 -0
- package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
- package/research/semantic-search/query-processing-analysis.md +207 -0
- package/research/semantic-search/root-cause-and-solution.md +114 -0
- package/research/semantic-search/threshold-validation-report.md +69 -0
- package/research/semantic-search/vector-search-analysis.md +63 -0
- package/research/task-management-2026/00-synthesis-recommendations.md +295 -0
- package/research/task-management-2026/01-ai-workflow-tools.md +416 -0
- package/research/task-management-2026/02-agent-framework-patterns.md +476 -0
- package/research/task-management-2026/03-lightweight-file-based.md +567 -0
- package/research/task-management-2026/04-established-tools-ai-features.md +541 -0
- package/research/task-management-2026/linear/01-core-features-workflow.md +771 -0
- package/research/task-management-2026/linear/02-api-integrations.md +930 -0
- package/research/task-management-2026/linear/03-ai-features.md +368 -0
- package/research/task-management-2026/linear/04-pricing-setup.md +205 -0
- package/research/task-management-2026/linear/05-usage-patterns-best-practices.md +605 -0
- package/research/test-path-issues.md +276 -0
- package/review/ALP-76/1-error-type-design.md +962 -0
- package/review/ALP-76/2-error-handling-patterns.md +906 -0
- package/review/ALP-76/3-error-presentation.md +624 -0
- package/review/ALP-76/4-test-coverage.md +625 -0
- package/review/ALP-76/5-migration-completeness.md +440 -0
- package/review/ALP-76/6-effect-best-practices.md +755 -0
- package/scripts/apply-branch-protection.sh +47 -0
- package/scripts/branch-protection-templates.json +79 -0
- package/scripts/prototype-summarization.ts +346 -0
- package/scripts/rebuild-hnswlib.js +58 -0
- package/scripts/setup-branch-protection.sh +64 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
- package/src/cli/argv-preprocessor.test.ts +210 -0
- package/src/cli/argv-preprocessor.ts +202 -0
- package/src/cli/cli.test.ts +627 -0
- package/src/cli/commands/backlinks.ts +54 -0
- package/src/cli/commands/config-cmd.ts +642 -0
- package/src/cli/commands/context.ts +285 -0
- package/src/cli/commands/duplicates.ts +122 -0
- package/src/cli/commands/embeddings.ts +529 -0
- package/src/cli/commands/index-cmd.ts +480 -0
- package/src/cli/commands/index.ts +16 -0
- package/src/cli/commands/links.ts +52 -0
- package/src/cli/commands/search.ts +1281 -0
- package/src/cli/commands/stats.ts +149 -0
- package/src/cli/commands/tree.ts +128 -0
- package/src/cli/config-layer.ts +176 -0
- package/src/cli/error-handler.test.ts +235 -0
- package/src/cli/error-handler.ts +655 -0
- package/src/cli/flag-schemas.ts +341 -0
- package/src/cli/help.ts +588 -0
- package/src/cli/index.ts +9 -0
- package/src/cli/main.ts +435 -0
- package/src/cli/options.ts +41 -0
- package/src/cli/shared-error-handling.ts +199 -0
- package/src/cli/typo-suggester.test.ts +105 -0
- package/src/cli/typo-suggester.ts +130 -0
- package/src/cli/utils.ts +259 -0
- package/src/config/file-provider.test.ts +320 -0
- package/src/config/file-provider.ts +273 -0
- package/src/config/index.ts +72 -0
- package/src/config/integration.test.ts +667 -0
- package/src/config/precedence.test.ts +277 -0
- package/src/config/precedence.ts +451 -0
- package/src/config/schema.test.ts +414 -0
- package/src/config/schema.ts +603 -0
- package/src/config/service.test.ts +320 -0
- package/src/config/service.ts +243 -0
- package/src/config/testing.test.ts +264 -0
- package/src/config/testing.ts +110 -0
- package/src/core/index.ts +1 -0
- package/src/core/types.ts +113 -0
- package/src/duplicates/detector.test.ts +183 -0
- package/src/duplicates/detector.ts +414 -0
- package/src/duplicates/index.ts +18 -0
- package/src/embeddings/embedding-namespace.test.ts +300 -0
- package/src/embeddings/embedding-namespace.ts +947 -0
- package/src/embeddings/heading-boost.test.ts +222 -0
- package/src/embeddings/hnsw-build-options.test.ts +198 -0
- package/src/embeddings/hyde.test.ts +272 -0
- package/src/embeddings/hyde.ts +264 -0
- package/src/embeddings/index.ts +10 -0
- package/src/embeddings/openai-provider.ts +414 -0
- package/src/embeddings/pricing.json +22 -0
- package/src/embeddings/provider-constants.ts +204 -0
- package/src/embeddings/provider-errors.test.ts +967 -0
- package/src/embeddings/provider-errors.ts +565 -0
- package/src/embeddings/provider-factory.test.ts +240 -0
- package/src/embeddings/provider-factory.ts +225 -0
- package/src/embeddings/provider-integration.test.ts +788 -0
- package/src/embeddings/query-preprocessing.test.ts +187 -0
- package/src/embeddings/semantic-search-threshold.test.ts +508 -0
- package/src/embeddings/semantic-search.ts +1270 -0
- package/src/embeddings/types.ts +359 -0
- package/src/embeddings/vector-store.ts +708 -0
- package/src/embeddings/voyage-provider.ts +313 -0
- package/src/errors/errors.test.ts +845 -0
- package/src/errors/index.ts +533 -0
- package/src/index/ignore-patterns.test.ts +354 -0
- package/src/index/ignore-patterns.ts +305 -0
- package/src/index/index.ts +4 -0
- package/src/index/indexer.ts +684 -0
- package/src/index/storage.ts +260 -0
- package/src/index/types.ts +147 -0
- package/src/index/watcher.ts +189 -0
- package/src/index.ts +30 -0
- package/src/integration/search-keyword.test.ts +678 -0
- package/src/mcp/server.ts +612 -0
- package/src/parser/index.ts +1 -0
- package/src/parser/parser.test.ts +291 -0
- package/src/parser/parser.ts +394 -0
- package/src/parser/section-filter.test.ts +277 -0
- package/src/parser/section-filter.ts +392 -0
- package/src/search/__tests__/hybrid-search.test.ts +650 -0
- package/src/search/bm25-store.ts +366 -0
- package/src/search/cross-encoder.test.ts +253 -0
- package/src/search/cross-encoder.ts +406 -0
- package/src/search/fuzzy-search.test.ts +419 -0
- package/src/search/fuzzy-search.ts +273 -0
- package/src/search/hybrid-search.ts +448 -0
- package/src/search/path-matcher.test.ts +276 -0
- package/src/search/path-matcher.ts +33 -0
- package/src/search/query-parser.test.ts +260 -0
- package/src/search/query-parser.ts +319 -0
- package/src/search/searcher.test.ts +280 -0
- package/src/search/searcher.ts +724 -0
- package/src/search/wink-bm25.d.ts +30 -0
- package/src/summarization/cli-providers/claude.ts +202 -0
- package/src/summarization/cli-providers/detection.test.ts +273 -0
- package/src/summarization/cli-providers/detection.ts +118 -0
- package/src/summarization/cli-providers/index.ts +8 -0
- package/src/summarization/cost.test.ts +139 -0
- package/src/summarization/cost.ts +102 -0
- package/src/summarization/error-handler.test.ts +127 -0
- package/src/summarization/error-handler.ts +111 -0
- package/src/summarization/index.ts +102 -0
- package/src/summarization/pipeline.test.ts +498 -0
- package/src/summarization/pipeline.ts +231 -0
- package/src/summarization/prompts.test.ts +269 -0
- package/src/summarization/prompts.ts +133 -0
- package/src/summarization/provider-factory.test.ts +396 -0
- package/src/summarization/provider-factory.ts +178 -0
- package/src/summarization/types.ts +184 -0
- package/src/summarize/budget-bugs.test.ts +620 -0
- package/src/summarize/formatters.ts +419 -0
- package/src/summarize/index.ts +20 -0
- package/src/summarize/summarizer.test.ts +275 -0
- package/src/summarize/summarizer.ts +597 -0
- package/src/summarize/verify-bugs.test.ts +238 -0
- package/src/types/huggingface-transformers.d.ts +66 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/tokens.test.ts +142 -0
- package/src/utils/tokens.ts +186 -0
- package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
- package/tests/fixtures/cli/.mdcontext/config.json +8 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/indexes/documents.json +33 -0
- package/tests/fixtures/cli/.mdcontext/indexes/links.json +12 -0
- package/tests/fixtures/cli/.mdcontext/indexes/sections.json +247 -0
- package/tests/fixtures/cli/README.md +9 -0
- package/tests/fixtures/cli/api-reference.md +11 -0
- package/tests/fixtures/cli/getting-started.md +11 -0
- package/tests/integration/embed-index.test.ts +712 -0
- package/tests/integration/search-context.test.ts +469 -0
- package/tests/integration/search-semantic.test.ts +522 -0
- package/tsconfig.json +26 -0
- package/vitest.config.ts +16 -0
- package/vitest.setup.ts +12 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Cost Estimation Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest'
|
|
6
|
+
import {
|
|
7
|
+
API_PRICING,
|
|
8
|
+
estimateSummaryCost,
|
|
9
|
+
estimateTokens,
|
|
10
|
+
formatCostDisplay,
|
|
11
|
+
} from './cost.js'
|
|
12
|
+
|
|
13
|
+
describe('estimateTokens', () => {
|
|
14
|
+
it('should estimate ~4 chars per token', () => {
|
|
15
|
+
expect(estimateTokens('test')).toBe(1)
|
|
16
|
+
expect(estimateTokens('testtest')).toBe(2)
|
|
17
|
+
expect(estimateTokens('x'.repeat(100))).toBe(25)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('should round up partial tokens', () => {
|
|
21
|
+
expect(estimateTokens('abc')).toBe(1) // 0.75 -> 1
|
|
22
|
+
expect(estimateTokens('abcde')).toBe(2) // 1.25 -> 2
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should handle empty string', () => {
|
|
26
|
+
expect(estimateTokens('')).toBe(0)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('estimateSummaryCost', () => {
|
|
31
|
+
describe('CLI providers (free)', () => {
|
|
32
|
+
it('should return isPaid=false for CLI mode', () => {
|
|
33
|
+
const result = estimateSummaryCost('test input', 'cli', 'claude')
|
|
34
|
+
expect(result.isPaid).toBe(false)
|
|
35
|
+
expect(result.estimatedCost).toBe(0)
|
|
36
|
+
expect(result.formattedCost).toBe('FREE (subscription)')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should still estimate tokens for CLI mode', () => {
|
|
40
|
+
const input = 'x'.repeat(400) // ~100 tokens
|
|
41
|
+
const result = estimateSummaryCost(input, 'cli', 'claude')
|
|
42
|
+
expect(result.inputTokens).toBe(100)
|
|
43
|
+
expect(result.outputTokens).toBe(500) // default
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe('API providers (paid)', () => {
|
|
48
|
+
it('should calculate cost for DeepSeek', () => {
|
|
49
|
+
const input = 'x'.repeat(4000) // ~1000 tokens
|
|
50
|
+
const result = estimateSummaryCost(input, 'api', 'deepseek', 500)
|
|
51
|
+
|
|
52
|
+
expect(result.inputTokens).toBe(1000)
|
|
53
|
+
expect(result.outputTokens).toBe(500)
|
|
54
|
+
expect(result.isPaid).toBe(true)
|
|
55
|
+
// Input: 1000 * 0.14 / 1M = 0.00014
|
|
56
|
+
// Output: 500 * 0.56 / 1M = 0.00028
|
|
57
|
+
// Total: 0.00042
|
|
58
|
+
expect(result.estimatedCost).toBeCloseTo(0.00042, 5)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should calculate cost for Anthropic (more expensive)', () => {
|
|
62
|
+
const input = 'x'.repeat(4000) // ~1000 tokens
|
|
63
|
+
const result = estimateSummaryCost(input, 'api', 'anthropic', 500)
|
|
64
|
+
|
|
65
|
+
expect(result.isPaid).toBe(true)
|
|
66
|
+
// Input: 1000 * 3.0 / 1M = 0.003
|
|
67
|
+
// Output: 500 * 15.0 / 1M = 0.0075
|
|
68
|
+
// Total: 0.0105
|
|
69
|
+
expect(result.estimatedCost).toBeCloseTo(0.0105, 4)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('should calculate cost for OpenAI', () => {
|
|
73
|
+
const input = 'x'.repeat(4000)
|
|
74
|
+
const result = estimateSummaryCost(input, 'api', 'openai', 500)
|
|
75
|
+
|
|
76
|
+
expect(result.isPaid).toBe(true)
|
|
77
|
+
// Input: 1000 * 1.75 / 1M = 0.00175
|
|
78
|
+
// Output: 500 * 14.0 / 1M = 0.007
|
|
79
|
+
// Total: 0.00875
|
|
80
|
+
expect(result.estimatedCost).toBeCloseTo(0.00875, 5)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('should handle CLI provider used with API mode (falls back to deepseek pricing)', () => {
|
|
84
|
+
const input = 'x'.repeat(4000)
|
|
85
|
+
// When a CLI provider is used with API mode, it falls back to deepseek pricing
|
|
86
|
+
const result = estimateSummaryCost(input, 'api', 'claude', 500)
|
|
87
|
+
|
|
88
|
+
expect(result.isPaid).toBe(true)
|
|
89
|
+
expect(result.estimatedCost).toBeCloseTo(0.00042, 5)
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
describe('provider comparison', () => {
|
|
94
|
+
it('should show Qwen as cheapest API provider', () => {
|
|
95
|
+
const input = 'x'.repeat(4000)
|
|
96
|
+
const qwen = estimateSummaryCost(input, 'api', 'qwen', 500)
|
|
97
|
+
const deepseek = estimateSummaryCost(input, 'api', 'deepseek', 500)
|
|
98
|
+
const anthropic = estimateSummaryCost(input, 'api', 'anthropic', 500)
|
|
99
|
+
|
|
100
|
+
expect(qwen.estimatedCost).toBeLessThan(deepseek.estimatedCost)
|
|
101
|
+
expect(deepseek.estimatedCost).toBeLessThan(anthropic.estimatedCost)
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('formatCostDisplay', () => {
|
|
107
|
+
it('should format free CLI cost', () => {
|
|
108
|
+
const estimate = estimateSummaryCost('test', 'cli', 'claude')
|
|
109
|
+
const display = formatCostDisplay(estimate)
|
|
110
|
+
expect(display).toContain('FREE')
|
|
111
|
+
expect(display).toContain('claude')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should format paid API cost', () => {
|
|
115
|
+
const estimate = estimateSummaryCost('test', 'api', 'deepseek')
|
|
116
|
+
const display = formatCostDisplay(estimate)
|
|
117
|
+
expect(display).toContain('Estimated cost')
|
|
118
|
+
expect(display).toContain('$')
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('API_PRICING', () => {
|
|
123
|
+
it('should have all expected providers', () => {
|
|
124
|
+
expect(API_PRICING.deepseek).toBeDefined()
|
|
125
|
+
expect(API_PRICING.qwen).toBeDefined()
|
|
126
|
+
expect(API_PRICING.anthropic).toBeDefined()
|
|
127
|
+
expect(API_PRICING.openai).toBeDefined()
|
|
128
|
+
expect(API_PRICING.gemini).toBeDefined()
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should have valid pricing (input < output)', () => {
|
|
132
|
+
for (const pricing of Object.values(API_PRICING)) {
|
|
133
|
+
expect(pricing.input).toBeGreaterThan(0)
|
|
134
|
+
expect(pricing.output).toBeGreaterThan(0)
|
|
135
|
+
// Output tokens typically cost more
|
|
136
|
+
expect(pricing.output).toBeGreaterThanOrEqual(pricing.input)
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
})
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Estimation for AI Summarization
|
|
3
|
+
*
|
|
4
|
+
* Provides cost estimates for API providers before running queries.
|
|
5
|
+
* CLI providers are free (subscription-based), so cost is always 0.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
APIProviderName,
|
|
10
|
+
CLIProviderName,
|
|
11
|
+
SummarizationMode,
|
|
12
|
+
} from './types.js'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Type guard to check if a provider is an API provider
|
|
16
|
+
*/
|
|
17
|
+
const isAPIProvider = (provider: string): provider is APIProviderName => {
|
|
18
|
+
return ['deepseek', 'anthropic', 'openai', 'gemini', 'qwen'].includes(
|
|
19
|
+
provider,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pricing per 1 million tokens for each provider.
|
|
25
|
+
* Values as of January 2026.
|
|
26
|
+
*/
|
|
27
|
+
export const API_PRICING: Record<
|
|
28
|
+
APIProviderName,
|
|
29
|
+
{ input: number; output: number; displayName: string }
|
|
30
|
+
> = {
|
|
31
|
+
deepseek: { input: 0.14, output: 0.56, displayName: 'DeepSeek' },
|
|
32
|
+
qwen: { input: 0.03, output: 0.12, displayName: 'Qwen' },
|
|
33
|
+
anthropic: { input: 3.0, output: 15.0, displayName: 'Anthropic Claude' },
|
|
34
|
+
openai: { input: 1.75, output: 14.0, displayName: 'OpenAI GPT' },
|
|
35
|
+
gemini: { input: 0.3, output: 2.5, displayName: 'Google Gemini' },
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Cost estimate result
|
|
40
|
+
*/
|
|
41
|
+
export interface CostEstimate {
|
|
42
|
+
readonly inputTokens: number
|
|
43
|
+
readonly outputTokens: number
|
|
44
|
+
readonly estimatedCost: number
|
|
45
|
+
readonly provider: string
|
|
46
|
+
readonly isPaid: boolean
|
|
47
|
+
readonly formattedCost: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Simple token estimation (4 chars ≈ 1 token).
|
|
52
|
+
*/
|
|
53
|
+
export const estimateTokens = (text: string): number => {
|
|
54
|
+
return Math.ceil(text.length / 4)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Estimate the cost of summarizing text.
|
|
59
|
+
*/
|
|
60
|
+
export const estimateSummaryCost = (
|
|
61
|
+
input: string,
|
|
62
|
+
mode: SummarizationMode,
|
|
63
|
+
provider: CLIProviderName | APIProviderName,
|
|
64
|
+
maxOutputTokens: number = 500,
|
|
65
|
+
): CostEstimate => {
|
|
66
|
+
const inputTokens = estimateTokens(input)
|
|
67
|
+
|
|
68
|
+
if (mode === 'cli') {
|
|
69
|
+
return {
|
|
70
|
+
inputTokens,
|
|
71
|
+
outputTokens: maxOutputTokens,
|
|
72
|
+
estimatedCost: 0,
|
|
73
|
+
provider,
|
|
74
|
+
isPaid: false,
|
|
75
|
+
formattedCost: 'FREE (subscription)',
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// For API mode, use API pricing (default to deepseek if provider not found)
|
|
80
|
+
const pricing = isAPIProvider(provider)
|
|
81
|
+
? API_PRICING[provider]
|
|
82
|
+
: API_PRICING.deepseek
|
|
83
|
+
const inputCost = (inputTokens * pricing.input) / 1_000_000
|
|
84
|
+
const outputCost = (maxOutputTokens * pricing.output) / 1_000_000
|
|
85
|
+
const totalCost = inputCost + outputCost
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
inputTokens,
|
|
89
|
+
outputTokens: maxOutputTokens,
|
|
90
|
+
estimatedCost: totalCost,
|
|
91
|
+
provider,
|
|
92
|
+
isPaid: true,
|
|
93
|
+
formattedCost: `$${totalCost.toFixed(4)}`,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const formatCostDisplay = (estimate: CostEstimate): string => {
|
|
98
|
+
if (!estimate.isPaid) {
|
|
99
|
+
return `Using ${estimate.provider} (subscription - FREE)`
|
|
100
|
+
}
|
|
101
|
+
return `Estimated cost: ${estimate.formattedCost}`
|
|
102
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Error Handler Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest'
|
|
6
|
+
import {
|
|
7
|
+
formatSummarizationError,
|
|
8
|
+
isRecoverableError,
|
|
9
|
+
} from './error-handler.js'
|
|
10
|
+
import { SummarizationError } from './types.js'
|
|
11
|
+
|
|
12
|
+
describe('formatSummarizationError', () => {
|
|
13
|
+
describe('SummarizationError handling', () => {
|
|
14
|
+
it('should format PROVIDER_NOT_AVAILABLE with install URL', () => {
|
|
15
|
+
const error = new SummarizationError(
|
|
16
|
+
'Claude not installed',
|
|
17
|
+
'PROVIDER_NOT_AVAILABLE',
|
|
18
|
+
'claude',
|
|
19
|
+
)
|
|
20
|
+
const message = formatSummarizationError(error)
|
|
21
|
+
|
|
22
|
+
expect(message).toContain('not available')
|
|
23
|
+
expect(message).toContain('https://claude.ai/download')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should format NO_API_KEY with env var hint', () => {
|
|
27
|
+
const error = new SummarizationError(
|
|
28
|
+
'API key missing',
|
|
29
|
+
'NO_API_KEY',
|
|
30
|
+
'deepseek',
|
|
31
|
+
)
|
|
32
|
+
const message = formatSummarizationError(error)
|
|
33
|
+
|
|
34
|
+
expect(message).toContain('API key')
|
|
35
|
+
expect(message).toContain('DEEPSEEK_API_KEY')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should format RATE_LIMITED with CLI suggestion', () => {
|
|
39
|
+
const error = new SummarizationError(
|
|
40
|
+
'Rate limit hit',
|
|
41
|
+
'RATE_LIMITED',
|
|
42
|
+
'openai',
|
|
43
|
+
)
|
|
44
|
+
const message = formatSummarizationError(error)
|
|
45
|
+
|
|
46
|
+
expect(message).toContain('Rate limit')
|
|
47
|
+
expect(message).toContain('CLI provider')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should format CLI_EXECUTION_FAILED with details', () => {
|
|
51
|
+
const error = new SummarizationError(
|
|
52
|
+
'Process exited with code 1',
|
|
53
|
+
'CLI_EXECUTION_FAILED',
|
|
54
|
+
'claude',
|
|
55
|
+
)
|
|
56
|
+
const message = formatSummarizationError(error)
|
|
57
|
+
|
|
58
|
+
expect(message).toContain('CLI error')
|
|
59
|
+
expect(message).toContain('Process exited with code 1')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should handle TIMEOUT errors', () => {
|
|
63
|
+
const error = new SummarizationError(
|
|
64
|
+
'Something went wrong',
|
|
65
|
+
'TIMEOUT',
|
|
66
|
+
'claude',
|
|
67
|
+
)
|
|
68
|
+
const message = formatSummarizationError(error)
|
|
69
|
+
|
|
70
|
+
expect(message).toContain('timed out')
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('generic Error handling', () => {
|
|
75
|
+
it('should extract message from regular Error', () => {
|
|
76
|
+
const error = new Error('Network failed')
|
|
77
|
+
const message = formatSummarizationError(error)
|
|
78
|
+
|
|
79
|
+
expect(message).toBe('Network failed')
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('unknown error handling', () => {
|
|
84
|
+
it('should handle null/undefined', () => {
|
|
85
|
+
expect(formatSummarizationError(null)).toBe(
|
|
86
|
+
'An unknown error occurred during summarization.',
|
|
87
|
+
)
|
|
88
|
+
expect(formatSummarizationError(undefined)).toBe(
|
|
89
|
+
'An unknown error occurred during summarization.',
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('isRecoverableError', () => {
|
|
96
|
+
it('should return true for API_REQUEST_FAILED', () => {
|
|
97
|
+
const error = new SummarizationError(
|
|
98
|
+
'Request failed',
|
|
99
|
+
'API_REQUEST_FAILED',
|
|
100
|
+
'deepseek',
|
|
101
|
+
)
|
|
102
|
+
expect(isRecoverableError(error)).toBe(true)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should return true for TIMEOUT', () => {
|
|
106
|
+
const error = new SummarizationError('Timed out', 'TIMEOUT', 'claude')
|
|
107
|
+
expect(isRecoverableError(error)).toBe(true)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('should return false for RATE_LIMITED', () => {
|
|
111
|
+
const error = new SummarizationError(
|
|
112
|
+
'Rate limited',
|
|
113
|
+
'RATE_LIMITED',
|
|
114
|
+
'openai',
|
|
115
|
+
)
|
|
116
|
+
expect(isRecoverableError(error)).toBe(false)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('should return false for NO_API_KEY', () => {
|
|
120
|
+
const error = new SummarizationError('No key', 'NO_API_KEY', 'anthropic')
|
|
121
|
+
expect(isRecoverableError(error)).toBe(false)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('should return false for non-SummarizationError', () => {
|
|
125
|
+
expect(isRecoverableError(new Error('Generic'))).toBe(false)
|
|
126
|
+
})
|
|
127
|
+
})
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handler for Summarization
|
|
3
|
+
*
|
|
4
|
+
* Provides user-friendly error messages and graceful degradation.
|
|
5
|
+
* Ensures summarization failures don't crash the CLI.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { SummarizationError, type SummarizationErrorCode } from './types.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Error message templates for different error codes.
|
|
12
|
+
*/
|
|
13
|
+
const ERROR_MESSAGES: Record<SummarizationErrorCode, string> = {
|
|
14
|
+
PROVIDER_NOT_FOUND: 'Summarization provider not found.',
|
|
15
|
+
PROVIDER_NOT_AVAILABLE:
|
|
16
|
+
'Summarization provider is not available. Check installation.',
|
|
17
|
+
CLI_EXECUTION_FAILED: 'CLI execution failed.',
|
|
18
|
+
API_REQUEST_FAILED: 'API request failed.',
|
|
19
|
+
RATE_LIMITED: 'Rate limit exceeded. Please try again later.',
|
|
20
|
+
INVALID_RESPONSE: 'Received invalid response from provider.',
|
|
21
|
+
TIMEOUT: 'Request timed out. Try again or reduce result count.',
|
|
22
|
+
NO_API_KEY: 'API key not configured.',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Installation URLs for CLI providers.
|
|
27
|
+
*/
|
|
28
|
+
const CLI_INSTALL_URLS: Record<string, string> = {
|
|
29
|
+
claude: 'https://claude.ai/download',
|
|
30
|
+
copilot: 'https://github.com/features/copilot',
|
|
31
|
+
opencode: 'https://github.com/opencode-ai/opencode',
|
|
32
|
+
aider: 'https://aider.chat',
|
|
33
|
+
cline: 'https://github.com/cline/cline',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Environment variable names for API keys.
|
|
38
|
+
*/
|
|
39
|
+
const API_KEY_ENV_VARS: Record<string, string> = {
|
|
40
|
+
deepseek: 'DEEPSEEK_API_KEY',
|
|
41
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
42
|
+
openai: 'OPENAI_API_KEY',
|
|
43
|
+
gemini: 'GOOGLE_API_KEY',
|
|
44
|
+
qwen: 'QWEN_API_KEY',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Format a SummarizationError into a user-friendly message.
|
|
49
|
+
*/
|
|
50
|
+
export const formatSummarizationError = (error: unknown): string => {
|
|
51
|
+
if (error instanceof SummarizationError) {
|
|
52
|
+
const baseMessage = ERROR_MESSAGES[error.code] ?? error.message
|
|
53
|
+
|
|
54
|
+
// Add provider-specific hints
|
|
55
|
+
if (error.code === 'PROVIDER_NOT_AVAILABLE' && error.provider) {
|
|
56
|
+
const installUrl = CLI_INSTALL_URLS[error.provider]
|
|
57
|
+
if (installUrl) {
|
|
58
|
+
return `${baseMessage}\n Install ${error.provider}: ${installUrl}`
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (error.code === 'NO_API_KEY' && error.provider) {
|
|
63
|
+
const envVar = API_KEY_ENV_VARS[error.provider]
|
|
64
|
+
if (envVar) {
|
|
65
|
+
return `${baseMessage}\n Set environment variable: ${envVar}`
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (error.code === 'RATE_LIMITED') {
|
|
70
|
+
return `${baseMessage}\n Try using a CLI provider (free with subscription) instead.`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (error.code === 'CLI_EXECUTION_FAILED' && error.message) {
|
|
74
|
+
// Include the actual error message for CLI failures
|
|
75
|
+
return `CLI error: ${error.message}`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return baseMessage
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (error instanceof Error) {
|
|
82
|
+
return error.message
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return 'An unknown error occurred during summarization.'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if an error is recoverable (can retry).
|
|
90
|
+
*/
|
|
91
|
+
export const isRecoverableError = (error: unknown): boolean => {
|
|
92
|
+
if (error instanceof SummarizationError) {
|
|
93
|
+
// These errors might succeed on retry
|
|
94
|
+
return ['API_REQUEST_FAILED', 'TIMEOUT'].includes(error.code)
|
|
95
|
+
}
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create a console-friendly error display.
|
|
101
|
+
*/
|
|
102
|
+
export const displaySummarizationError = (error: unknown): void => {
|
|
103
|
+
const message = formatSummarizationError(error)
|
|
104
|
+
|
|
105
|
+
console.error('')
|
|
106
|
+
console.error('Summarization failed:')
|
|
107
|
+
console.error(` ${message}`)
|
|
108
|
+
console.error('')
|
|
109
|
+
console.error(' Showing search results without summary.')
|
|
110
|
+
console.error('')
|
|
111
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarization Module
|
|
3
|
+
*
|
|
4
|
+
* AI-powered summarization of search results using CLI tools (free)
|
|
5
|
+
* or API providers (pay-per-use via Vercel AI SDK).
|
|
6
|
+
*
|
|
7
|
+
* ## Quick Start
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createSummarizer, buildPrompt } from './summarization/index.js'
|
|
11
|
+
*
|
|
12
|
+
* // Create a summarizer from config
|
|
13
|
+
* const summarizer = await createSummarizer({
|
|
14
|
+
* mode: 'cli',
|
|
15
|
+
* provider: 'claude',
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* // Build prompt with context
|
|
19
|
+
* const prompt = buildPrompt({
|
|
20
|
+
* query: 'authentication',
|
|
21
|
+
* resultCount: 10,
|
|
22
|
+
* searchMode: 'hybrid',
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* // Generate summary
|
|
26
|
+
* const result = await summarizer.summarize(searchResultsText, prompt)
|
|
27
|
+
* console.log(result.summary)
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* ## Architecture
|
|
31
|
+
*
|
|
32
|
+
* - **CLI Providers**: Free with subscription (Claude Code, Copilot, etc.)
|
|
33
|
+
* - **API Providers**: Pay-per-use via Vercel AI SDK (DeepSeek, OpenAI, etc.)
|
|
34
|
+
* - **Detection**: Auto-detect installed CLI tools
|
|
35
|
+
* - **Factory**: Create providers from config
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
// CLI providers
|
|
39
|
+
export {
|
|
40
|
+
ClaudeCLISummarizer,
|
|
41
|
+
detectInstalledCLIs,
|
|
42
|
+
getCLIInfo,
|
|
43
|
+
isCLIInstalled,
|
|
44
|
+
KNOWN_CLIS,
|
|
45
|
+
} from './cli-providers/index.js'
|
|
46
|
+
// Cost estimation
|
|
47
|
+
export type { CostEstimate } from './cost.js'
|
|
48
|
+
export {
|
|
49
|
+
API_PRICING,
|
|
50
|
+
estimateSummaryCost,
|
|
51
|
+
estimateTokens,
|
|
52
|
+
formatCostDisplay,
|
|
53
|
+
} from './cost.js'
|
|
54
|
+
// Error handling
|
|
55
|
+
export {
|
|
56
|
+
displaySummarizationError,
|
|
57
|
+
formatSummarizationError,
|
|
58
|
+
isRecoverableError,
|
|
59
|
+
} from './error-handler.js'
|
|
60
|
+
// Pipeline
|
|
61
|
+
export type {
|
|
62
|
+
PipelineOptions,
|
|
63
|
+
PipelineResult,
|
|
64
|
+
SummarizableResult,
|
|
65
|
+
} from './pipeline.js'
|
|
66
|
+
export {
|
|
67
|
+
formatResultsForSummary,
|
|
68
|
+
runSummarizationPipeline,
|
|
69
|
+
summarizeResults,
|
|
70
|
+
} from './pipeline.js'
|
|
71
|
+
// Prompts
|
|
72
|
+
export type { PromptTemplate, SearchContext } from './prompts.js'
|
|
73
|
+
export {
|
|
74
|
+
ACTIONABLE_PROMPT,
|
|
75
|
+
buildPrompt,
|
|
76
|
+
CONCISE_PROMPT,
|
|
77
|
+
DEFAULT_PROMPT,
|
|
78
|
+
DETAILED_PROMPT,
|
|
79
|
+
getPromptTemplate,
|
|
80
|
+
TECHNICAL_PROMPT,
|
|
81
|
+
} from './prompts.js'
|
|
82
|
+
// Provider factory
|
|
83
|
+
export {
|
|
84
|
+
createSummarizer,
|
|
85
|
+
getBestAvailableSummarizer,
|
|
86
|
+
} from './provider-factory.js'
|
|
87
|
+
// Core types
|
|
88
|
+
export type {
|
|
89
|
+
AISummarizationConfig,
|
|
90
|
+
APIProviderName,
|
|
91
|
+
APIProviderPricing,
|
|
92
|
+
CLIInfo,
|
|
93
|
+
CLIProviderName,
|
|
94
|
+
StreamingSummarizer,
|
|
95
|
+
StreamOptions,
|
|
96
|
+
SummarizationErrorCode,
|
|
97
|
+
SummarizationMode,
|
|
98
|
+
Summarizer,
|
|
99
|
+
SummarizerFactory,
|
|
100
|
+
SummaryResult,
|
|
101
|
+
} from './types.js'
|
|
102
|
+
export { SummarizationError } from './types.js'
|