Skip to content

Commit 1d1b45b

Browse files
authored
feat!: signal-driven conditional pipeline with single full/smoke config (#4)
* feat: conditional step execution with URL classification and fallback routing Add classify-url pipeline step, runIf/skipIf gates, and fallback load-source routing. - src/contracts/pipeline/condition.ts — recursive Condition type (string leaf, all/any/not combinators) - src/core/pipeline/conditions.ts — evaluateCondition, resolveStepGate, isTruthySignal - src/core/pipeline/compiled.ts — runIf/skipIf on CompiledPipelineStep - src/core/pipeline/orchestrator.ts — gate evaluation before step execution - src/builtins/pipeline-steps/classify-url/ — config, step, and descriptor - src/config/yaml/yaml-config.ts — conditionSchema with diagnostic-name validation - src/engine/engine-config.ts — runIf/skipIf on EngineStepConfig - src/shared/diagnostic-names.ts — isDiagnosticName helper - config/llm-context-loader.yaml — clean-combined rewired with classify → docling (runIf:binary_doc) → firecrawl (fallback) → clean (skipIf:code_host) - docs: ARCHITECTURE.md, CUSTOMIZATION.md, ROADMAP.md updated - 69 new focused tests; 388 total passing * feat: compile-time step disable, full/smoke pipeline split, env cleanup * feat(docling): opaque passthrough options with JSON-string coercion and standalone docs * feat(firecrawl): opaque passthrough options with PDF sniffing --------- Co-authored-by: David Soušek <15769039+sousekd@users.noreply.github.com>
1 parent 5d409e9 commit 1d1b45b

43 files changed

Lines changed: 1704 additions & 393 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ LOG_LEVEL=info
2222
LOG_PRETTY=auto
2323

2424
# --- Pipeline ------------------------------------------------------------
25-
# Active pipeline selected by HTTP adapters. Default: truncate (load-source + truncate)
26-
DEFAULT_PIPELINE=clean-combined
25+
# Active pipeline selected by HTTP adapters. Default: full (full-featured; external deps disabled by default).
26+
DEFAULT_PIPELINE=full
2727

2828
# Maximum concurrent source-loading groups. Default: 1; raise only if providers can handle it.
2929
SOURCE_CONCURRENCY=5
@@ -44,28 +44,37 @@ DEBUG_XML_INCLUDE_SKIPPED=false
4444
OUTPUT_TARGET_CHARS=35000
4545

4646
# --- Source provider -----------------------------------------------------
47-
# Optional source-provider override. Leave empty to use the selected pipeline's fallback.
48-
SOURCE_PROVIDER=
47+
# Enable Firecrawl source loading. Disabled by default. Default: false
48+
FIRECRAWL_ENABLED=false
4949

50-
# Firecrawl base URL. Required only when a referenced provider uses it (e.g. firecrawl-markdown, firecrawl-html).
50+
# Firecrawl base URL. Required only when FIRECRAWL_ENABLED=true.
5151
FIRECRAWL_BASE_URL=https://firecrawl.example
5252

5353
# Optional Firecrawl bearer token. Default: empty (no token)
5454
FIRECRAWL_API_KEY=
5555

56-
# Firecrawl PDF parsing. Set to false to return raw PDF bytes (binary body) instead of parsed text.
57-
FIRECRAWL_PARSE_PDF=
56+
# Opaque Firecrawl scrape options, keeping real API parameter names.
57+
FIRECRAWL_OPTIONS=
5858

59-
# Docling Serve base URL. Required only when a referenced provider uses it (e.g. docling-ocr).
59+
# Enable Docling OCR source loading for binary documents. Disabled by default. Default: false
60+
DOCLING_ENABLED=false
61+
62+
# Docling Serve base URL. Required only when DOCLING_ENABLED=true.
6063
DOCLING_BASE_URL=https://docling.example
6164

6265
# Optional Docling API key (X-Api-Key header). Default: empty (no token)
6366
DOCLING_API_KEY=
6467

68+
# Opaque JSON object of Docling convert options, merged into the convert body.
69+
DOCLING_OPTIONS=
70+
6571
# --- Content transformers ------------------------------------------------
6672
# Post-conversion link and whitespace cleanup for mdream-convert. Ignored when minimal=true (mdream-aggressive). Default: true
6773
MDREAM_CLEAN=true
6874

75+
# Enable Readability HTML-to-article extraction. Enabled by default (local; no external service needed). Default: true
76+
READABILITY_ENABLED=true
77+
6978
# Minimum content length for Readability's isProbablyReaderable gate. Default: 140
7079
READABILITY_MIN_CONTENT_CHARS=140
7180

@@ -76,7 +85,13 @@ READABILITY_MIN_SCORE=20
7685
READABILITY_MAX_ELEMENTS=0
7786

7887
# --- LLM provider --------------------------------------------------------
79-
# OpenAI-compatible Chat Completions /v1 base URL. Required only when a referenced provider uses it (e.g. llm-default).
88+
# Enable the clean LLM pass. Disabled by default. Default: false
89+
LLM_CLEAN_ENABLED=false
90+
91+
# Enable the summarize LLM pass. Disabled by default. Default: false
92+
LLM_SUMMARIZE_ENABLED=false
93+
94+
# OpenAI-compatible Chat Completions /v1 base URL. Required only when LLM_CLEAN_ENABLED or LLM_SUMMARIZE_ENABLED.
8095
LLM_BASE_URL=https://openai-compatible.example/v1
8196

8297
# Optional LLM bearer token. Default: empty (no token)
@@ -95,17 +110,23 @@ LLM_CHARS_PER_TOKEN=3.5
95110
LLM_SAFETY_MARGIN_TOKENS=128
96111

97112
# --- Step thresholds and timeouts ---------------------------------------
98-
# Timeout in seconds for the source-loading step. Default: 20
99-
LOAD_SOURCE_TIMEOUT_SECONDS=20
113+
# Timeout in seconds for the native HTTP source-loading step. Default: 20
114+
FETCH_TIMEOUT_SECONDS=20
115+
116+
# Timeout in seconds for the Firecrawl source-loading step. Default: 20
117+
FIRECRAWL_TIMEOUT_SECONDS=20
118+
119+
# Timeout in seconds for the Docling OCR source-loading step. Default: 60; OCR is slower.
120+
DOCLING_TIMEOUT_SECONDS=60
100121

101122
# Timeout in seconds for the clean LLM pass. Default: 60; raise for slower models.
102-
CLEAN_TIMEOUT_SECONDS=90
123+
LLM_CLEAN_TIMEOUT_SECONDS=90
103124

104125
# Minimum body length before the clean LLM pass runs. Default: 1000; lower values run cleanup more often.
105-
CLEAN_MIN_INPUT_CHARS=500
126+
LLM_CLEAN_MIN_INPUT_CHARS=500
106127

107128
# Timeout in seconds for the summarize LLM pass. Default: 60
108-
SUMMARIZE_TIMEOUT_SECONDS=60
129+
LLM_SUMMARIZE_TIMEOUT_SECONDS=60
109130

110131
# --- Inbound auth --------------------------------------------------------
111132
# Open WebUI adapter bearer token. Default: empty (leaves POST / open)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LLM Context Loader is a small HTTP service that turns URLs into markdown for LLM
1111

1212
## Current Shape
1313

14-
- **Pipelines:** `truncate` (default, no LLM), `clean-deterministic` (Firecrawl HTML + Readability + mdream, no LLM), `clean-llm` (Firecrawl + LLM), and `clean-combined` (Firecrawl HTML + Readability + mdream + LLM summarize), selected via `DEFAULT_PIPELINE`.
14+
- **Pipelines:** `full` (default; full-featured with toggleable Docling, Firecrawl, Readability, and LLM passes) and `smoke` (zero-dependency HTTP fetch + aggressive markdown + truncation), selected via `DEFAULT_PIPELINE`.
1515
- **Source providers:** native HTTP fetch, Firecrawl, Docling.
1616
- **Content transformers:** `readability` (article HTML extraction), `mdream` (HTML to markdown).
1717
- **LLM providers:** OpenAI-compatible `/chat/completions`.
@@ -64,7 +64,7 @@ docker compose -f compose.deploy.yaml up -d
6464

6565
The deploy compose file requires `LLMC_IMAGE_TAG`. The example env file uses `latest`, but repeatable deployments should pin it to an immutable release tag.
6666

67-
The out-of-box `truncate` pipeline needs no provider config. Switch to `clean-llm` with `DEFAULT_PIPELINE=clean-llm` and the appropriate provider vars. The Compose files pass all variables through without failing early; the service validates only the active pipeline's providers at startup. If Firecrawl or the LLM server runs on the host, use a LAN address or `host.docker.internal` instead of `localhost`.
67+
The `smoke` pipeline needs no provider config — it uses native HTTP fetch only. The Compose files pass all variables through without failing early; the service validates only the active pipeline's providers at startup. If Firecrawl or the LLM server runs on the host, use a LAN address or `host.docker.internal` instead of `localhost`.
6868

6969
## API
7070

compose.deploy.yaml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ x-llmc-environment: &llmc-environment # Bootstrap environment read before YAML l
1111
LOG_PRETTY: "${LOG_PRETTY:-auto}"
1212

1313
# Active pipeline selected by HTTP adapters.
14-
DEFAULT_PIPELINE: "${DEFAULT_PIPELINE:-truncate}"
14+
DEFAULT_PIPELINE: "${DEFAULT_PIPELINE:-full}"
1515

1616
# Pipeline concurrency and renderer selection.
1717
SOURCE_CONCURRENCY: "${SOURCE_CONCURRENCY:-1}"
@@ -21,13 +21,20 @@ x-llmc-environment: &llmc-environment # Bootstrap environment read before YAML l
2121
DEBUG_XML_INCLUDE_SKIPPED: "${DEBUG_XML_INCLUDE_SKIPPED:-false}"
2222
OUTPUT_TARGET_CHARS: "${OUTPUT_TARGET_CHARS:-25000}"
2323

24+
# Step toggles (disabled by default).
25+
DOCLING_ENABLED: "${DOCLING_ENABLED:-false}"
26+
FIRECRAWL_ENABLED: "${FIRECRAWL_ENABLED:-false}"
27+
READABILITY_ENABLED: "${READABILITY_ENABLED:-true}"
28+
LLM_CLEAN_ENABLED: "${LLM_CLEAN_ENABLED:-false}"
29+
LLM_SUMMARIZE_ENABLED: "${LLM_SUMMARIZE_ENABLED:-false}"
30+
2431
# Source provider.
25-
SOURCE_PROVIDER: "${SOURCE_PROVIDER:-}"
2632
FIRECRAWL_BASE_URL: "${FIRECRAWL_BASE_URL:-}"
2733
FIRECRAWL_API_KEY: "${FIRECRAWL_API_KEY:-}"
28-
FIRECRAWL_PARSE_PDF: "${FIRECRAWL_PARSE_PDF:-}"
34+
FIRECRAWL_OPTIONS: "${FIRECRAWL_OPTIONS:-}"
2935
DOCLING_BASE_URL: "${DOCLING_BASE_URL:-}"
3036
DOCLING_API_KEY: "${DOCLING_API_KEY:-}"
37+
DOCLING_OPTIONS: "${DOCLING_OPTIONS:-}"
3138

3239
# Content transformers.
3340
MDREAM_CLEAN: "${MDREAM_CLEAN:-true}"
@@ -44,10 +51,12 @@ x-llmc-environment: &llmc-environment # Bootstrap environment read before YAML l
4451
LLM_SAFETY_MARGIN_TOKENS: "${LLM_SAFETY_MARGIN_TOKENS:-128}"
4552

4653
# Step thresholds and timeouts.
47-
LOAD_SOURCE_TIMEOUT_SECONDS: "${LOAD_SOURCE_TIMEOUT_SECONDS:-20}"
48-
CLEAN_TIMEOUT_SECONDS: "${CLEAN_TIMEOUT_SECONDS:-60}"
49-
CLEAN_MIN_INPUT_CHARS: "${CLEAN_MIN_INPUT_CHARS:-1000}"
50-
SUMMARIZE_TIMEOUT_SECONDS: "${SUMMARIZE_TIMEOUT_SECONDS:-60}"
54+
FETCH_TIMEOUT_SECONDS: "${FETCH_TIMEOUT_SECONDS:-20}"
55+
FIRECRAWL_TIMEOUT_SECONDS: "${FIRECRAWL_TIMEOUT_SECONDS:-20}"
56+
DOCLING_TIMEOUT_SECONDS: "${DOCLING_TIMEOUT_SECONDS:-60}"
57+
LLM_CLEAN_TIMEOUT_SECONDS: "${LLM_CLEAN_TIMEOUT_SECONDS:-60}"
58+
LLM_CLEAN_MIN_INPUT_CHARS: "${LLM_CLEAN_MIN_INPUT_CHARS:-1000}"
59+
LLM_SUMMARIZE_TIMEOUT_SECONDS: "${LLM_SUMMARIZE_TIMEOUT_SECONDS:-60}"
5160

5261
# Per-adapter inbound bearer tokens. Empty means open route.
5362
OWUI_AUTH_TOKEN: "${OWUI_AUTH_TOKEN:-}"

compose.yaml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ x-llmc-environment: &llmc-environment # Bootstrap environment read before YAML l
1111
LOG_PRETTY: "${LOG_PRETTY:-auto}"
1212

1313
# Active pipeline selected by HTTP adapters.
14-
DEFAULT_PIPELINE: "${DEFAULT_PIPELINE:-truncate}"
14+
DEFAULT_PIPELINE: "${DEFAULT_PIPELINE:-full}"
1515

1616
# Pipeline concurrency and renderer selection.
1717
SOURCE_CONCURRENCY: "${SOURCE_CONCURRENCY:-1}"
@@ -21,13 +21,20 @@ x-llmc-environment: &llmc-environment # Bootstrap environment read before YAML l
2121
DEBUG_XML_INCLUDE_SKIPPED: "${DEBUG_XML_INCLUDE_SKIPPED:-false}"
2222
OUTPUT_TARGET_CHARS: "${OUTPUT_TARGET_CHARS:-25000}"
2323

24+
# Step toggles (disabled by default).
25+
DOCLING_ENABLED: "${DOCLING_ENABLED:-false}"
26+
FIRECRAWL_ENABLED: "${FIRECRAWL_ENABLED:-false}"
27+
READABILITY_ENABLED: "${READABILITY_ENABLED:-true}"
28+
LLM_CLEAN_ENABLED: "${LLM_CLEAN_ENABLED:-false}"
29+
LLM_SUMMARIZE_ENABLED: "${LLM_SUMMARIZE_ENABLED:-false}"
30+
2431
# Source provider.
25-
SOURCE_PROVIDER: "${SOURCE_PROVIDER:-}"
2632
FIRECRAWL_BASE_URL: "${FIRECRAWL_BASE_URL:-}"
2733
FIRECRAWL_API_KEY: "${FIRECRAWL_API_KEY:-}"
28-
FIRECRAWL_PARSE_PDF: "${FIRECRAWL_PARSE_PDF:-}"
34+
FIRECRAWL_OPTIONS: "${FIRECRAWL_OPTIONS:-}"
2935
DOCLING_BASE_URL: "${DOCLING_BASE_URL:-}"
3036
DOCLING_API_KEY: "${DOCLING_API_KEY:-}"
37+
DOCLING_OPTIONS: "${DOCLING_OPTIONS:-}"
3138

3239
# Content transformers.
3340
MDREAM_CLEAN: "${MDREAM_CLEAN:-true}"
@@ -44,10 +51,12 @@ x-llmc-environment: &llmc-environment # Bootstrap environment read before YAML l
4451
LLM_SAFETY_MARGIN_TOKENS: "${LLM_SAFETY_MARGIN_TOKENS:-128}"
4552

4653
# Step thresholds and timeouts.
47-
LOAD_SOURCE_TIMEOUT_SECONDS: "${LOAD_SOURCE_TIMEOUT_SECONDS:-20}"
48-
CLEAN_TIMEOUT_SECONDS: "${CLEAN_TIMEOUT_SECONDS:-60}"
49-
CLEAN_MIN_INPUT_CHARS: "${CLEAN_MIN_INPUT_CHARS:-1000}"
50-
SUMMARIZE_TIMEOUT_SECONDS: "${SUMMARIZE_TIMEOUT_SECONDS:-60}"
54+
FETCH_TIMEOUT_SECONDS: "${FETCH_TIMEOUT_SECONDS:-20}"
55+
FIRECRAWL_TIMEOUT_SECONDS: "${FIRECRAWL_TIMEOUT_SECONDS:-20}"
56+
DOCLING_TIMEOUT_SECONDS: "${DOCLING_TIMEOUT_SECONDS:-60}"
57+
LLM_CLEAN_TIMEOUT_SECONDS: "${LLM_CLEAN_TIMEOUT_SECONDS:-60}"
58+
LLM_CLEAN_MIN_INPUT_CHARS: "${LLM_CLEAN_MIN_INPUT_CHARS:-1000}"
59+
LLM_SUMMARIZE_TIMEOUT_SECONDS: "${LLM_SUMMARIZE_TIMEOUT_SECONDS:-60}"
5160

5261
# Per-adapter inbound bearer tokens. Empty means open route.
5362
OWUI_AUTH_TOKEN: "${OWUI_AUTH_TOKEN:-}"

0 commit comments

Comments
 (0)