@wrenautomation/birdwatch 0.0.0-stage → 0.30.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/LICENSE.md +61 -0
- package/README.md +320 -2
- package/dist/app/cli.d.ts +4 -0
- package/dist/app/cli.js +149 -0
- package/dist/app/cli.js.map +1 -0
- package/dist/app/engine-cli.d.ts +44 -0
- package/dist/app/engine-cli.js +596 -0
- package/dist/app/engine-cli.js.map +1 -0
- package/dist/app/index.d.ts +6 -0
- package/dist/app/index.js +7 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/serve.d.ts +14 -0
- package/dist/app/serve.js +102 -0
- package/dist/app/serve.js.map +1 -0
- package/dist/document/body.d.ts +6 -0
- package/dist/document/body.js +18 -0
- package/dist/document/body.js.map +1 -0
- package/dist/document/check.d.ts +35 -0
- package/dist/document/check.js +68 -0
- package/dist/document/check.js.map +1 -0
- package/dist/document/extract.d.ts +81 -0
- package/dist/document/extract.js +226 -0
- package/dist/document/extract.js.map +1 -0
- package/dist/document/index.d.ts +11 -0
- package/dist/document/index.js +12 -0
- package/dist/document/index.js.map +1 -0
- package/dist/document/model.d.ts +10 -0
- package/dist/document/model.js +2 -0
- package/dist/document/model.js.map +1 -0
- package/dist/document/readers.d.ts +24 -0
- package/dist/document/readers.js +87 -0
- package/dist/document/readers.js.map +1 -0
- package/dist/document/types.d.ts +99 -0
- package/dist/document/types.js +93 -0
- package/dist/document/types.js.map +1 -0
- package/dist/engine/agent.d.ts +475 -0
- package/dist/engine/agent.js +990 -0
- package/dist/engine/agent.js.map +1 -0
- package/dist/engine/canonical.d.ts +4 -0
- package/dist/engine/canonical.js +55 -0
- package/dist/engine/canonical.js.map +1 -0
- package/dist/engine/context.d.ts +9 -0
- package/dist/engine/context.js +141 -0
- package/dist/engine/context.js.map +1 -0
- package/dist/engine/cost.d.ts +13 -0
- package/dist/engine/cost.js +31 -0
- package/dist/engine/cost.js.map +1 -0
- package/dist/engine/index.d.ts +16 -0
- package/dist/engine/index.js +17 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/judge.d.ts +158 -0
- package/dist/engine/judge.js +323 -0
- package/dist/engine/judge.js.map +1 -0
- package/dist/engine/people.d.ts +34 -0
- package/dist/engine/people.js +125 -0
- package/dist/engine/people.js.map +1 -0
- package/dist/engine/plan.d.ts +6 -0
- package/dist/engine/plan.js +7 -0
- package/dist/engine/plan.js.map +1 -0
- package/dist/engine/plans/index.d.ts +19 -0
- package/dist/engine/plans/index.js +104 -0
- package/dist/engine/plans/index.js.map +1 -0
- package/dist/engine/ports.d.ts +76 -0
- package/dist/engine/ports.js +28 -0
- package/dist/engine/ports.js.map +1 -0
- package/dist/engine/recall.d.ts +42 -0
- package/dist/engine/recall.js +71 -0
- package/dist/engine/recall.js.map +1 -0
- package/dist/engine/state.d.ts +96 -0
- package/dist/engine/state.js +162 -0
- package/dist/engine/state.js.map +1 -0
- package/dist/engine/steps.d.ts +98 -0
- package/dist/engine/steps.js +435 -0
- package/dist/engine/steps.js.map +1 -0
- package/dist/engine/tree.d.ts +76 -0
- package/dist/engine/tree.js +148 -0
- package/dist/engine/tree.js.map +1 -0
- package/dist/engine/types.d.ts +250 -0
- package/dist/engine/types.js +168 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/engine/view.d.ts +138 -0
- package/dist/engine/view.js +188 -0
- package/dist/engine/view.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger/files.d.ts +39 -0
- package/dist/ledger/files.js +113 -0
- package/dist/ledger/files.js.map +1 -0
- package/dist/ledger/ids.d.ts +4 -0
- package/dist/ledger/ids.js +9 -0
- package/dist/ledger/ids.js.map +1 -0
- package/dist/ledger/index.d.ts +11 -0
- package/dist/ledger/index.js +12 -0
- package/dist/ledger/index.js.map +1 -0
- package/dist/ledger/ledger.d.ts +46 -0
- package/dist/ledger/ledger.js +105 -0
- package/dist/ledger/ledger.js.map +1 -0
- package/dist/ledger/memory.d.ts +19 -0
- package/dist/ledger/memory.js +19 -0
- package/dist/ledger/memory.js.map +1 -0
- package/dist/ledger/records.d.ts +1424 -0
- package/dist/ledger/records.js +292 -0
- package/dist/ledger/records.js.map +1 -0
- package/dist/sources/arxiv.d.ts +105 -0
- package/dist/sources/arxiv.js +321 -0
- package/dist/sources/arxiv.js.map +1 -0
- package/dist/sources/exa.d.ts +19 -0
- package/dist/sources/exa.js +59 -0
- package/dist/sources/exa.js.map +1 -0
- package/dist/sources/fetcher.d.ts +35 -0
- package/dist/sources/fetcher.js +67 -0
- package/dist/sources/fetcher.js.map +1 -0
- package/dist/sources/google.d.ts +16 -0
- package/dist/sources/google.js +64 -0
- package/dist/sources/google.js.map +1 -0
- package/dist/sources/index.d.ts +17 -0
- package/dist/sources/index.js +18 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/junk.d.ts +10 -0
- package/dist/sources/junk.js +16 -0
- package/dist/sources/junk.js.map +1 -0
- package/dist/sources/ladder.d.ts +47 -0
- package/dist/sources/ladder.js +158 -0
- package/dist/sources/ladder.js.map +1 -0
- package/dist/sources/ledger.d.ts +7 -0
- package/dist/sources/ledger.js +35 -0
- package/dist/sources/ledger.js.map +1 -0
- package/dist/sources/paste.d.ts +8 -0
- package/dist/sources/paste.js +22 -0
- package/dist/sources/paste.js.map +1 -0
- package/dist/sources/searxng.d.ts +11 -0
- package/dist/sources/searxng.js +38 -0
- package/dist/sources/searxng.js.map +1 -0
- package/dist/sources/sites.d.ts +53 -0
- package/dist/sources/sites.js +285 -0
- package/dist/sources/sites.js.map +1 -0
- package/dist/sources/ytdlp.d.ts +43 -0
- package/dist/sources/ytdlp.js +117 -0
- package/dist/sources/ytdlp.js.map +1 -0
- package/package.json +61 -3
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* arXiv: search through its API, a paper read whole from its HTML page (the PDF when it has
|
|
3
|
+
* none). Both go to export.arxiv.org, the host arXiv names for programs, one call at a time and
|
|
4
|
+
* 3 seconds apart (arxiv.org's robots ask 15). Each hit's snippet leads with what triage
|
|
5
|
+
* weighs first: OpenAlex's citation count (one call per search, open data; a failed call leaves
|
|
6
|
+
* it out), the paper's comment (venue, code), then its abstract. A follow lists what a paper
|
|
7
|
+
* cites (`refs`, Semantic Scholar: OpenAlex holds no reference list for arXiv) or what cites it
|
|
8
|
+
* (`citers`, OpenAlex, most cited first). Free.
|
|
9
|
+
*/
|
|
10
|
+
import { httpError, transientStatus, transport } from "@wrenautomation/models";
|
|
11
|
+
import { DomUtils, parseDocument } from "htmlparser2";
|
|
12
|
+
import { defaultReaders } from "../document/index.js";
|
|
13
|
+
import { arxivId } from "../engine/canonical.js";
|
|
14
|
+
import { readResponse } from "./fetcher.js";
|
|
15
|
+
export const ARXIV = "https://export.arxiv.org";
|
|
16
|
+
export const OPENALEX = "https://api.openalex.org/works";
|
|
17
|
+
export const S2 = "https://api.semanticscholar.org/graph/v1/paper";
|
|
18
|
+
/** arXiv's rule for programs: one call every 3 seconds at most. */
|
|
19
|
+
export const ARXIV_GAP_MS = 3_000;
|
|
20
|
+
const STOP = new Set("a an and are as at be by can do does for from how in into is it of on or that the their this to under what when which who why with without".split(" "));
|
|
21
|
+
/**
|
|
22
|
+
* The terms as arXiv's query: every content word in any field (`any`: one of them), inside the
|
|
23
|
+
* categories when given (`cs.AI`, `cs.CL`).
|
|
24
|
+
*/
|
|
25
|
+
export function arxivQuery(terms, categories = [], any = false) {
|
|
26
|
+
const words = [
|
|
27
|
+
...new Set(terms.toLowerCase().match(/[\p{L}\p{N}][\p{L}\p{N}-]*/gu) ?? []),
|
|
28
|
+
].filter((w) => w.length > 1 && !STOP.has(w));
|
|
29
|
+
if (!words.length)
|
|
30
|
+
throw new Error(`arxiv: no words to search in "${terms}"`);
|
|
31
|
+
const body = words.map((w) => `all:"${w}"`).join(any ? " OR " : " AND ");
|
|
32
|
+
const cats = categories.map((c) => `cat:${c}`).join(" OR ");
|
|
33
|
+
return cats ? `(${body}) AND (${cats})` : body;
|
|
34
|
+
}
|
|
35
|
+
const flat = (s) => s.replace(/\s+/g, " ").trim();
|
|
36
|
+
/** The API's Atom feed as papers, and how many matched in all. */
|
|
37
|
+
export function feedPapers(xml) {
|
|
38
|
+
const doc = parseDocument(xml, { xmlMode: true });
|
|
39
|
+
const one = (name, under) => {
|
|
40
|
+
const [el] = DomUtils.getElementsByTagName(name, under, true, 1);
|
|
41
|
+
return el ? flat(DomUtils.textContent(el)) : "";
|
|
42
|
+
};
|
|
43
|
+
const papers = DomUtils.getElementsByTagName("entry", doc).flatMap((e) => {
|
|
44
|
+
let id = null;
|
|
45
|
+
try {
|
|
46
|
+
id = arxivId(new URL(one("id", e)));
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
if (!id)
|
|
50
|
+
return [];
|
|
51
|
+
const published = one("published", e).slice(0, 10);
|
|
52
|
+
const comment = one("arxiv:comment", e);
|
|
53
|
+
return [
|
|
54
|
+
{
|
|
55
|
+
id,
|
|
56
|
+
title: one("title", e),
|
|
57
|
+
abstract: one("summary", e),
|
|
58
|
+
authors: DomUtils.getElementsByTagName("author", e).map((a) => one("name", a)),
|
|
59
|
+
...(published ? { published } : {}),
|
|
60
|
+
...(comment ? { comment } : {}),
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
});
|
|
64
|
+
return { total: Number(one("opensearch:totalResults", doc)) || 0, papers };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Whether an OpenAlex row is the paper. A row may be the published version merged with the
|
|
68
|
+
* preprint (an ACL DOI, not arXiv's), so it is when it names the id anywhere, never a longer id.
|
|
69
|
+
*/
|
|
70
|
+
const names = (row, id) => new RegExp(`(^|[^\\d])${id.toLowerCase().replace(".", "\\.")}([^\\d]|$)`).test(JSON.stringify(row).toLowerCase());
|
|
71
|
+
/** Each id's citation count from OpenAlex's rows. */
|
|
72
|
+
export function citedOf(rows, ids) {
|
|
73
|
+
const out = new Map();
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
const count = row.cited_by_count;
|
|
76
|
+
if (typeof count !== "number")
|
|
77
|
+
continue;
|
|
78
|
+
for (const id of ids)
|
|
79
|
+
if (!out.has(id) && names(row, id))
|
|
80
|
+
out.set(id, count);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/** OpenAlex keeps an abstract as each word's positions; the words back in order. */
|
|
85
|
+
export function abstractOf(index) {
|
|
86
|
+
if (!index || typeof index !== "object")
|
|
87
|
+
return "";
|
|
88
|
+
const at = [];
|
|
89
|
+
for (const [word, spots] of Object.entries(index))
|
|
90
|
+
if (Array.isArray(spots))
|
|
91
|
+
for (const i of spots)
|
|
92
|
+
if (typeof i === "number")
|
|
93
|
+
at[i] = word;
|
|
94
|
+
return at.filter(Boolean).join(" ");
|
|
95
|
+
}
|
|
96
|
+
const authorLine = (names) => names.length > 3 ? `${names.slice(0, 3).join(", ")} et al.` : names.join(", ");
|
|
97
|
+
export function workHit(w) {
|
|
98
|
+
let url;
|
|
99
|
+
for (const l of w.links) {
|
|
100
|
+
try {
|
|
101
|
+
const id = arxivId(new URL(l));
|
|
102
|
+
if (id)
|
|
103
|
+
url = `https://arxiv.org/abs/${id}`;
|
|
104
|
+
}
|
|
105
|
+
catch { }
|
|
106
|
+
if (url)
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
url ??= w.doi ? `https://doi.org/${w.doi.replace(/^https?:\/\/doi\.org\//, "")}` : w.links[0];
|
|
110
|
+
if (!url)
|
|
111
|
+
return null;
|
|
112
|
+
const snippet = [
|
|
113
|
+
w.lead ?? "",
|
|
114
|
+
w.cited !== undefined ? `Cited ${w.cited} times (${w.by}).` : "",
|
|
115
|
+
w.abstract ? `Abstract: ${w.abstract}` : "",
|
|
116
|
+
]
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
.join(" ");
|
|
119
|
+
const authors = authorLine(w.authors);
|
|
120
|
+
return {
|
|
121
|
+
url,
|
|
122
|
+
...(w.title ? { title: w.title } : {}),
|
|
123
|
+
...(authors ? { channel: authors } : {}),
|
|
124
|
+
...(w.date ? { date: w.date } : {}),
|
|
125
|
+
...(snippet ? { snippet } : {}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export const openAlexWork = (r) => {
|
|
129
|
+
const abstract = abstractOf(r.abstract_inverted_index);
|
|
130
|
+
return {
|
|
131
|
+
links: (r.locations ?? []).flatMap((l) => (l.landing_page_url ? [l.landing_page_url] : [])),
|
|
132
|
+
...(r.ids?.doi ? { doi: r.ids.doi } : {}),
|
|
133
|
+
...(r.display_name ? { title: r.display_name } : {}),
|
|
134
|
+
authors: (r.authorships ?? []).flatMap((a) => a.author?.display_name ?? []),
|
|
135
|
+
...(r.publication_date ? { date: r.publication_date } : {}),
|
|
136
|
+
...(typeof r.cited_by_count === "number" ? { cited: r.cited_by_count } : {}),
|
|
137
|
+
by: "OpenAlex",
|
|
138
|
+
...(abstract ? { abstract } : {}),
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
export const s2Work = (p) => {
|
|
142
|
+
const date = p.publicationDate ?? (p.year ? String(p.year) : undefined);
|
|
143
|
+
return {
|
|
144
|
+
links: [
|
|
145
|
+
...(p.externalIds?.ArXiv ? [`https://arxiv.org/abs/${p.externalIds.ArXiv}`] : []),
|
|
146
|
+
...(p.paperId ? [`https://www.semanticscholar.org/paper/${p.paperId}`] : []),
|
|
147
|
+
],
|
|
148
|
+
...(p.externalIds?.DOI ? { doi: p.externalIds.DOI } : {}),
|
|
149
|
+
...(p.title ? { title: p.title } : {}),
|
|
150
|
+
authors: (p.authors ?? []).flatMap((a) => a.name ?? []),
|
|
151
|
+
...(date ? { date } : {}),
|
|
152
|
+
...(typeof p.citationCount === "number" ? { cited: p.citationCount } : {}),
|
|
153
|
+
by: "Semantic Scholar",
|
|
154
|
+
...(p.abstract ? { abstract: p.abstract } : {}),
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
/** A paper as a hit: citations and the comment first, so a clipped snippet keeps them. */
|
|
158
|
+
export function paperHit(p, cited) {
|
|
159
|
+
const lead = [
|
|
160
|
+
cited !== undefined ? `Cited ${cited} times (OpenAlex).` : "",
|
|
161
|
+
p.comment ? `Comment: ${p.comment}` : "",
|
|
162
|
+
].filter(Boolean);
|
|
163
|
+
const authors = authorLine(p.authors);
|
|
164
|
+
return {
|
|
165
|
+
url: `https://arxiv.org/abs/${p.id}`,
|
|
166
|
+
...(p.title ? { title: p.title } : {}),
|
|
167
|
+
...(authors ? { channel: authors } : {}),
|
|
168
|
+
...(p.published ? { date: p.published } : {}),
|
|
169
|
+
snippet: [...lead, `Abstract: ${p.abstract}`].join(" "),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const paperId = (url) => {
|
|
173
|
+
try {
|
|
174
|
+
return arxivId(new URL(url));
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
export function arxivSource(o) {
|
|
181
|
+
const fetchFn = o.fetchFn ?? fetch;
|
|
182
|
+
const readers = o.readers ?? defaultReaders();
|
|
183
|
+
const gap = o.gapMs ?? ARXIV_GAP_MS;
|
|
184
|
+
let chain = Promise.resolve();
|
|
185
|
+
let last = Number.NEGATIVE_INFINITY;
|
|
186
|
+
// One arXiv call at a time, `gap` after the last one ended.
|
|
187
|
+
const paced = (url) => {
|
|
188
|
+
const run = chain.then(async () => {
|
|
189
|
+
const wait = last + gap - Date.now();
|
|
190
|
+
if (wait > 0)
|
|
191
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
192
|
+
try {
|
|
193
|
+
return await fetchFn(url, {
|
|
194
|
+
headers: { "user-agent": o.agent },
|
|
195
|
+
signal: AbortSignal.timeout(60_000),
|
|
196
|
+
}).catch((err) => {
|
|
197
|
+
throw transport("arxiv", err);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
last = Date.now();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
chain = run.catch(() => { });
|
|
205
|
+
return run;
|
|
206
|
+
};
|
|
207
|
+
const search = async (query, n) => {
|
|
208
|
+
const url = `${ARXIV}/api/query?${new URLSearchParams({
|
|
209
|
+
search_query: query,
|
|
210
|
+
start: "0",
|
|
211
|
+
max_results: String(n),
|
|
212
|
+
sortBy: "relevance",
|
|
213
|
+
})}`;
|
|
214
|
+
const res = await paced(url);
|
|
215
|
+
if (!res.ok)
|
|
216
|
+
throw httpError("arxiv", res);
|
|
217
|
+
return feedPapers(await res.text());
|
|
218
|
+
};
|
|
219
|
+
// OpenAlex and Semantic Scholar: other hosts, no 3 second rule.
|
|
220
|
+
const api = async (name, url, headers = {}) => {
|
|
221
|
+
const res = await fetchFn(url, {
|
|
222
|
+
headers: { "user-agent": o.agent, ...headers },
|
|
223
|
+
signal: AbortSignal.timeout(15_000),
|
|
224
|
+
}).catch((err) => {
|
|
225
|
+
throw transport(name, err);
|
|
226
|
+
});
|
|
227
|
+
if (!res.ok)
|
|
228
|
+
throw httpError(name, res);
|
|
229
|
+
return (await res.json());
|
|
230
|
+
};
|
|
231
|
+
const alex = (params) => api("openalex", `${OPENALEX}?${new URLSearchParams({ ...params, ...(o.openalexKey ? { api_key: o.openalexKey } : {}) })}`);
|
|
232
|
+
const refs = async (id, n) => {
|
|
233
|
+
const fields = "isInfluential,title,externalIds,citationCount,publicationDate,year,authors,abstract";
|
|
234
|
+
const body = await api("semanticscholar", `${S2}/arXiv:${id}/references?fields=${fields}&limit=1000`, o.s2Key ? { "x-api-key": o.s2Key } : {});
|
|
235
|
+
// A publisher may hide the list: `data` comes back empty, and the fetch step writes a gap.
|
|
236
|
+
const rows = (body.data ?? []).filter((r) => r.citedPaper?.title);
|
|
237
|
+
// The works the paper leans on (Semantic Scholar's influence flag) first: the most cited
|
|
238
|
+
// refs are often background (GPT-3), not what the paper builds on.
|
|
239
|
+
rows.sort((a, b) => Number(b.isInfluential ?? false) - Number(a.isInfluential ?? false) ||
|
|
240
|
+
(b.citedPaper?.citationCount ?? 0) - (a.citedPaper?.citationCount ?? 0));
|
|
241
|
+
return rows
|
|
242
|
+
.flatMap((r) => {
|
|
243
|
+
const w = s2Work(r.citedPaper);
|
|
244
|
+
return workHit(r.isInfluential ? { ...w, lead: "The paper leans on it." } : w) ?? [];
|
|
245
|
+
})
|
|
246
|
+
.slice(0, n);
|
|
247
|
+
};
|
|
248
|
+
const citers = async (id, n) => {
|
|
249
|
+
const found = await alex({ filter: `doi:10.48550/arxiv.${id}`, select: "id,ids,locations" });
|
|
250
|
+
const work = (found.results ?? []).find((r) => names(r, id));
|
|
251
|
+
const w = work?.id?.split("/").pop();
|
|
252
|
+
if (!w)
|
|
253
|
+
return [];
|
|
254
|
+
const body = await alex({
|
|
255
|
+
filter: `cites:${w}`,
|
|
256
|
+
sort: "cited_by_count:desc",
|
|
257
|
+
per_page: String(Math.min(n, 200)),
|
|
258
|
+
select: "id,ids,display_name,cited_by_count,publication_date,locations,authorships,abstract_inverted_index",
|
|
259
|
+
});
|
|
260
|
+
return (body.results ?? []).flatMap((r) => workHit(openAlexWork(r)) ?? []);
|
|
261
|
+
};
|
|
262
|
+
// A count is a hint: a failed call leaves it out.
|
|
263
|
+
const cited = async (ids) => ids.length
|
|
264
|
+
? alex({
|
|
265
|
+
filter: `doi:${ids.map((id) => `10.48550/arxiv.${id}`).join("|")}`,
|
|
266
|
+
select: "ids,cited_by_count,locations",
|
|
267
|
+
per_page: "50",
|
|
268
|
+
})
|
|
269
|
+
.then((body) => citedOf(body.results ?? [], ids))
|
|
270
|
+
.catch(() => new Map())
|
|
271
|
+
: new Map();
|
|
272
|
+
return {
|
|
273
|
+
name: "arxiv",
|
|
274
|
+
kind: "both",
|
|
275
|
+
cost: "free",
|
|
276
|
+
first: true,
|
|
277
|
+
keeps: (site) => /(^|\.)arxiv\.org$/.test(site),
|
|
278
|
+
async search(q) {
|
|
279
|
+
const n = o.n ?? 15;
|
|
280
|
+
// Every word first; short of n, the rest from any of them, by relevance.
|
|
281
|
+
const papers = (await search(arxivQuery(q.terms, o.categories), n)).papers;
|
|
282
|
+
if (papers.length < n) {
|
|
283
|
+
const have = new Set(papers.map((p) => p.id));
|
|
284
|
+
const more = (await search(arxivQuery(q.terms, o.categories, true), n)).papers;
|
|
285
|
+
papers.push(...more.filter((p) => !have.has(p.id)).slice(0, n - papers.length));
|
|
286
|
+
}
|
|
287
|
+
const counts = await cited(papers.map((p) => p.id));
|
|
288
|
+
return papers.map((p) => paperHit(p, counts.get(p.id)));
|
|
289
|
+
},
|
|
290
|
+
follows: (as, url) => (as === "refs" || as === "citers") && paperId(url) !== null,
|
|
291
|
+
async follow(as, url, n) {
|
|
292
|
+
const id = paperId(url);
|
|
293
|
+
if (!id)
|
|
294
|
+
throw new Error(`arxiv: not a paper: ${url}`);
|
|
295
|
+
if (as === "refs")
|
|
296
|
+
return refs(id, n);
|
|
297
|
+
if (as === "citers")
|
|
298
|
+
return citers(id, n);
|
|
299
|
+
throw new Error(`arxiv follows refs or citers, not ${as}`);
|
|
300
|
+
},
|
|
301
|
+
opens: (url) => paperId(url) !== null,
|
|
302
|
+
async open(h) {
|
|
303
|
+
const id = paperId(h.url);
|
|
304
|
+
if (!id)
|
|
305
|
+
throw new Error(`arxiv: not a paper: ${h.url}`);
|
|
306
|
+
// The HTML keeps tables and sections; older papers have only the PDF.
|
|
307
|
+
let res = await paced(`${ARXIV}/html/${id}`);
|
|
308
|
+
let shown = `https://arxiv.org/html/${id}`;
|
|
309
|
+
if (res.status === 404) {
|
|
310
|
+
await res.body?.cancel().catch(() => { });
|
|
311
|
+
res = await paced(`${ARXIV}/pdf/${id}`);
|
|
312
|
+
shown = `https://arxiv.org/pdf/${id}`;
|
|
313
|
+
}
|
|
314
|
+
if (transientStatus(res.status))
|
|
315
|
+
throw httpError("arxiv", res);
|
|
316
|
+
const doc = await readResponse(res, shown, readers, h, "arxiv");
|
|
317
|
+
return { ...doc, url: shown };
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=arxiv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arxiv.js","sourceRoot":"","sources":["../../src/sources/arxiv.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exa: `POST https://api.exa.ai/search`, a key per call from the ring; `findSimilar` for a
|
|
3
|
+
* follow's pages like one URL (its own site left out). Metered: the search, plus
|
|
4
|
+
* one highlight per result (a few sentences Exa picks for the query) as the hit's snippet, so
|
|
5
|
+
* triage has words to go on. Contents bill per result on top of the search.
|
|
6
|
+
*/
|
|
7
|
+
import type { Source } from "../engine/ports.js";
|
|
8
|
+
/** What one highlight costs Exa to make: sentences per result. */
|
|
9
|
+
export declare const HIGHLIGHT: {
|
|
10
|
+
readonly numSentences: 3;
|
|
11
|
+
readonly highlightsPerUrl: 1;
|
|
12
|
+
};
|
|
13
|
+
export declare const EXA_SEARCH = "https://api.exa.ai/search";
|
|
14
|
+
export declare const EXA_SIMILAR = "https://api.exa.ai/findSimilar";
|
|
15
|
+
export declare function exa(o: {
|
|
16
|
+
keys: readonly string[];
|
|
17
|
+
fetchFn?: typeof fetch;
|
|
18
|
+
n?: number;
|
|
19
|
+
}): Source;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exa: `POST https://api.exa.ai/search`, a key per call from the ring; `findSimilar` for a
|
|
3
|
+
* follow's pages like one URL (its own site left out). Metered: the search, plus
|
|
4
|
+
* one highlight per result (a few sentences Exa picks for the query) as the hit's snippet, so
|
|
5
|
+
* triage has words to go on. Contents bill per result on top of the search.
|
|
6
|
+
*/
|
|
7
|
+
import { httpError, transport } from "@wrenautomation/models";
|
|
8
|
+
/** What one highlight costs Exa to make: sentences per result. */
|
|
9
|
+
export const HIGHLIGHT = { numSentences: 3, highlightsPerUrl: 1 };
|
|
10
|
+
export const EXA_SEARCH = "https://api.exa.ai/search";
|
|
11
|
+
export const EXA_SIMILAR = "https://api.exa.ai/findSimilar";
|
|
12
|
+
const hitOf = (r) => ({
|
|
13
|
+
url: r.url,
|
|
14
|
+
...(r.title ? { title: r.title } : {}),
|
|
15
|
+
...(r.author ? { channel: r.author } : {}),
|
|
16
|
+
...(r.publishedDate ? { date: r.publishedDate.slice(0, 10) } : {}),
|
|
17
|
+
...(r.highlights?.[0]?.trim() ? { snippet: r.highlights[0].trim() } : {}),
|
|
18
|
+
});
|
|
19
|
+
export function exa(o) {
|
|
20
|
+
if (!o.keys.length)
|
|
21
|
+
throw new Error("exa: no key");
|
|
22
|
+
const fetchFn = o.fetchFn ?? fetch;
|
|
23
|
+
let turn = 0;
|
|
24
|
+
const post = async (url, body) => {
|
|
25
|
+
const key = o.keys[turn++ % o.keys.length];
|
|
26
|
+
const res = await fetchFn(url, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "x-api-key": key, "content-type": "application/json" },
|
|
29
|
+
body: JSON.stringify(body),
|
|
30
|
+
signal: AbortSignal.timeout(30_000),
|
|
31
|
+
}).catch((err) => {
|
|
32
|
+
throw transport("exa", err);
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok)
|
|
35
|
+
throw httpError("exa", res);
|
|
36
|
+
const out = (await res.json());
|
|
37
|
+
return (out.results ?? []).map(hitOf);
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
name: "exa",
|
|
41
|
+
kind: "search",
|
|
42
|
+
cost: "metered",
|
|
43
|
+
search: (q) => post(EXA_SEARCH, {
|
|
44
|
+
query: q.terms,
|
|
45
|
+
numResults: o.n ?? 10,
|
|
46
|
+
type: "auto",
|
|
47
|
+
contents: { highlights: HIGHLIGHT },
|
|
48
|
+
...(q.site ? { includeDomains: [q.site] } : {}),
|
|
49
|
+
}),
|
|
50
|
+
follows: (as) => as === "similar",
|
|
51
|
+
follow: (_as, url, n) => post(EXA_SIMILAR, {
|
|
52
|
+
url,
|
|
53
|
+
numResults: n,
|
|
54
|
+
excludeSourceDomain: true,
|
|
55
|
+
contents: { highlights: HIGHLIGHT },
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=exa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exa.js","sourceRoot":"","sources":["../../src/sources/exa.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The polite fetcher as an open source: one GET, the body read by `./document`'s reader for its media.
|
|
3
|
+
* It opens http(s) pages that are not videos. A 4xx, a media no reader takes or an empty page is
|
|
4
|
+
* a miss (a throw with the reason: the spend says so, the next source may try); a transport
|
|
5
|
+
* failure throws a Transient.
|
|
6
|
+
*/
|
|
7
|
+
import type { PoliteFetcher } from "@wrenautomation/read/fetch";
|
|
8
|
+
import { type Media, type Reader } from "../document/index.js";
|
|
9
|
+
import type { Source } from "../engine/ports.js";
|
|
10
|
+
export interface Opener {
|
|
11
|
+
open(url: string): Promise<Response>;
|
|
12
|
+
}
|
|
13
|
+
/** What a hit already shows for free, carried onto the document when the page has nothing better. */
|
|
14
|
+
interface Shown {
|
|
15
|
+
title?: string | undefined;
|
|
16
|
+
channel?: string | undefined;
|
|
17
|
+
date?: string | undefined;
|
|
18
|
+
length?: number | undefined;
|
|
19
|
+
}
|
|
20
|
+
/** An http(s) URL that is not a YouTube page: the `youtube` source reads those. */
|
|
21
|
+
export declare function isPage(url: string): boolean;
|
|
22
|
+
export declare function readResponse(res: Response, url: string, readers: Map<Media, Reader>, hit?: Shown, what?: string): Promise<{
|
|
23
|
+
url: string;
|
|
24
|
+
media: "html" | "pdf" | "text" | "video" | "audio";
|
|
25
|
+
text: string;
|
|
26
|
+
title?: string | undefined;
|
|
27
|
+
channel?: string | undefined;
|
|
28
|
+
date?: string | undefined;
|
|
29
|
+
length?: number | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function fetcherSource(o: {
|
|
32
|
+
fetcher: PoliteFetcher | Opener;
|
|
33
|
+
readers?: Map<Media, Reader>;
|
|
34
|
+
}): Source;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The polite fetcher as an open source: one GET, the body read by `./document`'s reader for its media.
|
|
3
|
+
* It opens http(s) pages that are not videos. A 4xx, a media no reader takes or an empty page is
|
|
4
|
+
* a miss (a throw with the reason: the spend says so, the next source may try); a transport
|
|
5
|
+
* failure throws a Transient.
|
|
6
|
+
*/
|
|
7
|
+
import { transport } from "@wrenautomation/models";
|
|
8
|
+
import { defaultReaders, mediaOf } from "../document/index.js";
|
|
9
|
+
import { youtubeId } from "../engine/canonical.js";
|
|
10
|
+
import { junkReason } from "./junk.js";
|
|
11
|
+
const free = (h) => ({
|
|
12
|
+
...(h.title ? { title: h.title } : {}),
|
|
13
|
+
...(h.channel ? { channel: h.channel } : {}),
|
|
14
|
+
...(h.date ? { date: h.date } : {}),
|
|
15
|
+
...(h.length !== undefined ? { length: h.length } : {}),
|
|
16
|
+
});
|
|
17
|
+
/** An http(s) URL that is not a YouTube page: the `youtube` source reads those. */
|
|
18
|
+
export function isPage(url) {
|
|
19
|
+
if (!/^https?:/.test(url))
|
|
20
|
+
return false;
|
|
21
|
+
try {
|
|
22
|
+
return !youtubeId(new URL(url));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function readResponse(res, url, readers, hit = {}, what = "fetcher") {
|
|
29
|
+
if (res.status >= 400) {
|
|
30
|
+
await res.body?.cancel().catch(() => { });
|
|
31
|
+
throw new Error(`${what}: HTTP ${res.status}`);
|
|
32
|
+
}
|
|
33
|
+
const type = res.headers.get("content-type");
|
|
34
|
+
const media = mediaOf(type, res.url || url);
|
|
35
|
+
const reader = media ? readers.get(media) : undefined;
|
|
36
|
+
if (!reader || media === "video" || media === "audio") {
|
|
37
|
+
await res.body?.cancel().catch(() => { });
|
|
38
|
+
throw new Error(`${what}: no reader for ${media ?? type ?? "an unknown media"}`);
|
|
39
|
+
}
|
|
40
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
41
|
+
const input = media === "pdf" ? { bytes } : { text: new TextDecoder("utf8", { fatal: false }).decode(bytes) };
|
|
42
|
+
const doc = await reader.read({ url: res.url || url, ...input, ...free(hit) });
|
|
43
|
+
if (!doc)
|
|
44
|
+
throw new Error(`${what}: nothing to read in the ${media}`);
|
|
45
|
+
const junk = junkReason(doc);
|
|
46
|
+
if (junk)
|
|
47
|
+
throw new Error(`${what}: ${junk}`);
|
|
48
|
+
return doc;
|
|
49
|
+
}
|
|
50
|
+
export function fetcherSource(o) {
|
|
51
|
+
const readers = o.readers ?? defaultReaders();
|
|
52
|
+
return {
|
|
53
|
+
name: "fetcher",
|
|
54
|
+
kind: "open",
|
|
55
|
+
cost: "free",
|
|
56
|
+
opens: isPage,
|
|
57
|
+
async open(h) {
|
|
58
|
+
if (!isPage(h.url))
|
|
59
|
+
throw new Error(`fetcher: not a page: ${h.url}`);
|
|
60
|
+
const res = await o.fetcher.open(h.url).catch((err) => {
|
|
61
|
+
throw transport("fetcher", err);
|
|
62
|
+
});
|
|
63
|
+
return readResponse(res, h.url, readers, h);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/sources/fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google's own page through the desk's browser (`web GET /google`): each organic result as a
|
|
3
|
+
* hit, and the AI Overview as one hit of its own. The Overview is a claim, never a proof: its
|
|
4
|
+
* text and the questions people also ask ride in that hit's snippet; each page it cites becomes
|
|
5
|
+
* a hit, so the proof comes from reading those. A captcha or a spent cap is a miss.
|
|
6
|
+
*/
|
|
7
|
+
import type { LadderClient } from "@wrenautomation/read/fetch";
|
|
8
|
+
import type { Source } from "../engine/ports.js";
|
|
9
|
+
import type { HitViewIn } from "../engine/types.js";
|
|
10
|
+
/** The Overview's hit: Google's search URL for the terms, its fragment naming it. */
|
|
11
|
+
export declare const overviewUrl: (terms: string) => string;
|
|
12
|
+
export declare function serpHits(body: unknown, terms: string): HitViewIn[];
|
|
13
|
+
export declare function googleSource(o: {
|
|
14
|
+
sites: LadderClient;
|
|
15
|
+
n?: number;
|
|
16
|
+
}): Source;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google's own page through the desk's browser (`web GET /google`): each organic result as a
|
|
3
|
+
* hit, and the AI Overview as one hit of its own. The Overview is a claim, never a proof: its
|
|
4
|
+
* text and the questions people also ask ride in that hit's snippet; each page it cites becomes
|
|
5
|
+
* a hit, so the proof comes from reading those. A captcha or a spent cap is a miss.
|
|
6
|
+
*/
|
|
7
|
+
import { routeCall } from "./sites.js";
|
|
8
|
+
/** Google's printed date ("Aug 21, 2026") as an ISO day; nothing when it is not one. */
|
|
9
|
+
const isoDay = (d) => {
|
|
10
|
+
if (!d)
|
|
11
|
+
return undefined;
|
|
12
|
+
const t = Date.parse(d);
|
|
13
|
+
return Number.isNaN(t) ? undefined : new Date(t).toISOString().slice(0, 10);
|
|
14
|
+
};
|
|
15
|
+
/** The Overview's hit: Google's search URL for the terms, its fragment naming it. */
|
|
16
|
+
export const overviewUrl = (terms) => `https://www.google.com/search?q=${encodeURIComponent(terms)}#ai-overview`;
|
|
17
|
+
export function serpHits(body, terms) {
|
|
18
|
+
const serp = (body ?? {});
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const r of serp.results ?? []) {
|
|
21
|
+
if (!r.url)
|
|
22
|
+
continue;
|
|
23
|
+
const date = isoDay(r.date);
|
|
24
|
+
out.push({
|
|
25
|
+
url: r.url,
|
|
26
|
+
...(r.title ? { title: r.title } : {}),
|
|
27
|
+
...(r.snippet ? { snippet: r.snippet } : {}),
|
|
28
|
+
...(date ? { date } : {}),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const o = serp.overview;
|
|
32
|
+
if (o?.text?.trim()) {
|
|
33
|
+
const asked = serp.questions?.length
|
|
34
|
+
? `\n\nPeople also ask: ${serp.questions.join(" | ")}`
|
|
35
|
+
: "";
|
|
36
|
+
out.push({
|
|
37
|
+
url: overviewUrl(terms),
|
|
38
|
+
title: `Google AI Overview: ${terms}`,
|
|
39
|
+
channel: "Google AI Overview",
|
|
40
|
+
snippet: `${o.text.trim()}${asked}`,
|
|
41
|
+
});
|
|
42
|
+
for (const s of o.sources ?? [])
|
|
43
|
+
if (s.url)
|
|
44
|
+
out.push({
|
|
45
|
+
url: s.url,
|
|
46
|
+
...(s.title ? { title: s.title } : {}),
|
|
47
|
+
snippet: "Cited by Google's AI Overview",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
export function googleSource(o) {
|
|
53
|
+
return {
|
|
54
|
+
name: "google",
|
|
55
|
+
kind: "search",
|
|
56
|
+
cost: "browser",
|
|
57
|
+
async search(q) {
|
|
58
|
+
const terms = q.site ? `${q.terms} site:${q.site}` : q.terms;
|
|
59
|
+
const body = await routeCall(o.sites, "google", "web", "/google", { q: terms, n: o.n ?? 10 });
|
|
60
|
+
return serpHits(body, terms);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/sources/google.ts"],"names":[],"mappings":"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"}
|