webfetch-llm 0.1.0__py3-none-any.whl

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.
webfetch/compress.py ADDED
@@ -0,0 +1,360 @@
1
+ """
2
+ Sentence-level extractive compression for tool results.
3
+
4
+ Within each top-ranked chunk, keep only the sentences relevant to the query.
5
+ Runs at tool-result FORMATTING time, after the cache read, so cached chunks
6
+ stay full-text and budget-agnostic - retuning compression never invalidates
7
+ the cache.
8
+
9
+ Why extractive (select sentences) rather than abstractive (rewrite):
10
+ abstractive needs an LLM call per result, which is against the library's
11
+ zero-marginal-cost design; extractive is a pure function of (query, chunks).
12
+
13
+ Parameters (scorer, selection policy, guards) are chosen by the eval harness
14
+ (evals/run_compression_eval.py) which imports THIS module - the shipped code
15
+ is exactly what was measured. Config defaults in webfetch/config.py hold the
16
+ winning configuration: cross-encoder scored, ratio 0.5, all guards on -
17
+ measured ZERO recall drop (29/29 answer survival) at 50% of baseline tokens
18
+ on 50 captured production results. The cross-encoder is what makes lossless
19
+ compression possible here: bi-encoder selection at the same token level
20
+ loses 3-4 answers of 29.
21
+
22
+ Guards against the known failure modes of naive sentence selection:
23
+ - anaphora: a kept sentence starting with a pronoun/connective would be
24
+ unreadable alone, so its preceding sentence is retained with it
25
+ - table-like lines (markdown rows, digit-dense spec lines) are not prose -
26
+ sentence scoring misjudges them, so they bypass scoring and are kept
27
+ - cross-chunk dedup: the chunker's 10% overlap re-emits boundary sentences
28
+ in the next chunk; duplicates waste budget
29
+
30
+ Requires the optional rerank extra for the bi-encoder scorer; without it the
31
+ scorer degrades to the zero-dep lexical scorer (never crashes the tool path).
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import logging
37
+ import math
38
+ import re
39
+ import threading
40
+
41
+ from webfetch.config import (
42
+ BIENCODER_MODEL,
43
+ COMPRESS_ANAPHORA_GUARD,
44
+ COMPRESS_DEDUP,
45
+ COMPRESS_PARAM,
46
+ COMPRESS_POLICY,
47
+ COMPRESS_SCORER,
48
+ COMPRESS_TABLE_GUARD,
49
+ CROSSENCODER_MODEL,
50
+ )
51
+ from webfetch.rank.base import Chunk
52
+
53
+ logger = logging.getLogger(__name__)
54
+
55
+ # Sentence boundary: terminal punctuation, whitespace, then something that
56
+ # looks like a sentence start. Deliberately regex-based and zero-dep (same
57
+ # philosophy as the chunker) - abbreviation mistakes cost a split, and the
58
+ # eval measures the net effect rather than assuming splitter perfection.
59
+ _SENT_BOUNDARY_RE = re.compile(r"(?<=[.!?])\s+(?=[A-Z0-9\"'(\[])")
60
+
61
+ # First words that signal the sentence leans on its predecessor.
62
+ _ANAPHORIC_STARTS = frozenset({
63
+ "it", "its", "this", "that", "these", "those", "they", "them", "their",
64
+ "he", "she", "his", "her", "him", "however", "but", "also", "moreover",
65
+ "additionally", "furthermore", "meanwhile", "instead", "still", "yet",
66
+ "so", "such", "both", "neither", "otherwise", "consequently", "thus",
67
+ "therefore", "here", "there",
68
+ })
69
+
70
+ _FIRST_WORD_RE = re.compile(r"[a-zA-Z]+")
71
+
72
+ # Digit share of non-space chars above which a line is treated as data,
73
+ # not prose (spec lines, score lines, table rows).
74
+ _TABLE_DIGIT_RATIO = 0.20
75
+
76
+ # Sentences shorter than this are never deduped - short strings ("Yes.",
77
+ # a bare number) can legitimately repeat with different meanings.
78
+ _DEDUP_MIN_CHARS = 30
79
+
80
+ _bi_model = None
81
+ _ce_model = None
82
+ _models_unavailable = False
83
+ # Concurrent tool calls racing lazy model construction crash inside torch -
84
+ # same locking pattern as rank/biencoder.py.
85
+ _init_lock = threading.Lock()
86
+
87
+
88
+ def split_sentences(text: str) -> list[tuple[int, str]]:
89
+ """Split text into (line_index, sentence) pairs.
90
+
91
+ Newlines are hard boundaries (extracted pages use them structurally:
92
+ headings, list items, table rows); prose lines are further split on
93
+ sentence punctuation. Chunk-edge fragments come through as ordinary
94
+ sentences and are scored like any other.
95
+
96
+ Args:
97
+ text: Chunk text.
98
+
99
+ Returns:
100
+ List of (line_index, sentence) pairs in document order.
101
+ """
102
+ out: list[tuple[int, str]] = []
103
+ for line_idx, line in enumerate(text.split("\n")):
104
+ line = line.strip()
105
+ if not line:
106
+ continue
107
+ for sent in _SENT_BOUNDARY_RE.split(line):
108
+ sent = sent.strip()
109
+ if sent:
110
+ out.append((line_idx, sent))
111
+ return out
112
+
113
+
114
+ def is_table_like(sentence: str) -> bool:
115
+ """True for lines that are data rather than prose (skip scoring)."""
116
+ if "|" in sentence:
117
+ return True
118
+ compact = sentence.replace(" ", "")
119
+ if not compact:
120
+ return False
121
+ digits = sum(ch.isdigit() for ch in compact)
122
+ return digits / len(compact) >= _TABLE_DIGIT_RATIO
123
+
124
+
125
+ def starts_anaphoric(sentence: str) -> bool:
126
+ """True if the sentence's first word leans on the preceding sentence."""
127
+ m = _FIRST_WORD_RE.search(sentence[:24])
128
+ return bool(m) and m.group(0).lower() in _ANAPHORIC_STARTS
129
+
130
+
131
+ def _tokenize(text: str) -> list[str]:
132
+ return re.sub(r"[^\w\s]", " ", text.lower()).split()
133
+
134
+
135
+ def score_lexical(query: str, sentences: list[str]) -> list[float]:
136
+ """IDF-weighted query-term coverage per sentence, in [0, 1].
137
+
138
+ IDF is computed over the sentences of THIS call (the per-result corpus):
139
+ a query term appearing in every sentence carries no selection signal,
140
+ while a rare one dominates. Zero-dep fallback scorer.
141
+ """
142
+ q_terms = list(dict.fromkeys(_tokenize(query)))
143
+ if not q_terms or not sentences:
144
+ return [0.0] * len(sentences)
145
+ sent_tokens = [set(_tokenize(s)) for s in sentences]
146
+ n = len(sentences)
147
+ idf = {t: math.log(1 + n / (1 + sum(t in st for st in sent_tokens)))
148
+ for t in q_terms}
149
+ total = sum(idf.values()) or 1.0
150
+ return [sum(idf[t] for t in q_terms if t in st) / total
151
+ for st in sent_tokens]
152
+
153
+
154
+ def _deps_available() -> bool:
155
+ global _models_unavailable
156
+ if _models_unavailable:
157
+ return False
158
+ try:
159
+ import sentence_transformers # noqa: F401
160
+ except ImportError:
161
+ logger.warning(
162
+ "sentence-transformers not installed - compression degrades to "
163
+ "the lexical scorer. Install webfetch-llm[rerank]."
164
+ )
165
+ _models_unavailable = True
166
+ return False
167
+ return True
168
+
169
+
170
+ def score_biencoder(query: str, sentences: list[str]) -> list[float] | None:
171
+ """Cosine similarity of each sentence to the query; None without [rerank]."""
172
+ global _bi_model
173
+ if not _deps_available():
174
+ return None
175
+ from sentence_transformers import SentenceTransformer
176
+ with _init_lock:
177
+ if _bi_model is None:
178
+ _bi_model = SentenceTransformer(BIENCODER_MODEL)
179
+ q_vec = _bi_model.encode([query], normalize_embeddings=True,
180
+ show_progress_bar=False)[0]
181
+ s_vecs = _bi_model.encode(sentences, normalize_embeddings=True,
182
+ show_progress_bar=False)
183
+ return [float(v @ q_vec) for v in s_vecs]
184
+
185
+
186
+ def score_crossencoder(query: str, sentences: list[str]) -> list[float] | None:
187
+ """Joint (query, sentence) relevance scores; None without [rerank].
188
+
189
+ Same ms-marco model as the ranking cascade's stage 3. O(N) forward
190
+ passes, but N here is the ~15-25 sentences of one tool result - tens of
191
+ milliseconds, not the cost profile that keeps cross-encoders out of
192
+ full-list ranking.
193
+ """
194
+ global _ce_model
195
+ if not _deps_available():
196
+ return None
197
+ from sentence_transformers import CrossEncoder
198
+ with _init_lock:
199
+ if _ce_model is None:
200
+ _ce_model = CrossEncoder(CROSSENCODER_MODEL)
201
+ scores = _ce_model.predict([(query, s) for s in sentences],
202
+ show_progress_bar=False)
203
+ return [float(s) for s in scores]
204
+
205
+
206
+ def _select_indices(scores: list[float], sentences: list[str],
207
+ policy: str, param: float) -> set[int]:
208
+ """Pick sentence indices for one chunk under the selection policy.
209
+
210
+ Policies:
211
+ ratio: best-scoring sentences until ~param of the chunk's chars kept.
212
+ topk: best int(param) sentences.
213
+ threshold: every sentence scoring >= param.
214
+
215
+ Always returns at least one index (the best-scoring sentence) so a chunk
216
+ can never compress to nothing.
217
+ """
218
+ order = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)
219
+ keep: set[int] = set()
220
+ if policy == "ratio":
221
+ total = sum(len(s) for s in sentences)
222
+ used = 0
223
+ for i in order:
224
+ if keep and used + len(sentences[i]) > param * total:
225
+ continue # try smaller later sentences - greedy knapsack
226
+ keep.add(i)
227
+ used += len(sentences[i])
228
+ elif policy == "topk":
229
+ keep = set(order[: max(1, int(param))])
230
+ elif policy == "threshold":
231
+ keep = {i for i in order if scores[i] >= param}
232
+ else:
233
+ raise ValueError(f"unknown compression policy: {policy!r}")
234
+ if not keep:
235
+ keep = {order[0]}
236
+ return keep
237
+
238
+
239
+ def compress_chunks(
240
+ query: str,
241
+ chunks: list[Chunk],
242
+ scorer: str = COMPRESS_SCORER,
243
+ policy: str = COMPRESS_POLICY,
244
+ param: float = COMPRESS_PARAM,
245
+ anaphora_guard: bool = COMPRESS_ANAPHORA_GUARD,
246
+ table_guard: bool = COMPRESS_TABLE_GUARD,
247
+ dedup: bool = COMPRESS_DEDUP,
248
+ ) -> list[Chunk]:
249
+ """Compress each chunk to its query-relevant sentences.
250
+
251
+ Returns NEW Chunk objects - inputs are never mutated, because cached
252
+ chunk instances may be shared with other readers. Kept sentences stay in
253
+ document order; sentences from the same source line rejoin with a space,
254
+ different lines with a newline (preserves table/list structure).
255
+
256
+ On any unexpected failure the original chunks are returned unchanged -
257
+ this runs on the tool path, where a formatting bug must never turn a
258
+ good search into an error.
259
+
260
+ Args:
261
+ query: The search query driving relevance.
262
+ chunks: Ranked chunks (best first) from the pipeline.
263
+ scorer: "biencoder", "crossencoder", "lexical", or "lead"
264
+ (position baseline).
265
+ policy: Selection policy - "ratio", "topk", or "threshold".
266
+ param: Policy parameter (ratio fraction, k, or score cutoff).
267
+ anaphora_guard: Retain the predecessor of pronoun-initial keeps.
268
+ table_guard: Keep table-like lines unconditionally.
269
+ dedup: Drop sentences already emitted by an earlier chunk.
270
+
271
+ Returns:
272
+ Compressed chunks, same order; chunks fully deduplicated away are
273
+ dropped. Empty input returns [].
274
+ """
275
+ if not chunks:
276
+ return []
277
+ try:
278
+ return _compress(query, chunks, scorer, policy, param,
279
+ anaphora_guard, table_guard, dedup)
280
+ except Exception:
281
+ logger.warning("compression failed - returning chunks uncompressed",
282
+ exc_info=True)
283
+ return chunks
284
+
285
+
286
+ def _compress(query: str, chunks: list[Chunk], scorer: str, policy: str,
287
+ param: float, anaphora_guard: bool, table_guard: bool,
288
+ dedup: bool) -> list[Chunk]:
289
+ per_chunk = [split_sentences(c.text) for c in chunks]
290
+
291
+ # Score every sentence across all chunks in ONE batch (matters for the
292
+ # bi-encoder: one encode call instead of one per chunk).
293
+ flat = [s for sents in per_chunk for (_, s) in sents]
294
+ if scorer == "biencoder":
295
+ flat_scores = score_biencoder(query, flat)
296
+ if flat_scores is None:
297
+ flat_scores = score_lexical(query, flat)
298
+ elif scorer == "crossencoder":
299
+ flat_scores = score_crossencoder(query, flat)
300
+ if flat_scores is None:
301
+ flat_scores = score_lexical(query, flat)
302
+ elif scorer == "lexical":
303
+ flat_scores = score_lexical(query, flat)
304
+ elif scorer == "lead":
305
+ # Position baseline: earlier in chunk = higher. Eval control arm.
306
+ flat_scores = []
307
+ for sents in per_chunk:
308
+ flat_scores.extend(1.0 / (1 + i) for i in range(len(sents)))
309
+ else:
310
+ raise ValueError(f"unknown compression scorer: {scorer!r}")
311
+
312
+ out: list[Chunk] = []
313
+ seen_norm: set[str] = set()
314
+ pos = 0
315
+ for chunk, sents in zip(chunks, per_chunk):
316
+ scores = flat_scores[pos: pos + len(sents)]
317
+ pos += len(sents)
318
+ if not sents:
319
+ continue
320
+ if len(sents) == 1:
321
+ keep = {0}
322
+ else:
323
+ texts = [s for (_, s) in sents]
324
+ keep = _select_indices(scores, texts, policy, param)
325
+ if table_guard:
326
+ keep |= {i for i, t in enumerate(texts) if is_table_like(t)}
327
+ if anaphora_guard:
328
+ # Walk each kept sentence's predecessors so chains resolve
329
+ # ("It ... " preceded by "This ..." pulls in both).
330
+ for i in sorted(keep):
331
+ j = i
332
+ while (j > 0 and starts_anaphoric(texts[j])
333
+ and (j - 1) not in keep):
334
+ keep.add(j - 1)
335
+ j -= 1
336
+
337
+ kept = [sents[i] for i in sorted(keep)]
338
+ if dedup:
339
+ deduped = []
340
+ for line_idx, s in kept:
341
+ norm = " ".join(_tokenize(s))
342
+ if len(s) >= _DEDUP_MIN_CHARS and norm in seen_norm:
343
+ continue
344
+ seen_norm.add(norm)
345
+ deduped.append((line_idx, s))
346
+ kept = deduped
347
+ if not kept:
348
+ continue # chunk was pure overlap-duplicate content
349
+
350
+ parts = [kept[0][1]]
351
+ for (prev_line, _), (line_idx, s) in zip(kept, kept[1:]):
352
+ parts.append(("\n" if line_idx != prev_line else " ") + s)
353
+ out.append(Chunk(text="".join(parts), url=chunk.url,
354
+ title=chunk.title, score=chunk.score))
355
+ return out
356
+
357
+
358
+ __all__ = ["compress_chunks", "split_sentences", "score_lexical",
359
+ "score_biencoder", "score_crossencoder", "is_table_like",
360
+ "starts_anaphoric"]
webfetch/config.py ADDED
@@ -0,0 +1,154 @@
1
+ """
2
+ Central constants and defaults for the webfetch pipeline.
3
+
4
+ All tuneable knobs live here so nothing is hardcoded in module logic.
5
+ Change a value here and it propagates everywhere - no grep-and-replace needed.
6
+ """
7
+
8
+ # --- Search ---
9
+ # How many URLs to retrieve from the search adapter per query.
10
+ DEFAULT_N_RESULTS: int = 10
11
+
12
+ # Which search provider to use when none is specified by the caller.
13
+ # "ddg" = DuckDuckGo (free, no key); see search/__init__.py for all.
14
+ DEFAULT_SEARCH_PROVIDER: str = "ddg"
15
+
16
+ # --- Fetch ---
17
+ # Seconds before an HTTP fetch is abandoned. Keeps slow pages from
18
+ # blocking the pipeline.
19
+ FETCH_TIMEOUT_SECS: int = 10
20
+
21
+ # Thread pool size for concurrent URL fetching. Fetching is IO-bound (network
22
+ # waits, not CPU), so more workers than cores is fine and cuts wall time a lot.
23
+ DEFAULT_FETCH_WORKERS: int = 8
24
+
25
+ # Extracted text shorter than this suggests a JS-rendered SPA whose real
26
+ # content never reached the prose extractor - triggers the playwright
27
+ # fallback even though extraction technically "succeeded".
28
+ MIN_EXTRACTED_CHARS: int = 300
29
+
30
+ # --- Ranking ---
31
+ # Default cascade: hybrid fusion (full-list BM25 + bi-encoder rankings fused
32
+ # via RRF) -> cross-encoder. Fusion replaced the BM25-first gate after the
33
+ # gap-1 experiment measured recall 46% -> 54% at identical token cost - the
34
+ # lexical gate was dropping semantically-relevant chunks it could not see.
35
+ HYBRID_FUSION_TOP_K: int = 30 # fused chunks passed to the cross-encoder
36
+
37
+ # Used by the degraded (no-embeddings) path and by callers composing the
38
+ # old-style cascade manually.
39
+ BM25_TOP_K: int = 20 # after BM25: keep best 20 chunks
40
+ BIENCODER_TOP_K: int = 10 # after bi-encoder: keep best 10
41
+ CROSSENCODER_TOP_K: int = 5 # after cross-encoder: keep best 5
42
+
43
+ # Default models for optional reranking stages.
44
+ BIENCODER_MODEL: str = "all-MiniLM-L6-v2"
45
+ CROSSENCODER_MODEL: str = "cross-encoder/ms-marco-MiniLM-L-6-v2"
46
+
47
+ # --- Chunking ---
48
+ # Characters per text chunk fed into the ranker.
49
+ # 400 chars ~ 100 tokens - small enough for precise reranking, big
50
+ # enough for context.
51
+ DEFAULT_CHUNK_SIZE: int = 400
52
+
53
+ # Overlap between consecutive chunks to avoid splitting a key sentence
54
+ # at a boundary.
55
+ CHUNK_OVERLAP_RATIO: float = 0.10 # 10% overlap
56
+
57
+ # --- Token budget ---
58
+ # Maximum characters of ranked text sent to the LLM extraction call.
59
+ # ~6000 chars / 4 chars-per-token ~ 1500 tokens of context - cheap for
60
+ # haiku-class models.
61
+ DEFAULT_TOKEN_BUDGET: int = 6000
62
+
63
+ # --- Cache ---
64
+ # Default path for the sqlite3 cache database.
65
+ DEFAULT_CACHE_DB: str = "~/.webfetch/cache.db"
66
+
67
+ # How long cached results are kept before expiry. Acts as the hard ceiling
68
+ # for all rows (pages, legacy query rows without a freshness class).
69
+ DEFAULT_CACHE_TTL_DAYS: int = 90
70
+
71
+ # Volatility-aware TTLs, resolved at READ time so retuning these applies to
72
+ # already-cached rows. Effective TTL = min(TTL of the row's stored class,
73
+ # TTL of the caller's freshness hint, the ttl_days ceiling).
74
+ TTL_BY_FRESHNESS: dict[str, int] = {
75
+ "realtime": 15 * 60, # prices, scores, breaking news
76
+ "recent": 7 * 86400, # things that change over weeks/months
77
+ "stable": 90 * 86400, # historical/definitional facts, specs
78
+ }
79
+
80
+ # Class used when there is no model hint and the classifier is unsure,
81
+ # and for legacy rows cached before freshness existed.
82
+ DEFAULT_FRESHNESS: str = "recent"
83
+
84
+ # --- Search resilience ---
85
+ # Circuit breaker: an engine failing this many CONSECUTIVE times (errors,
86
+ # or silent-block empties) is benched for the cooldown, then given one
87
+ # half-open probe. Stops burning latency on a dead/blocking engine.
88
+ SEARCH_BREAKER_THRESHOLD: int = 3
89
+ SEARCH_BREAKER_COOLDOWN_SECS: float = 300.0
90
+
91
+ # In fusion, an engine's empty response only counts as a breaker failure
92
+ # when a peer engine returned at least this many results for the SAME
93
+ # query - distinguishes a silent block from a genuinely hard query.
94
+ FUSION_PEER_EMPTY_MIN: int = 3
95
+
96
+ # --- Cost receipts ---
97
+ # Baseline for savings estimates (webfetch/receipts.py). Both Anthropic and
98
+ # OpenAI charge $10/1k hosted searches (verified 2026-07); the hosted tools
99
+ # also inject ~17.4k content tokens per call vs our ~3.5k compressed
100
+ # (measured, Layer 3 eval 2026-07-14). Token price defaults to Opus-class
101
+ # input - override per call for cheaper models.
102
+ RECEIPT_HOSTED_SEARCH_FEE: float = 10.00 / 1000
103
+ RECEIPT_HOSTED_TOKENS_PER_CALL: int = 17400
104
+ RECEIPT_TOKEN_PRICE_PER_MTOK: float = 5.00
105
+
106
+ # --- LLM extraction ---
107
+ # Default model for the extraction step. Cheapest capable model by default.
108
+ DEFAULT_EXTRACT_MODEL: str = "claude-haiku-4-5-20251001"
109
+
110
+ # --- Semantic query cache ---
111
+ # Thresholds picked by the eval harness (evals/run_matcher_eval.py, 247-pair
112
+ # factoid-enriched set): bi >= 0.60 keeps paraphrase recall at 0.98 as a
113
+ # shortlist gate; NLI bidirectional entailment >= 0.97 gives precision 0.955
114
+ # with zero trusted-negative false positives. See matcher_recommendation.json.
115
+ SEMCACHE_BI_THRESHOLD: float = 0.60
116
+ SEMCACHE_CE_THRESHOLD: float = 0.97
117
+
118
+ # NLI verifier won the 4-model bake-off: only model to clear the 0.95
119
+ # precision bar, natively rejects entity/number swaps (Portland trap: 0.000).
120
+ SEMCACHE_CE_MODEL: str = "cross-encoder/nli-deberta-v3-base"
121
+
122
+ # Verify only the top cosine candidate - precision-first; Layer 2 measured
123
+ # zero wrong-target matches, so deeper candidate lists buy nothing.
124
+ SEMCACHE_MAX_CANDIDATES: int = 1
125
+
126
+ # --- Tool mode ---
127
+ # Max characters of ranked context returned per web_search tool call.
128
+ # Larger than DEFAULT_TOKEN_BUDGET because in tool mode the calling model is
129
+ # the extractor and benefits from a bit more surrounding context.
130
+ DEFAULT_TOOL_RESULT_BUDGET: int = 8000
131
+
132
+ # --- Sentence-level compression (tool-result formatting) ---
133
+ # Applied AFTER the cache read, so cached rows stay full-text and retuning
134
+ # these never invalidates the cache. Values picked by the eval sweep
135
+ # (evals/run_compression_eval.py, 50 captured production results): this
136
+ # config measured recall 29/50 vs 29/50 uncompressed (zero drop, 29/29
137
+ # answer survival) at 50% of baseline tokens (332 vs 665 mean). The
138
+ # cross-encoder scorer is what preserves recall - biencoder at the same
139
+ # tokens loses 3-4 answers. Without [rerank] it degrades to the lexical
140
+ # scorer (measured: 27/29 survival at 51%).
141
+ COMPRESSION_ENABLED: bool = True
142
+ COMPRESS_SCORER: str = "crossencoder" # | "biencoder" | "lexical" | "lead"
143
+ COMPRESS_POLICY: str = "ratio" # "ratio" | "topk" | "threshold"
144
+ COMPRESS_PARAM: float = 0.5 # keep best sentences, <= 50% of chunk chars
145
+ COMPRESS_ANAPHORA_GUARD: bool = True # +14 tokens, keeps pronouns resolvable
146
+ COMPRESS_TABLE_GUARD: bool = True # ablation: protects 1 answer of 29
147
+ COMPRESS_DEDUP: bool = True # ablation: -13 tokens free (overlap dupes)
148
+
149
+ # Tool-result context format (build_context). Same eval: merging same-URL
150
+ # chunks under one header + hostname-only headers cut the fixed header
151
+ # overhead (26% of an uncompressed result) with zero measured recall cost -
152
+ # titles stay because answers live in them (extraction-hardening eval).
153
+ TOOL_MERGE_SOURCES: bool = True
154
+ TOOL_HEADER_STYLE: str = "domain" # "full" | "domain"
@@ -0,0 +1 @@
1
+ {"model": "all-MiniLM-L6-v2", "source": "FreshQA (CC), full 377 rows", "classes": {"realtime": [0.012145215645432472, -0.0018631262937560678, -0.06274841725826263, -0.007661583833396435, -0.027888312935829163, 0.0621718093752861, -0.021171551197767258, 0.02851240523159504, -0.011449315585196018, 0.02597236819565296, -0.04086684435606003, -0.006424089893698692, -0.02788771130144596, 0.02362537570297718, -0.03769982233643532, 0.017427198588848114, -0.017687330022454262, -0.08234846591949463, 0.08868501335382462, -0.10261496156454086, -0.007088787388056517, 0.002663521096110344, 0.0016332603991031647, 0.00045282961218617857, 0.08852767199277878, -0.03599361702799797, -0.056443117558956146, -0.022277243435382843, -0.07022085040807724, -0.016778215765953064, -0.06464487314224243, -0.02756372094154358, 0.027233166620135307, 0.03248134255409241, -0.04783632978796959, -0.04881690815091133, 0.02403809316456318, 0.0007506250985898077, 0.02884712442755699, 0.012483729049563408, -0.02234613709151745, -0.10250423848628998, 0.016286777332425117, 0.012731242924928665, 0.03766198456287384, -0.025340810418128967, -0.016598522663116455, 0.02768656052649021, 0.054936714470386505, 0.11487270146608353, -0.03534339368343353, 0.03725761920213699, -0.017243774607777596, 0.009950782172381878, 0.06690368056297302, 0.005692985374480486, -0.044698603451251984, 0.0004932482843287289, 0.04355696961283684, 0.01979084312915802, -0.007639622315764427, -0.03338771313428879, -0.10322568565607071, 0.03135615959763527, 0.01046554371714592, -0.04580345377326012, -0.026506880298256874, -0.07263809442520142, -0.014567894861102104, -0.02869809791445732, 0.01659376546740532, 0.010415657423436642, 0.006484807003289461, -0.08891996741294861, 0.023524625226855278, 0.01739215850830078, 0.035195961594581604, 0.03747803717851639, 0.003209460061043501, -0.0376424640417099, 0.007335755508393049, -0.08569755405187607, -0.015708794817328453, -0.021274028345942497, 0.056080762296915054, 0.03369034081697464, -0.032607536762952805, 0.07464656978845596, -0.056957997381687164, 0.014871630817651749, -0.05218343064188957, 0.029951659962534904, -0.01689605414867401, 0.052715156227350235, -0.1119815930724144, -0.0018735149642452598, -0.028360188007354736, -0.004249660298228264, -0.04698532447218895, 0.11000624299049377, -0.021992405876517296, 0.07617287337779999, 0.042818401008844376, 0.0037722475826740265, 0.056841593235731125, 0.030398523434996605, 0.06313391029834747, 0.028064215555787086, -0.033619530498981476, -0.026942992582917213, -0.05855797603726387, -0.009410723112523556, -0.023611513897776604, -0.0013498563785105944, -0.004817285109311342, -0.04733685776591301, 0.04180905967950821, 0.0655769407749176, 0.06571927666664124, 0.029141250997781754, 0.06606484204530716, 0.04993269219994545, 0.0006714511546306312, 0.010644162073731422, -0.09988965839147568, 0.016641344875097275, -0.017963502556085587, -7.996425952427355e-33, 0.04056042432785034, -0.08298078179359436, 0.0798611044883728, 0.03384505212306976, -0.0005813181633129716, -0.013754554092884064, 0.008965825662016869, -0.018057813867926598, -0.055044565349817276, -0.07378089427947998, -0.019387418404221535, -0.06616166234016418, -0.041721466928720474, -0.11676525324583054, 0.0884120985865593, -0.0005623944452963769, -0.08393930643796921, 0.045821357518434525, -0.03545466437935829, 0.02201877534389496, 0.02102014608681202, 0.03818574175238609, 0.005251807626336813, -0.046063873916864395, 0.0017609883798286319, -0.012767121195793152, 0.016234265640378, -0.03738025575876236, 0.03839366137981415, 0.017702419310808182, 0.02254652976989746, -0.011753003112971783, -0.008132238872349262, 0.021470986306667328, 0.026390258222818375, 0.031572166830301285, -0.02854541316628456, -0.04545816779136658, 0.05124926194548607, 0.032728858292102814, 0.014105470851063728, -0.03141537681221962, 0.005319760646671057, -0.0634508728981018, -0.012997179292142391, 0.016193777322769165, -0.0289461612701416, 0.013243574649095535, 0.07796746492385864, 0.019404128193855286, -0.018053743988275528, -0.00757976621389389, -0.08551377803087234, -0.017113754525780678, 0.01956339366734028, -0.0217848252505064, 0.028527241200208664, -0.052100133150815964, 0.08539976924657822, 0.0727059468626976, -0.00771735142916441, 0.10828250646591187, -0.0010062677320092916, -0.0017656820127740502, -0.07601210474967957, 0.03872839733958244, 0.06104473024606705, -0.016915468499064445, -0.054150838404893875, 0.04271630197763443, 0.07039860635995865, -0.0031229224987328053, 0.010230539366602898, -0.0991160199046135, 0.017362629994750023, 0.013642113655805588, 0.0605914480984211, -0.0418471023440361, 0.02950374223291874, 0.060241036117076874, -0.047129079699516296, 0.007117462810128927, 0.07195363193750381, 0.028437813743948936, -0.06897237151861191, 0.02679777517914772, -0.042234260588884354, 0.026559779420495033, 0.012453213334083557, -0.025323128327727318, -0.062185730785131454, -0.07120354473590851, 0.03637091815471649, -0.04062645882368088, -0.06572014838457108, 3.756538684524308e-33, -0.019561057910323143, 0.0010238690301775932, 0.03263934329152107, 0.06091630086302757, 0.03326853737235069, -0.05022892355918884, 0.02662106789648533, 0.20079641044139862, 0.02190878428518772, 0.03251644968986511, 0.10060176253318787, -0.005975282751023769, 0.11721522361040115, 0.03066098317503929, 0.07437632977962494, 0.054939668625593185, 0.058271657675504684, -0.047429993748664856, -0.06029954552650452, -0.03828994557261467, -0.024580322206020355, 0.0824195146560669, -0.05107038468122482, 0.029964735731482506, 0.02194763906300068, -0.013980412855744362, 0.053490251302719116, 0.00391295924782753, -0.13898153603076935, -0.08299368619918823, 0.007824414409697056, -0.012302936986088753, -0.1006881594657898, 0.04606233164668083, -0.03258052095770836, 0.09304725378751755, 0.006648424081504345, -0.00026814319426193833, 0.028638750314712524, 0.07307504117488861, 0.05531078577041626, -0.017754772678017616, -0.012831241823732853, 0.16821259260177612, 0.05074983090162277, 0.03985459730029106, -0.05292412266135216, 0.08841066062450409, 0.05655524879693985, -0.008059504441916943, -0.07679089158773422, 0.026545094326138496, -0.07387138158082962, 0.01698480173945427, 0.01564045250415802, 0.03352392092347145, -0.07063072174787521, 0.03391892462968826, -0.013085504062473774, -0.018996283411979675, 0.008864144794642925, 0.026843387633562088, -0.04298478364944458, -0.009842624887824059, -0.013877437449991703, 7.742519665043801e-05, 0.01939546875655651, 0.03087269701063633, -0.06924799829721451, -0.010178822092711926, 0.05894096940755844, 0.006799302063882351, -0.06124420464038849, -0.021927375346422195, -0.09395230561494827, 0.10161103308200836, 0.05908716842532158, 0.04067505523562431, 0.03260904178023338, -0.020806023851037025, -0.0950707197189331, 0.053077954798936844, -0.056930337101221085, 0.044653572142124176, -0.012820999138057232, -0.003900255775079131, 0.06577984988689423, -0.1083097755908966, -0.018936049193143845, 0.04814876988530159, -0.03550277650356293, -0.0239479448646307, -0.004242108669131994, -0.09287764877080917, -0.017485903576016426, -4.011367948919542e-08, 0.05853461101651192, 0.14321114122867584, -0.09642613679170609, -0.068077951669693, 0.05938224494457245, 0.06424376368522644, 0.06816771626472473, 0.02329518087208271, 0.024788212031126022, 0.0216663908213377, 0.10322057455778122, -0.04315197840332985, 0.01926328055560589, -0.01207323744893074, -0.0005831048474647105, -0.04060975834727287, -0.025956114754080772, 0.04761594533920288, -0.008457469753921032, -0.041826892644166946, 0.026088401675224304, 0.031063469126820564, 0.07961023598909378, -0.09879054129123688, 0.0010286689503118396, 0.004794402047991753, -0.013164789415895939, 0.05569709464907646, -0.015505952760577202, -0.005806891713291407, 0.019580019637942314, 0.016695119440555573, -0.08401018381118774, -0.14084604382514954, -0.024840427562594414, 0.0046034264378249645, -0.04590464383363724, 0.02744842879474163, -0.03233516216278076, -0.08428578823804855, 0.010429917834699154, 0.06057283282279968, 0.010982648469507694, 0.06134016811847687, 0.04124429449439049, 0.029994413256645203, -0.023568596690893173, -0.037896428257226944, 0.020653579384088516, -0.08995361626148224, -0.07378672063350677, 0.02678094245493412, 0.054825007915496826, -0.020050644874572754, 0.019060198217630386, 0.002838355489075184, -0.025905828922986984, -0.046560149639844894, -0.06630369275808334, -0.03418434411287308, 0.11502895504236221, -0.12107022851705551, 0.04983608052134514, 0.08930587023496628], "recent": [0.037740834057331085, -0.025897791609168053, -0.07063736766576767, -0.0030858858954161406, -0.0385655052959919, 0.027679670602083206, -0.005790873430669308, 0.04536600410938263, 0.009580287151038647, 0.041824787855148315, 0.002868938259780407, -0.0330912210047245, 0.010563128627836704, 0.024402238428592682, -0.03492194414138794, 0.01100903283804655, -0.04160817340016365, -0.07459341734647751, 0.0861305445432663, -0.11681894958019257, 0.000607187335845083, -0.025019336491823196, 0.04239147529006004, -0.030158009380102158, 0.07918523997068405, -0.026850827038288116, -0.06338309496641159, -0.008769571781158447, -0.05210849270224571, -0.0670437440276146, -0.05640832707285881, -0.03528883308172226, 0.04560999572277069, 0.04130649194121361, -0.011238071136176586, -0.028030933812260628, 0.025195254012942314, 0.008335919119417667, 0.06000549718737602, -0.007748901378363371, 0.00048418165533803403, -0.07644284516572952, 0.03349863365292549, -0.007790022064000368, 0.0558280423283577, -0.0007756453705951571, -0.0057226321659982204, 0.02470877580344677, 0.020756904035806656, 0.07881532609462738, -0.005602407269179821, 0.02508022077381611, -0.016782615333795547, 0.03592527285218239, 0.07109124958515167, -0.04779466986656189, -0.04691481590270996, -0.0009210046846419573, 0.025139687582850456, 0.053828924894332886, -0.002145996317267418, -0.017301000654697418, -0.11765002459287643, 0.01028557401150465, -0.011623680591583252, -0.020329630002379417, -0.033269159495830536, -0.0458010695874691, -0.03787567839026451, 0.0015074169496074319, 0.05620766058564186, -0.018920497968792915, 0.010189317166805267, -0.03809700906276703, -0.0008899683598428965, -0.01289956271648407, 0.05275963246822357, 0.09183822572231293, -0.0025698968674987555, -0.05026788264513016, 0.03196341544389725, -0.04640628397464752, -0.02241269126534462, -0.01151073258370161, 0.05161017179489136, 0.0334722064435482, -0.028133969753980637, 0.060756903141736984, -0.05072283744812012, -0.0039917235262691975, -0.0464647077023983, 0.04364056885242462, 0.02522849477827549, 0.0595581941306591, -0.10544005036354065, 0.040252745151519775, -0.035451192408800125, 0.03506895899772644, -0.06946254521608353, 0.09570952504873276, -0.015216988511383533, 0.049334000796079636, 0.07752926647663116, 0.013933182694017887, -0.01580444537103176, 0.03478824347257614, 0.04229752719402313, 0.07602357864379883, -0.015588724054396152, 0.002205786295235157, -0.07989031821489334, -0.008642822504043579, -0.05011498183012009, -0.005334169138222933, -0.005515052936971188, -0.05893829092383385, 0.060996122658252716, 0.04934447258710861, 0.04784965515136719, 0.013765772804617882, 0.06403610110282898, 0.018437998369336128, -0.004653866868466139, 0.017492491751909256, -0.10154706239700317, 0.030901899561285973, -0.056882862001657486, -9.263546414476393e-33, 0.032071489840745926, -0.0631452277302742, 0.08019828796386719, 0.046986088156700134, -0.041777417063713074, 0.019012004137039185, 0.0045827883295714855, -0.0044275070540606976, -0.048470113426446915, -0.04983275383710861, -0.01822718232870102, -0.056053366512060165, -0.01828877255320549, -0.08254925161600113, 0.09881918132305145, 0.007796112447977066, -0.06468319147825241, 0.0760025680065155, -0.060067180544137955, 0.013709616847336292, 0.03374325856566429, 0.08879794180393219, 0.024127846583724022, -0.00841542985290289, 0.02462981455028057, 0.021595649421215057, 0.006472499575465918, -0.04018458351492882, 0.056987080723047256, 0.027295934036374092, 0.043269768357276917, -0.035261642187833786, -0.0553387887775898, 0.0012502741301432252, 0.022229338064789772, 0.03574218973517418, -0.030987700447440147, -0.05300057306885719, 0.03411632776260376, 0.03243895620107651, 0.01464895997196436, -0.03079126589000225, 0.012365912087261677, -0.023611238226294518, -0.019613271579146385, 0.020287813618779182, -0.05531042069196701, 0.007631160318851471, 0.04959418624639511, -0.0028270920738577843, -0.03970704972743988, -0.0012680422514677048, -0.10289273411035538, -0.016428861767053604, 0.051626332104206085, -0.024168673902750015, 0.01413167454302311, 0.004920460749417543, 0.06266112625598907, 0.08981794118881226, -0.03504524007439613, 0.10948540270328522, -0.030017409473657608, 0.05491165444254875, -0.028453201055526733, 0.03521046042442322, 0.03874867781996727, -0.028874889016151428, -0.029068557545542717, 0.009280937723815441, 0.03872179985046387, -0.013307967223227024, 0.025576138868927956, -0.059037335216999054, -0.02324475534260273, -0.018154621124267578, 0.05024878308176994, -0.03812074288725853, -0.0005742490175180137, 0.0959213599562645, -0.08256079256534576, 0.0028051540721207857, 0.07616480439901352, 0.0471491701900959, -0.032695621252059937, 0.047330521047115326, -0.03588801249861717, -0.001659886329434812, 0.010642332956194878, -0.006945728324353695, -0.09805209934711456, -0.05619858577847481, 0.027882959693670273, -0.05604751035571098, -0.10592898726463318, 4.5949629689841814e-33, -0.02613542228937149, -0.006271560676395893, 0.0457206629216671, 0.03334523364901543, 0.03378026932477951, -0.026292745023965836, 0.04472527652978897, 0.17767280340194702, -0.03315893933176994, 0.004677652381360531, 0.09173073619604111, -0.016673699021339417, 0.1146891638636589, 0.04301730915904045, 0.06296279281377792, 0.06419584900140762, 0.08006896078586578, -0.0630093514919281, -0.04692116379737854, -0.0552690327167511, -0.051715556532144547, 0.07841462641954422, 7.64712312957272e-05, 0.07047218084335327, -0.029466819018125534, 0.0026049974840134382, 0.010392696596682072, -0.02673671767115593, -0.12546704709529877, -0.05680812895298004, -0.004450392443686724, -0.011376120150089264, -0.11601763963699341, 0.055631838738918304, -0.030161255970597267, 0.05621485784649849, -0.009667915292084217, 0.014201724901795387, 0.011887979693710804, 0.11088187992572784, 0.054768797010183334, -0.011493510566651821, 0.015432603657245636, 0.15411017835140228, 0.02968861348927021, 0.01719019003212452, -0.04063909873366356, 0.06752496212720871, 0.016008097678422928, -0.02203967794775963, -0.0654606819152832, 0.018488537520170212, -0.09390315413475037, 0.0002816113119479269, 0.036626268178224564, -0.0027083519380539656, -0.07971291989088058, 0.04305737838149071, -0.005723634269088507, -0.017149874940514565, 0.03781665116548538, 0.036178670823574066, -0.03408880531787872, 0.04199240356683731, -0.011985711753368378, 0.0028120034839957952, -0.03526388108730316, 0.06770520657300949, -0.08036894351243973, -0.042860716581344604, 0.08275144547224045, -0.0190457571297884, -0.06447432190179825, -0.0013508021365851164, -0.11597707122564316, 0.09675540775060654, 0.025637278333306313, 0.03058444894850254, 0.04587564244866371, -0.0248523261398077, -0.09393557906150818, -0.0026686012279242277, -0.019358353689312935, 0.014417261816561222, -0.029305467382073402, 0.004780230578035116, 0.06614120304584503, -0.11459170281887054, 0.030194466933608055, 0.044906068593263626, -0.043565358966588974, -0.02789449878036976, 0.029291005805134773, -0.08918238431215286, -0.021739071235060692, -4.051126722970366e-08, 0.050828926265239716, 0.09618842601776123, -0.04176934435963631, -0.04011300578713417, 0.05205736681818962, 0.03308804705739021, 0.06941086053848267, 0.03233039379119873, 0.019226500764489174, 0.028578905388712883, 0.08651749789714813, -0.026446888223290443, -0.006831962149590254, -0.010019184090197086, -0.025466298684477806, -0.07011319696903229, -0.03966142237186432, 0.09581855684518814, -0.010219096206128597, -0.010008341632783413, -0.006578824482858181, 0.047231514006853104, 0.06408018618822098, -0.09780948609113693, 0.01514657773077488, -0.02015356533229351, 0.004760416690260172, 0.01761423423886299, 0.010450637899339199, -0.014002174139022827, 0.0002521428687032312, -0.008097398094832897, -0.06720700114965439, -0.13718897104263306, -0.01689615473151207, 0.014587732031941414, -0.028353476896882057, -0.02413005568087101, -0.034959759563207626, -0.11913619935512543, -0.00029614943196065724, 0.05826498195528984, 0.01299167051911354, 0.0897693783044815, 0.07465356588363647, 0.00587701378390193, -0.03150487691164017, -0.05592454597353935, 0.03574699908494949, -0.1141921803355217, -0.105095773935318, 0.04447728767991066, 0.0626031756401062, -0.01961544156074524, -0.007970171049237251, -0.0004538485372904688, -0.01703469268977642, -0.05490802973508835, -0.050680164247751236, -0.035791438072919846, 0.09396317601203918, -0.14849130809307098, 0.08407998085021973, 0.06755759567022324], "stable": [-0.009878501296043396, 0.0660642459988594, -0.05964508652687073, 0.07210763543844223, -0.03596775606274605, 0.02193950116634369, 0.010246319696307182, 0.01852239854633808, -0.04952670633792877, 0.020290177315473557, 0.023801632225513458, -0.05430629104375839, -0.007544808555394411, 0.012260775081813335, -0.06389766931533813, 0.03241700306534767, -0.053984079509973526, -0.07338772714138031, 0.05813191086053848, -0.06823553144931793, -0.005922270938754082, -0.011817307211458683, 0.03510754182934761, -0.008638807572424412, 0.06499254703521729, -0.01711813174188137, -0.024374794214963913, 0.007834694348275661, -0.015754472464323044, -0.03877580538392067, -0.041879672557115555, -0.052929844707250595, 0.030507778748869896, 0.03479808196425438, 0.0003642712254077196, -0.0018468601629137993, 0.09256058931350708, 0.01781170256435871, 0.03229816257953644, 0.0028201970271766186, -0.04097898676991463, -0.05748302862048149, 0.058425866067409515, 0.035652417689561844, 0.017063038423657417, -0.00208694557659328, 1.945298572536558e-05, 0.020170750096440315, 0.0525299571454525, 0.06233098730444908, 0.01996224746108055, -0.007750102784484625, -0.05245819315314293, -0.031384505331516266, 0.07049878686666489, 0.01562911458313465, -0.025653736665844917, 0.005772517994046211, 0.033708617091178894, 0.0173160582780838, -0.038299381732940674, -0.023969877511262894, -0.08515048772096634, 0.03904426097869873, 0.0337010882794857, -0.01881220191717148, -0.022112177684903145, -0.0830058604478836, -0.01255874801427126, -0.04907488450407982, 0.058949124068021774, -0.021205447614192963, 0.025199897587299347, -0.06132317706942558, -0.004188921302556992, -0.014213490299880505, 0.045258406549692154, 0.0980139970779419, -0.03531423583626747, -0.030920423567295074, -0.03895387426018715, -0.06878765672445297, -0.01498069055378437, 0.041184403002262115, 0.024011759087443352, 0.024984082207083702, -0.02330908738076687, 0.04412960261106491, -0.03279155492782593, -0.009370105341076851, -0.04633424058556557, 0.00010355184349464253, -0.007409134414047003, 0.05980905145406723, -0.10712308436632156, -0.0016119017964228988, -0.02891424112021923, 0.05164550617337227, -0.01999475061893463, 0.08253007382154465, 0.013118532486259937, 0.0412047877907753, 0.06558967381715775, 0.04939449205994606, 0.012494037859141827, 0.03203149884939194, 0.021725697442889214, 0.04889465123414993, -0.005762160290032625, -0.006175832357257605, -0.05037158355116844, -0.03631116822361946, 0.022419270128011703, 0.05585220083594322, 0.05395171791315079, -0.019489850848913193, 0.023703837767243385, 0.05224357917904854, 0.036405641585588455, -0.04141676053404808, 0.054783858358860016, 0.011990341357886791, -0.026010261848568916, 0.002385602332651615, -0.16738146543502808, 0.053104545921087265, -0.04563811421394348, -1.1385195433591571e-32, 0.03814498707652092, -0.0689789205789566, 0.04041396453976631, 0.08191869407892227, 0.014672595076262951, 0.005293590947985649, -0.006078558508306742, 0.019997579976916313, -0.040207281708717346, -0.0526622049510479, -0.009530546143651009, -0.1254967600107193, -0.05126592144370079, -0.12994910776615143, 0.06820761412382126, 0.03678153455257416, -0.08823713660240173, 0.02777552604675293, -0.03936967998743057, -0.020527733489871025, 0.011278019286692142, 0.0680217295885086, -0.0006382729043252766, -0.05814585089683533, -0.023165149614214897, 0.015882395207881927, 0.017337651923298836, -0.050064388662576675, 0.03945594280958176, 0.03115176595747471, 0.026074353605508804, -0.03448919579386711, -0.030477076768875122, 0.009733759798109531, 0.06363176554441452, 0.04730990156531334, -0.038697969168424606, -0.09644670784473419, 0.005985030438750982, 0.06498679518699646, 0.07189147919416428, -0.013101630844175816, 0.007560222875326872, -0.009547903202474117, -0.010277465917170048, -0.022786013782024384, -0.028719522058963776, 0.023598508909344673, 0.11158104240894318, -0.007700982037931681, -0.04821554571390152, -0.005352020729333162, -0.07801919430494308, -0.02650800719857216, 0.04496317356824875, 0.011938092298805714, 0.026169680058956146, -0.0013595058117061853, 0.05485756695270538, 0.06567436456680298, 0.0012906172778457403, 0.13648147881031036, 0.023734988644719124, 0.08998269587755203, -0.0095582390204072, 0.026485173031687737, 0.02947866916656494, -0.03661210834980011, -0.04421375319361687, -0.017298301681876183, 0.02297912910580635, -0.0008622432942502201, 0.043219152837991714, -0.07702449709177017, -0.048244915902614594, -0.0011753002181649208, -0.007110916543751955, -0.053615424782037735, -0.02565167471766472, 0.03301990404725075, -0.0672312006354332, 0.02777446247637272, 0.033486258238554, 0.055901262909173965, -0.06408447027206421, -0.010863428935408592, -0.015546686016023159, -0.001255270792171359, -0.008552140556275845, -0.014277186244726181, -0.11752666532993317, -0.03857119381427765, 0.036908265203237534, -0.10304670035839081, -0.1406712532043457, 5.338419432183107e-33, -0.035239845514297485, -0.024217309430241585, 0.05473233014345169, 0.022820761427283287, 0.028393885120749474, -0.04210122302174568, 0.035068243741989136, 0.15622800588607788, 0.0221007838845253, 0.03761698678135872, 0.07671965658664703, -0.02328198216855526, 0.10679496824741364, 0.025215674191713333, 0.073450468480587, 0.05074753239750862, 0.06479737162590027, -0.003941272385418415, -0.04551118239760399, -0.049933552742004395, -0.07364815473556519, 0.02552993968129158, -0.0714607834815979, 0.015462617389857769, -0.012316695414483547, 0.054023656994104385, 0.06723211705684662, -0.042197808623313904, -0.13952405750751495, -0.04436447471380234, -0.002935767639428377, 0.024541763588786125, -0.10958870500326157, 0.03318606689572334, -0.03618679940700531, 0.09100988507270813, 0.0005205267225392163, -0.0015193012077361345, 0.02488815411925316, 0.06314726918935776, 0.01987849734723568, -0.008496267721056938, 0.004493177868425846, 0.2061968892812729, 0.02684602700173855, 0.020799856632947922, -0.0240657776594162, 0.10361810028553009, 0.031669653952121735, 0.011405418626964092, -0.08602043241262436, 0.03416803479194641, -0.006508660968393087, -0.018249591812491417, 0.01674700528383255, -0.013997111469507217, -0.05165862664580345, 0.04553484916687012, 0.028897026553750038, -0.022380631417036057, 0.01289576105773449, -0.008146153762936592, -0.014556516893208027, 0.018003376200795174, -0.004316835198551416, 0.01513249333947897, -0.04365140199661255, 0.12434182316064835, -0.0656566470861435, -0.03079024702310562, 0.12046895921230316, 0.04114476218819618, -0.034990835934877396, 0.007664693985134363, -0.09582898765802383, 0.05962927266955376, 0.029368393123149872, 0.02580225095152855, 0.007645400706678629, -0.027397513389587402, -0.1363711804151535, 0.022010598331689835, -0.03838039189577103, 0.038143340498209, -0.02666621282696724, -0.015414954163134098, 0.030951106920838356, -0.06612234562635422, 0.007744719740003347, -0.0015180594054982066, -0.04261331632733345, -0.010056674480438232, 0.027605708688497543, -0.09087405353784561, -0.024939894676208496, -4.877212234077888e-08, 0.02553410269320011, 0.1265815794467926, -0.04538703337311745, -0.025004295632243156, 0.014260372146964073, 0.025149479508399963, 0.07109005749225616, 0.03147389367222786, -0.009967900812625885, 0.044358670711517334, -0.0068642375990748405, 0.014319314621388912, 0.02237335965037346, -0.004660268314182758, -0.003350135637447238, -0.05754431337118149, -0.027631275355815887, 0.04403224214911461, -0.024214953184127808, 0.03008132055401802, 0.047187186777591705, -0.018362415954470634, 0.04596714302897453, -0.08293260633945465, -0.00023648078786209226, -0.01700695976614952, 0.02500813640654087, 0.036679912358522415, -0.0171666257083416, -0.012540695257484913, -0.010196696035563946, 0.013239305466413498, -0.07839847356081009, -0.10489100217819214, -0.029697928577661514, 0.004295755177736282, 0.0014388053677976131, -0.013160772621631622, -0.0455457828938961, -0.15142354369163513, 0.012144980952143669, 0.14141105115413666, 0.0033308325801044703, 0.09230928868055344, 0.09918193519115448, 0.02047782950103283, -0.0018556228606030345, -0.01753951981663704, 0.013949376530945301, -0.06404218077659607, -0.09226547181606293, 0.06893295794725418, 0.06536483019590378, -0.020992908626794815, -0.019392572343349457, -0.04842235520482063, -0.004990136716514826, -0.04778695106506348, -0.07618878036737442, 0.020379342138767242, 0.08492814004421234, -0.06385879963636398, 0.06381313502788544, 0.023798275738954544]}}
@@ -0,0 +1,35 @@
1
+ """
2
+ Extract stage public interface.
3
+
4
+ Takes the top chunks from the ranking stage, concatenates them into a
5
+ token-budgeted context, calls an LLM, and returns structured values for the
6
+ requested extraction keys.
7
+
8
+ Pick an adapter explicitly:
9
+
10
+ from webfetch.extract import ClaudeExtractor
11
+ extractor = ClaudeExtractor()
12
+ values = extractor.extract(
13
+ chunks=top_chunks,
14
+ keys={
15
+ "accuracy": "measurement accuracy including units and conditions",
16
+ "range": "full measurement range with units",
17
+ "resolution": "smallest measurable increment with units",
18
+ },
19
+ )
20
+ """
21
+
22
+ from webfetch.extract.base import AbstractExtractor, build_context
23
+ from webfetch.extract.claude import ClaudeExtractor
24
+ from webfetch.extract.gemini import GeminiExtractor
25
+ from webfetch.extract.gpt import GPTExtractor
26
+ from webfetch.extract.groq import GroqExtractor
27
+
28
+ __all__ = [
29
+ "AbstractExtractor",
30
+ "ClaudeExtractor",
31
+ "GPTExtractor",
32
+ "GeminiExtractor",
33
+ "GroqExtractor",
34
+ "build_context",
35
+ ]