@steipete/summarize 0.3.0 → 0.5.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/CHANGELOG.md +80 -5
- package/README.md +122 -20
- package/dist/cli.cjs +8446 -4360
- package/dist/cli.cjs.map +4 -4
- package/dist/esm/cli-main.js +47 -2
- package/dist/esm/cli-main.js.map +1 -1
- package/dist/esm/config.js +368 -3
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/content/link-preview/content/index.js +13 -0
- package/dist/esm/content/link-preview/content/index.js.map +1 -1
- package/dist/esm/content/link-preview/content/utils.js +3 -1
- package/dist/esm/content/link-preview/content/utils.js.map +1 -1
- package/dist/esm/content/link-preview/content/video.js +96 -0
- package/dist/esm/content/link-preview/content/video.js.map +1 -0
- package/dist/esm/content/link-preview/transcript/providers/youtube/captions.js +21 -21
- package/dist/esm/content/link-preview/transcript/providers/youtube/captions.js.map +1 -1
- package/dist/esm/costs.js.map +1 -1
- package/dist/esm/flags.js +41 -1
- package/dist/esm/flags.js.map +1 -1
- package/dist/esm/generate-free.js +616 -0
- package/dist/esm/generate-free.js.map +1 -0
- package/dist/esm/llm/cli.js +290 -0
- package/dist/esm/llm/cli.js.map +1 -0
- package/dist/esm/llm/generate-text.js +159 -105
- package/dist/esm/llm/generate-text.js.map +1 -1
- package/dist/esm/llm/html-to-markdown.js +4 -2
- package/dist/esm/llm/html-to-markdown.js.map +1 -1
- package/dist/esm/markitdown.js +54 -0
- package/dist/esm/markitdown.js.map +1 -0
- package/dist/esm/model-auto.js +353 -0
- package/dist/esm/model-auto.js.map +1 -0
- package/dist/esm/model-spec.js +82 -0
- package/dist/esm/model-spec.js.map +1 -0
- package/dist/esm/prompts/cli.js +18 -0
- package/dist/esm/prompts/cli.js.map +1 -0
- package/dist/esm/prompts/file.js +21 -2
- package/dist/esm/prompts/file.js.map +1 -1
- package/dist/esm/prompts/index.js +2 -1
- package/dist/esm/prompts/index.js.map +1 -1
- package/dist/esm/prompts/link-summary.js +3 -8
- package/dist/esm/prompts/link-summary.js.map +1 -1
- package/dist/esm/refresh-free.js +667 -0
- package/dist/esm/refresh-free.js.map +1 -0
- package/dist/esm/run.js +1612 -533
- package/dist/esm/run.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/types/config.d.ts +58 -5
- package/dist/types/content/link-preview/content/types.d.ts +10 -0
- package/dist/types/content/link-preview/content/utils.d.ts +1 -1
- package/dist/types/content/link-preview/content/video.d.ts +5 -0
- package/dist/types/costs.d.ts +2 -1
- package/dist/types/flags.d.ts +7 -0
- package/dist/types/generate-free.d.ts +17 -0
- package/dist/types/llm/cli.d.ts +24 -0
- package/dist/types/llm/generate-text.d.ts +13 -4
- package/dist/types/llm/html-to-markdown.d.ts +9 -3
- package/dist/types/markitdown.d.ts +10 -0
- package/dist/types/model-auto.d.ts +23 -0
- package/dist/types/model-spec.d.ts +33 -0
- package/dist/types/prompts/cli.d.ts +8 -0
- package/dist/types/prompts/file.d.ts +7 -0
- package/dist/types/prompts/index.d.ts +2 -1
- package/dist/types/refresh-free.d.ts +19 -0
- package/dist/types/run.d.ts +3 -1
- package/dist/types/version.d.ts +1 -1
- package/docs/README.md +4 -1
- package/docs/cli.md +95 -0
- package/docs/config.md +123 -1
- package/docs/extract-only.md +10 -7
- package/docs/firecrawl.md +2 -2
- package/docs/llm.md +24 -4
- package/docs/manual-tests.md +40 -0
- package/docs/model-auto.md +92 -0
- package/docs/site/assets/site.js +20 -17
- package/docs/site/docs/config.html +3 -3
- package/docs/site/docs/extract-only.html +7 -5
- package/docs/site/docs/firecrawl.html +6 -6
- package/docs/site/docs/index.html +2 -2
- package/docs/site/docs/llm.html +2 -2
- package/docs/site/docs/openai.html +2 -2
- package/docs/site/docs/website.html +7 -4
- package/docs/site/docs/youtube.html +2 -2
- package/docs/site/index.html +1 -1
- package/docs/smoketest.md +58 -0
- package/docs/website.md +13 -8
- package/docs/youtube.md +1 -1
- package/package.json +8 -4
- package/dist/esm/content/link-preview/transcript/providers/twitter.js +0 -12
- package/dist/esm/content/link-preview/transcript/providers/twitter.js.map +0 -1
- package/dist/esm/content/link-preview/transcript/providers/youtube/ytdlp.js +0 -114
- package/dist/esm/content/link-preview/transcript/providers/youtube/ytdlp.js.map +0 -1
- package/dist/esm/summarizeHome.js +0 -20
- package/dist/esm/summarizeHome.js.map +0 -1
- package/dist/esm/tty/live-markdown.js +0 -52
- package/dist/esm/tty/live-markdown.js.map +0 -1
- package/dist/types/content/link-preview/transcript/providers/twitter.d.ts +0 -3
- package/dist/types/content/link-preview/transcript/providers/youtube/ytdlp.d.ts +0 -3
- package/dist/types/summarizeHome.d.ts +0 -6
- package/dist/types/tty/live-markdown.d.ts +0 -10
|
@@ -14,7 +14,13 @@ export type LlmTokenUsage = {
|
|
|
14
14
|
completionTokens: number | null;
|
|
15
15
|
totalTokens: number | null;
|
|
16
16
|
};
|
|
17
|
-
|
|
17
|
+
type RetryNotice = {
|
|
18
|
+
attempt: number;
|
|
19
|
+
maxRetries: number;
|
|
20
|
+
delayMs: number;
|
|
21
|
+
error: unknown;
|
|
22
|
+
};
|
|
23
|
+
export declare function generateTextWithModelId({ modelId, apiKeys, system, prompt, temperature, maxOutputTokens, timeoutMs, fetchImpl, forceOpenRouter, retries, onRetry, }: {
|
|
18
24
|
modelId: string;
|
|
19
25
|
apiKeys: LlmApiKeys;
|
|
20
26
|
system?: string;
|
|
@@ -23,14 +29,16 @@ export declare function generateTextWithModelId({ modelId, apiKeys, system, prom
|
|
|
23
29
|
maxOutputTokens?: number;
|
|
24
30
|
timeoutMs: number;
|
|
25
31
|
fetchImpl: typeof fetch;
|
|
26
|
-
|
|
32
|
+
forceOpenRouter?: boolean;
|
|
33
|
+
retries?: number;
|
|
34
|
+
onRetry?: (notice: RetryNotice) => void;
|
|
27
35
|
}): Promise<{
|
|
28
36
|
text: string;
|
|
29
37
|
canonicalModelId: string;
|
|
30
38
|
provider: 'xai' | 'openai' | 'google' | 'anthropic';
|
|
31
39
|
usage: LlmTokenUsage | null;
|
|
32
40
|
}>;
|
|
33
|
-
export declare function streamTextWithModelId({ modelId, apiKeys, system, prompt, temperature, maxOutputTokens, timeoutMs, fetchImpl,
|
|
41
|
+
export declare function streamTextWithModelId({ modelId, apiKeys, system, prompt, temperature, maxOutputTokens, timeoutMs, fetchImpl, forceOpenRouter, }: {
|
|
34
42
|
modelId: string;
|
|
35
43
|
apiKeys: LlmApiKeys;
|
|
36
44
|
system?: string;
|
|
@@ -39,7 +47,7 @@ export declare function streamTextWithModelId({ modelId, apiKeys, system, prompt
|
|
|
39
47
|
maxOutputTokens?: number;
|
|
40
48
|
timeoutMs: number;
|
|
41
49
|
fetchImpl: typeof fetch;
|
|
42
|
-
|
|
50
|
+
forceOpenRouter?: boolean;
|
|
43
51
|
}): Promise<{
|
|
44
52
|
textStream: AsyncIterable<string>;
|
|
45
53
|
canonicalModelId: string;
|
|
@@ -47,3 +55,4 @@ export declare function streamTextWithModelId({ modelId, apiKeys, system, prompt
|
|
|
47
55
|
usage: Promise<LlmTokenUsage | null>;
|
|
48
56
|
lastError: () => unknown;
|
|
49
57
|
}>;
|
|
58
|
+
export {};
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import type { ConvertHtmlToMarkdown } from '../content/link-preview/deps.js';
|
|
2
2
|
import type { LlmTokenUsage } from './generate-text.js';
|
|
3
|
-
|
|
4
|
-
export declare function createHtmlToMarkdownConverter({ modelId, xaiApiKey, googleApiKey, openaiApiKey, anthropicApiKey, openrouterApiKey, openrouter, fetchImpl, onUsage, }: {
|
|
3
|
+
export declare function createHtmlToMarkdownConverter({ modelId, forceOpenRouter, xaiApiKey, googleApiKey, openaiApiKey, anthropicApiKey, openrouterApiKey, fetchImpl, retries, onRetry, onUsage, }: {
|
|
5
4
|
modelId: string;
|
|
5
|
+
forceOpenRouter?: boolean;
|
|
6
6
|
xaiApiKey: string | null;
|
|
7
7
|
googleApiKey: string | null;
|
|
8
8
|
openaiApiKey: string | null;
|
|
9
9
|
fetchImpl: typeof fetch;
|
|
10
10
|
anthropicApiKey: string | null;
|
|
11
11
|
openrouterApiKey: string | null;
|
|
12
|
-
|
|
12
|
+
retries?: number;
|
|
13
|
+
onRetry?: (notice: {
|
|
14
|
+
attempt: number;
|
|
15
|
+
maxRetries: number;
|
|
16
|
+
delayMs: number;
|
|
17
|
+
error: unknown;
|
|
18
|
+
}) => void;
|
|
13
19
|
onUsage?: (usage: {
|
|
14
20
|
model: string;
|
|
15
21
|
provider: 'xai' | 'openai' | 'google' | 'anthropic';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ExecFileFn = typeof import('node:child_process').execFile;
|
|
2
|
+
export declare function convertToMarkdownWithMarkitdown({ bytes, filenameHint, mediaTypeHint, uvxCommand, timeoutMs, env, execFileImpl, }: {
|
|
3
|
+
bytes: Uint8Array;
|
|
4
|
+
filenameHint: string | null;
|
|
5
|
+
mediaTypeHint: string | null;
|
|
6
|
+
uvxCommand?: string | null;
|
|
7
|
+
timeoutMs: number;
|
|
8
|
+
env: Record<string, string | undefined>;
|
|
9
|
+
execFileImpl: ExecFileFn;
|
|
10
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AutoRuleKind, CliProvider, SummarizeConfig } from './config.js';
|
|
2
|
+
import type { LiteLlmCatalog } from './pricing/litellm.js';
|
|
3
|
+
export type AutoSelectionInput = {
|
|
4
|
+
kind: AutoRuleKind;
|
|
5
|
+
promptTokens: number | null;
|
|
6
|
+
desiredOutputTokens: number | null;
|
|
7
|
+
requiresVideoUnderstanding: boolean;
|
|
8
|
+
env: Record<string, string | undefined>;
|
|
9
|
+
config: SummarizeConfig | null;
|
|
10
|
+
catalog: LiteLlmCatalog | null;
|
|
11
|
+
openrouterProvidersFromEnv: string[] | null;
|
|
12
|
+
cliAvailability?: Partial<Record<CliProvider, boolean>>;
|
|
13
|
+
};
|
|
14
|
+
export type AutoModelAttempt = {
|
|
15
|
+
transport: 'native' | 'openrouter' | 'cli';
|
|
16
|
+
userModelId: string;
|
|
17
|
+
llmModelId: string | null;
|
|
18
|
+
openrouterProviders: string[] | null;
|
|
19
|
+
forceOpenRouter: boolean;
|
|
20
|
+
requiredEnv: 'XAI_API_KEY' | 'OPENAI_API_KEY' | 'GEMINI_API_KEY' | 'ANTHROPIC_API_KEY' | 'OPENROUTER_API_KEY' | 'CLI_CLAUDE' | 'CLI_CODEX' | 'CLI_GEMINI';
|
|
21
|
+
debug: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function buildAutoModelAttempts(input: AutoSelectionInput): AutoModelAttempt[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CliProvider } from './config.js';
|
|
2
|
+
export type FixedModelSpec = {
|
|
3
|
+
transport: 'native';
|
|
4
|
+
userModelId: string;
|
|
5
|
+
llmModelId: string;
|
|
6
|
+
provider: 'xai' | 'openai' | 'google' | 'anthropic';
|
|
7
|
+
openrouterProviders: string[] | null;
|
|
8
|
+
forceOpenRouter: false;
|
|
9
|
+
requiredEnv: 'XAI_API_KEY' | 'OPENAI_API_KEY' | 'GEMINI_API_KEY' | 'ANTHROPIC_API_KEY';
|
|
10
|
+
} | {
|
|
11
|
+
transport: 'openrouter';
|
|
12
|
+
userModelId: string;
|
|
13
|
+
openrouterModelId: string;
|
|
14
|
+
llmModelId: string;
|
|
15
|
+
openrouterProviders: string[] | null;
|
|
16
|
+
forceOpenRouter: true;
|
|
17
|
+
requiredEnv: 'OPENROUTER_API_KEY';
|
|
18
|
+
} | {
|
|
19
|
+
transport: 'cli';
|
|
20
|
+
userModelId: string;
|
|
21
|
+
llmModelId: null;
|
|
22
|
+
openrouterProviders: null;
|
|
23
|
+
forceOpenRouter: false;
|
|
24
|
+
requiredEnv: 'CLI_CLAUDE' | 'CLI_CODEX' | 'CLI_GEMINI';
|
|
25
|
+
cliProvider: CliProvider;
|
|
26
|
+
cliModel: string | null;
|
|
27
|
+
};
|
|
28
|
+
export type RequestedModel = {
|
|
29
|
+
kind: 'auto';
|
|
30
|
+
} | ({
|
|
31
|
+
kind: 'fixed';
|
|
32
|
+
} & FixedModelSpec);
|
|
33
|
+
export declare function parseRequestedModelId(raw: string): RequestedModel;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SummaryLengthTarget } from './link-summary.js';
|
|
2
|
+
export declare function buildPathSummaryPrompt({ kindLabel, filePath, filename, mediaType, summaryLength, }: {
|
|
3
|
+
kindLabel: 'file' | 'image';
|
|
4
|
+
filePath: string;
|
|
5
|
+
filename: string | null;
|
|
6
|
+
mediaType: string | null;
|
|
7
|
+
summaryLength: SummaryLengthTarget;
|
|
8
|
+
}): string;
|
|
@@ -5,3 +5,10 @@ export declare function buildFileSummaryPrompt({ filename, mediaType, summaryLen
|
|
|
5
5
|
summaryLength: SummaryLengthTarget;
|
|
6
6
|
contentLength?: number | null;
|
|
7
7
|
}): string;
|
|
8
|
+
export declare function buildFileTextSummaryPrompt({ filename, originalMediaType, contentMediaType, summaryLength, contentLength, }: {
|
|
9
|
+
filename: string | null;
|
|
10
|
+
originalMediaType: string | null;
|
|
11
|
+
contentMediaType: string;
|
|
12
|
+
summaryLength: SummaryLengthTarget;
|
|
13
|
+
contentLength: number;
|
|
14
|
+
}): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export type { SummaryLength } from '../shared/contracts.js';
|
|
2
|
-
export {
|
|
2
|
+
export { buildPathSummaryPrompt } from './cli.js';
|
|
3
|
+
export { buildFileSummaryPrompt, buildFileTextSummaryPrompt } from './file.js';
|
|
3
4
|
export { buildLinkSummaryPrompt, estimateMaxCompletionTokensForCharacters, pickSummaryLengthForCharacters, type ShareContextEntry, SUMMARY_LENGTH_TO_TOKENS, type SummaryLengthTarget, } from './link-summary.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type GenerateFreeOptions = {
|
|
2
|
+
runs: number;
|
|
3
|
+
smart: number;
|
|
4
|
+
maxCandidates: number;
|
|
5
|
+
concurrency: number;
|
|
6
|
+
timeoutMs: number;
|
|
7
|
+
minParamB: number;
|
|
8
|
+
maxAgeDays: number;
|
|
9
|
+
setDefault: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare function refreshFree({ env, fetchImpl, stdout, stderr, verbose, options, }: {
|
|
12
|
+
env: Record<string, string | undefined>;
|
|
13
|
+
fetchImpl: typeof fetch;
|
|
14
|
+
stdout: NodeJS.WritableStream;
|
|
15
|
+
stderr: NodeJS.WritableStream;
|
|
16
|
+
verbose?: boolean;
|
|
17
|
+
options?: Partial<GenerateFreeOptions>;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export {};
|
package/dist/types/run.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type ExecFileFn } from './markitdown.js';
|
|
1
2
|
type RunEnv = {
|
|
2
3
|
env: Record<string, string | undefined>;
|
|
3
4
|
fetch: typeof fetch;
|
|
5
|
+
execFile?: ExecFileFn;
|
|
4
6
|
stdout: NodeJS.WritableStream;
|
|
5
7
|
stderr: NodeJS.WritableStream;
|
|
6
8
|
};
|
|
7
|
-
export declare function runCli(argv: string[], { env, fetch, stdout, stderr }: RunEnv): Promise<void>;
|
|
9
|
+
export declare function runCli(argv: string[], { env, fetch, execFile: execFileOverride, stdout, stderr }: RunEnv): Promise<void>;
|
|
8
10
|
export {};
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const FALLBACK_VERSION = "0.
|
|
1
|
+
export declare const FALLBACK_VERSION = "0.5.0";
|
|
2
2
|
export declare function resolvePackageVersion(importMetaUrl?: string): string;
|
package/docs/README.md
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
- `docs/youtube.md` — YouTube transcript extraction (youtubei / captionTracks / Apify)
|
|
5
5
|
- `docs/firecrawl.md` — Firecrawl mode + API key
|
|
6
6
|
- `docs/llm.md` — LLM summarization + model config (Gateway/OpenAI)
|
|
7
|
-
- `docs/
|
|
7
|
+
- `docs/cli.md` — CLI models (Claude/Codex/Gemini)
|
|
8
|
+
- `docs/model-auto.md` — automatic model selection (`--model auto`)
|
|
9
|
+
- `docs/manual-tests.md` — manual end-to-end test checklist
|
|
10
|
+
- `docs/extract-only.md` — extract mode (no summary LLM call)
|
|
8
11
|
|
|
9
12
|
## Website
|
|
10
13
|
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# CLI models
|
|
2
|
+
|
|
3
|
+
Summarize can use installed CLIs (Claude, Codex, Gemini) as local model backends.
|
|
4
|
+
|
|
5
|
+
## Model ids
|
|
6
|
+
|
|
7
|
+
- `cli/claude/<model>` (e.g. `cli/claude/sonnet`)
|
|
8
|
+
- `cli/codex/<model>` (e.g. `cli/codex/gpt-5.2`)
|
|
9
|
+
- `cli/gemini/<model>` (e.g. `cli/gemini/gemini-3-flash-preview`)
|
|
10
|
+
|
|
11
|
+
Use `--cli [provider]` (case-insensitive) for the provider default, or `--model cli/<provider>/<model>` to pin a model.
|
|
12
|
+
If `--cli` is provided without a provider, auto selection is used with CLI enabled.
|
|
13
|
+
|
|
14
|
+
## Auto mode
|
|
15
|
+
|
|
16
|
+
Auto mode does **not** use CLIs unless you set `cli.enabled` in config.
|
|
17
|
+
|
|
18
|
+
Why: CLI adds ~4s latency per attempt and higher variance.
|
|
19
|
+
Recommendation: enable only Gemini unless you have a reason to add others.
|
|
20
|
+
|
|
21
|
+
Gemini CLI performance: summarize sets `GEMINI_CLI_NO_RELAUNCH=true` for Gemini CLI runs to avoid a costly self-relaunch (can be overridden by setting it yourself).
|
|
22
|
+
|
|
23
|
+
When enabled, auto prepends CLI attempts in the order listed in `cli.enabled`
|
|
24
|
+
(recommended: `["gemini"]`).
|
|
25
|
+
|
|
26
|
+
Enable CLI attempts:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"cli": { "enabled": ["gemini"] }
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Disable CLI attempts:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"cli": { "enabled": [] }
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Note: when `cli.enabled` is set, it also acts as an allowlist for explicit `--cli` / `--model cli/...`.
|
|
43
|
+
|
|
44
|
+
## CLI discovery
|
|
45
|
+
|
|
46
|
+
Binary lookup:
|
|
47
|
+
|
|
48
|
+
- `CLAUDE_PATH`, `CODEX_PATH`, `GEMINI_PATH` (optional overrides)
|
|
49
|
+
- Otherwise uses `PATH`
|
|
50
|
+
|
|
51
|
+
## Attachments (images/files)
|
|
52
|
+
|
|
53
|
+
When a CLI attempt is used for an image or non-text file, Summarize switches to a
|
|
54
|
+
path-based prompt and enables the required tool flags:
|
|
55
|
+
|
|
56
|
+
- Claude: `--tools Read --dangerously-skip-permissions`
|
|
57
|
+
- Gemini: `--yolo` and `--include-directories <dir>`
|
|
58
|
+
- Codex: `codex exec --output-last-message ...` and `-i <image>` for images
|
|
59
|
+
|
|
60
|
+
## Config
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"cli": {
|
|
65
|
+
"enabled": ["claude", "gemini", "codex"],
|
|
66
|
+
"codex": { "model": "gpt-5.2" },
|
|
67
|
+
"gemini": { "model": "gemini-3-flash-preview", "extraArgs": ["--verbose"] },
|
|
68
|
+
"claude": {
|
|
69
|
+
"model": "sonnet",
|
|
70
|
+
"binary": "/usr/local/bin/claude",
|
|
71
|
+
"extraArgs": ["--verbose"]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Notes:
|
|
78
|
+
|
|
79
|
+
- CLI output is treated as text only (no token accounting).
|
|
80
|
+
- If a CLI call fails, auto mode falls back to the next candidate.
|
|
81
|
+
|
|
82
|
+
## Generate free preset (OpenRouter)
|
|
83
|
+
|
|
84
|
+
`summarize` ships with a built-in preset `free`, backed by OpenRouter `:free` models.
|
|
85
|
+
To regenerate the candidate list (and persist it in your config):
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
summarize refresh-free
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Options:
|
|
92
|
+
|
|
93
|
+
- `--runs 2` (default): extra timing runs per selected model (total runs = 1 + runs)
|
|
94
|
+
- `--smart 3` (default): number of “smart-first” picks (rest filled by fastest)
|
|
95
|
+
- `--set-default`: also sets `"model": "free"` in `~/.summarize/config.json`
|
package/docs/config.md
CHANGED
|
@@ -15,14 +15,136 @@ For `model`:
|
|
|
15
15
|
1. CLI flag `--model`
|
|
16
16
|
2. Env `SUMMARIZE_MODEL`
|
|
17
17
|
3. Config file `model`
|
|
18
|
-
4. Built-in default (`
|
|
18
|
+
4. Built-in default (`auto`)
|
|
19
19
|
|
|
20
20
|
## Format
|
|
21
21
|
|
|
22
22
|
`~/.summarize/config.json`:
|
|
23
23
|
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"model": { "id": "google/gemini-3-flash-preview" }
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Shorthand (equivalent):
|
|
31
|
+
|
|
24
32
|
```json
|
|
25
33
|
{
|
|
26
34
|
"model": "google/gemini-3-flash-preview"
|
|
27
35
|
}
|
|
28
36
|
```
|
|
37
|
+
|
|
38
|
+
`model` can also be auto:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"model": { "mode": "auto" }
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Shorthand (equivalent):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"model": "auto"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Presets
|
|
55
|
+
|
|
56
|
+
Define presets you can select via `--model <preset>`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"models": {
|
|
61
|
+
"fast": { "id": "openai/gpt-5-mini" },
|
|
62
|
+
"or-free": {
|
|
63
|
+
"rules": [
|
|
64
|
+
{
|
|
65
|
+
"candidates": [
|
|
66
|
+
"openrouter/google/gemini-2.0-flash-exp:free",
|
|
67
|
+
"openrouter/meta-llama/llama-3.3-70b-instruct:free"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Notes:
|
|
77
|
+
|
|
78
|
+
- `auto` is reserved and can’t be defined as a preset.
|
|
79
|
+
- `free` is built-in (OpenRouter `:free` candidates). Override it by defining `models.free` in your config, or regenerate it via `summarize refresh-free`.
|
|
80
|
+
|
|
81
|
+
Use a preset as your default `model`:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"model": "fast"
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Notes:
|
|
90
|
+
|
|
91
|
+
- For presets, `"mode": "auto"` is optional when `"rules"` is present.
|
|
92
|
+
|
|
93
|
+
For auto selection with rules:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"model": {
|
|
98
|
+
"mode": "auto",
|
|
99
|
+
"rules": [
|
|
100
|
+
{
|
|
101
|
+
"when": ["video"],
|
|
102
|
+
"candidates": ["google/gemini-3-flash-preview"]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"when": ["website", "youtube"],
|
|
106
|
+
"bands": [
|
|
107
|
+
{
|
|
108
|
+
"token": { "max": 8000 },
|
|
109
|
+
"candidates": ["openai/gpt-5-mini"]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"candidates": ["xai/grok-4-fast-non-reasoning"]
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"candidates": ["openai/gpt-5-mini", "openrouter/openai/gpt-5-mini"]
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"media": { "videoMode": "auto" }
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Notes:
|
|
126
|
+
|
|
127
|
+
- Parsed leniently (JSON5), but **comments are not allowed**.
|
|
128
|
+
- Unknown keys are ignored.
|
|
129
|
+
- `model.rules` is optional. If omitted, built-in defaults apply.
|
|
130
|
+
- `model.rules[].when` (optional) must be an array (e.g. `["video","youtube"]`).
|
|
131
|
+
- `model.rules[]` must use either `candidates` or `bands`.
|
|
132
|
+
|
|
133
|
+
## CLI config
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"cli": {
|
|
138
|
+
"enabled": ["gemini"],
|
|
139
|
+
"codex": { "model": "gpt-5.2" },
|
|
140
|
+
"claude": { "binary": "/usr/local/bin/claude", "extraArgs": ["--verbose"] }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Notes:
|
|
146
|
+
|
|
147
|
+
- `cli.enabled` is an allowlist (auto uses CLIs only when set; explicit `--cli` / `--model cli/...` must be included).
|
|
148
|
+
- Recommendation: keep `cli.enabled` to `["gemini"]` unless you have a reason to add others (extra latency/variance).
|
|
149
|
+
- `cli.<provider>.binary` overrides CLI binary discovery.
|
|
150
|
+
- `cli.<provider>.extraArgs` appends extra CLI args.
|
package/docs/extract-only.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
# Extract
|
|
1
|
+
# Extract mode
|
|
2
2
|
|
|
3
|
-
`--extract
|
|
3
|
+
`--extract` prints the extracted content and exits.
|
|
4
|
+
|
|
5
|
+
Deprecated alias: `--extract-only`.
|
|
4
6
|
|
|
5
7
|
## Notes
|
|
6
8
|
|
|
7
9
|
- No summarization LLM call happens in this mode.
|
|
8
|
-
- `--
|
|
10
|
+
- `--format md` may still convert HTML → Markdown (depending on `--markdown-mode` and available tools).
|
|
9
11
|
- `--length` is intended for summarization guidance; extraction prints full content.
|
|
10
|
-
- For non-YouTube URLs
|
|
11
|
-
- Force plain HTML extraction with `--firecrawl off
|
|
12
|
-
- For non-YouTube URLs
|
|
13
|
-
- Force it with `--markdown llm`.
|
|
12
|
+
- For non-YouTube URLs with `--format md`, the CLI prefers Firecrawl Markdown by default when `FIRECRAWL_API_KEY` is configured (unless you set `--firecrawl` explicitly).
|
|
13
|
+
- Force plain HTML extraction with `--firecrawl off` (or use `--format text`).
|
|
14
|
+
- For non-YouTube URLs with `--format md`, `--markdown-mode auto` can convert HTML → Markdown via an LLM when configured.
|
|
15
|
+
- Force it with `--markdown-mode llm`.
|
|
16
|
+
- If no LLM is configured, `--markdown-mode auto` may fall back to `uvx markitdown` when available.
|
package/docs/firecrawl.md
CHANGED
|
@@ -8,9 +8,9 @@ Firecrawl is a fallback for sites that block direct HTML fetching or don’t ren
|
|
|
8
8
|
- `auto` (default): use Firecrawl only when HTML extraction looks blocked/thin.
|
|
9
9
|
- `always`: try Firecrawl first (falls back to HTML if Firecrawl is unavailable/empty).
|
|
10
10
|
|
|
11
|
-
## Extract
|
|
11
|
+
## Extract default
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
When `--extract --format md` is used for non-YouTube URLs and `FIRECRAWL_API_KEY` is configured, the CLI defaults to `--firecrawl always` to return Markdown.
|
|
14
14
|
|
|
15
15
|
## API key
|
|
16
16
|
|
package/docs/llm.md
CHANGED
|
@@ -1,37 +1,57 @@
|
|
|
1
1
|
# LLM / summarization mode
|
|
2
2
|
|
|
3
|
-
By default `summarize` will call an LLM using **direct provider API keys**.
|
|
3
|
+
By default `summarize` will call an LLM using **direct provider API keys**. When CLI tools are
|
|
4
|
+
installed, auto mode can use local CLI models when `cli.enabled` is set (see `docs/cli.md`).
|
|
4
5
|
|
|
5
6
|
## Defaults
|
|
6
7
|
|
|
7
|
-
- Default model: `
|
|
8
|
+
- Default model: `auto`
|
|
8
9
|
- Override with `SUMMARIZE_MODEL`, config file (`model`), or `--model`.
|
|
9
10
|
|
|
10
11
|
## Env
|
|
11
12
|
|
|
13
|
+
- `.env` (optional): when running the CLI, `summarize` also reads `.env` in the current working directory and merges it into the environment (real env vars win).
|
|
12
14
|
- `XAI_API_KEY` (required for `xai/...` models)
|
|
13
15
|
- `OPENAI_API_KEY` (required for `openai/...` models)
|
|
14
16
|
- `OPENAI_BASE_URL` (optional; OpenAI-compatible API endpoint, e.g. OpenRouter)
|
|
15
|
-
- `OPENROUTER_API_KEY` (optional; used when `OPENAI_BASE_URL` points to OpenRouter)
|
|
17
|
+
- `OPENROUTER_API_KEY` (optional; required for `openrouter/...` models; also used when `OPENAI_BASE_URL` points to OpenRouter)
|
|
16
18
|
- `GEMINI_API_KEY` (required for `google/...` models; also accepts `GOOGLE_GENERATIVE_AI_API_KEY` / `GOOGLE_API_KEY`)
|
|
17
19
|
- `ANTHROPIC_API_KEY` (required for `anthropic/...` models)
|
|
18
20
|
- `SUMMARIZE_MODEL` (optional; overrides default model selection)
|
|
21
|
+
- `CLAUDE_PATH` / `CODEX_PATH` / `GEMINI_PATH` (optional; override CLI binary paths)
|
|
19
22
|
|
|
20
23
|
## Flags
|
|
21
24
|
|
|
22
25
|
- `--model <model>`
|
|
23
26
|
- Examples:
|
|
27
|
+
- `cli/codex/gpt-5.2`
|
|
28
|
+
- `cli/claude/sonnet`
|
|
29
|
+
- `cli/gemini/gemini-3-flash-preview`
|
|
24
30
|
- `google/gemini-3-flash-preview`
|
|
25
|
-
- `openai/gpt-5
|
|
31
|
+
- `openai/gpt-5-mini`
|
|
26
32
|
- `xai/grok-4-fast-non-reasoning`
|
|
27
33
|
- `google/gemini-2.0-flash`
|
|
28
34
|
- `anthropic/claude-sonnet-4-5`
|
|
35
|
+
- `openrouter/meta-llama/llama-3.3-70b-instruct:free` (force OpenRouter)
|
|
36
|
+
- `--cli [provider]`
|
|
37
|
+
- Examples: `--cli claude`, `--cli Gemini`, `--cli codex` (equivalent to `--model cli/<provider>`); `--cli` alone uses auto selection with CLI enabled.
|
|
38
|
+
- `--model auto`
|
|
39
|
+
- See `docs/model-auto.md`
|
|
40
|
+
- `--model <preset>`
|
|
41
|
+
- Uses a config-defined preset (see `docs/config.md` → “Presets”).
|
|
42
|
+
- `--video-mode auto|transcript|understand`
|
|
43
|
+
- Only relevant for video inputs / video-only pages.
|
|
29
44
|
- `--length short|medium|long|xl|xxl|<chars>`
|
|
30
45
|
- This is *soft guidance* to the model (no hard truncation).
|
|
31
46
|
- Minimum numeric value: 50 chars.
|
|
47
|
+
- Default: `long`.
|
|
32
48
|
- `--max-output-tokens <count>`
|
|
33
49
|
- Hard cap for output tokens (optional).
|
|
50
|
+
- If omitted, no max token parameter is sent (provider default).
|
|
34
51
|
- Minimum numeric value: 16.
|
|
52
|
+
- Recommendation: prefer `--length` unless you need a hard cap (some providers count “reasoning” into the cap).
|
|
53
|
+
- `--retries <count>`
|
|
54
|
+
- LLM retry attempts on timeout (default: 1).
|
|
35
55
|
- `--json` (includes prompt + summary in one JSON object)
|
|
36
56
|
|
|
37
57
|
## Input limits
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Manual tests
|
|
2
|
+
|
|
3
|
+
Goal: sanity-check auto selection + presets end-to-end.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
- `OPENAI_API_KEY=...` (optional)
|
|
8
|
+
- `GEMINI_API_KEY=...` (optional)
|
|
9
|
+
- `ANTHROPIC_API_KEY=...` (optional)
|
|
10
|
+
- `XAI_API_KEY=...` (optional)
|
|
11
|
+
- `OPENROUTER_API_KEY=...` (optional)
|
|
12
|
+
|
|
13
|
+
Tip: use `--verbose` to see model attempts + the chosen model.
|
|
14
|
+
|
|
15
|
+
## Auto (default)
|
|
16
|
+
|
|
17
|
+
- Website summary (should pick a model, show it in spinner):
|
|
18
|
+
- `summarize --max-output-tokens 200 https://example.com`
|
|
19
|
+
- No-model-needed shortcut (should print extracted text; no footer “no model needed”):
|
|
20
|
+
- `summarize --max-output-tokens 99999 https://example.com`
|
|
21
|
+
- Missing-key skip (configure only one key; should skip other providers, still succeed):
|
|
22
|
+
- Set only `OPENAI_API_KEY`, then run a website summary; should not try Gemini/Anthropic/XAI.
|
|
23
|
+
|
|
24
|
+
## Presets
|
|
25
|
+
|
|
26
|
+
- Define a preset in `~/.summarize/config.json` (see `docs/config.md` → “Presets”), then:
|
|
27
|
+
- `summarize --model <preset> --max-output-tokens 200 https://example.com`
|
|
28
|
+
- If the preset contains OpenRouter models, ensure `OPENROUTER_API_KEY` is set.
|
|
29
|
+
|
|
30
|
+
## Images
|
|
31
|
+
|
|
32
|
+
- Local image (auto uses API models by default; enable CLI via `cli.enabled` to test CLIs):
|
|
33
|
+
- `summarize ./path/to/image.png --max-output-tokens 200`
|
|
34
|
+
|
|
35
|
+
## Video
|
|
36
|
+
|
|
37
|
+
- YouTube:
|
|
38
|
+
- `summarize https://www.youtube.com/watch?v=dQw4w9WgXcQ --max-output-tokens 200`
|
|
39
|
+
- Local video understanding (requires Gemini video-capable model; otherwise expect an error or transcript-only behavior depending on input):
|
|
40
|
+
- `summarize ./path/to/video.mp4 --max-output-tokens 200`
|