@robzilla1738/agentswarm 0.5.0 → 0.7.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/README.md +29 -12
- package/dist/agent.js +6 -15
- package/dist/cli.js +31 -4
- package/dist/config.js +44 -1
- package/dist/crawltools.js +3 -22
- package/dist/executor.js +276 -60
- package/dist/hub.js +67 -3
- package/dist/journal.js +39 -5
- package/dist/memory.js +17 -11
- package/dist/pdftext.js +211 -0
- package/dist/prompts.js +23 -15
- package/dist/report.js +39 -1
- package/dist/run.js +8 -0
- package/dist/sandbox.js +11 -0
- package/dist/searchcore.js +55 -2
- package/dist/state.js +67 -17
- package/dist/tools.js +208 -19
- package/dist/util.js +117 -3
- package/dist/webtools.js +185 -32
- package/package.json +1 -1
- package/ui/out/404/index.html +1 -1
- package/ui/out/404.html +1 -1
- package/ui/out/_next/static/chunks/677-a62d486d6734bcf3.js +1 -0
- package/ui/out/_next/static/chunks/app/run/page-c29f95c51af08c60.js +1 -0
- package/ui/out/_next/static/chunks/app/settings/page-41a5d8ba43ecfd4a.js +1 -0
- package/ui/out/_next/static/css/{9f7bd82b8e4c762c.css → d95c2ba395730031.css} +1 -1
- package/ui/out/index.html +1 -1
- package/ui/out/index.txt +3 -3
- package/ui/out/run/index.html +1 -1
- package/ui/out/run/index.txt +3 -3
- package/ui/out/settings/index.html +1 -1
- package/ui/out/settings/index.txt +3 -3
- package/ui/out/_next/static/chunks/677-859e8d42add1806b.js +0 -1
- package/ui/out/_next/static/chunks/app/run/page-2420c9e4c963d9b3.js +0 -1
- package/ui/out/_next/static/chunks/app/settings/page-092a6bf42dfde57d.js +0 -1
- /package/ui/out/_next/static/{errjtBR_bKoee8ogLp8xk → JFkx5KtNi0DYyqm_THzbY}/_buildManifest.js +0 -0
- /package/ui/out/_next/static/{errjtBR_bKoee8ogLp8xk → JFkx5KtNi0DYyqm_THzbY}/_ssgManifest.js +0 -0
package/dist/util.js
CHANGED
|
@@ -33,8 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.ansi =
|
|
36
|
+
exports.ansi = void 0;
|
|
37
37
|
exports.rid = rid;
|
|
38
|
+
exports.sleep = sleep;
|
|
39
|
+
exports.mergeSignal = mergeSignal;
|
|
38
40
|
exports.truncateMiddle = truncateMiddle;
|
|
39
41
|
exports.clip = clip;
|
|
40
42
|
exports.oneLine = oneLine;
|
|
@@ -48,6 +50,7 @@ exports.ensureDir = ensureDir;
|
|
|
48
50
|
exports.readJson = readJson;
|
|
49
51
|
exports.writeJson = writeJson;
|
|
50
52
|
exports.pathInside = pathInside;
|
|
53
|
+
exports.validateArtifactFormat = validateArtifactFormat;
|
|
51
54
|
exports.decodeEntities = decodeEntities;
|
|
52
55
|
exports.htmlToText = htmlToText;
|
|
53
56
|
const fs = __importStar(require("fs"));
|
|
@@ -61,8 +64,35 @@ function rid(prefix) {
|
|
|
61
64
|
const c = ridCounter.toString(36).padStart(2, "0");
|
|
62
65
|
return `${prefix}_${t}${r}${c}`;
|
|
63
66
|
}
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
/** Resolves after ms; rejects early if the signal aborts first. */
|
|
68
|
+
function sleep(ms, signal) {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
if (!signal) {
|
|
71
|
+
setTimeout(resolve, ms);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (signal.aborted) {
|
|
75
|
+
reject(new Error("aborted"));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const t = setTimeout(() => {
|
|
79
|
+
signal.removeEventListener("abort", onAbort);
|
|
80
|
+
resolve();
|
|
81
|
+
}, ms);
|
|
82
|
+
const onAbort = () => {
|
|
83
|
+
clearTimeout(t);
|
|
84
|
+
reject(new Error("aborted"));
|
|
85
|
+
};
|
|
86
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** A timeout signal, combined with the caller's signal when one is given. */
|
|
90
|
+
function mergeSignal(timeoutMs, signal) {
|
|
91
|
+
const t = AbortSignal.timeout(timeoutMs);
|
|
92
|
+
if (!signal)
|
|
93
|
+
return t;
|
|
94
|
+
return typeof AbortSignal.any === "function" ? AbortSignal.any([t, signal]) : signal;
|
|
95
|
+
}
|
|
66
96
|
// ---------- strings ----------
|
|
67
97
|
function truncateMiddle(s, max, label = "bytes") {
|
|
68
98
|
if (s.length <= max)
|
|
@@ -147,6 +177,90 @@ function pathInside(parent, child) {
|
|
|
147
177
|
const rel = path.relative(path.resolve(parent), path.resolve(child));
|
|
148
178
|
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
149
179
|
}
|
|
180
|
+
// ---------- artifact validation ----------
|
|
181
|
+
/**
|
|
182
|
+
* Cheap structural checks for common deliverable formats — catches a worker
|
|
183
|
+
* shipping malformed JSON/CSV/stub HTML before an LLM verifier spends tokens
|
|
184
|
+
* on it. Returns a problem description, or null when the file looks sound
|
|
185
|
+
* (or is a format we don't check).
|
|
186
|
+
*/
|
|
187
|
+
function validateArtifactFormat(absPath) {
|
|
188
|
+
const ext = path.extname(absPath).toLowerCase();
|
|
189
|
+
if (![".json", ".csv", ".html", ".htm"].includes(ext))
|
|
190
|
+
return null;
|
|
191
|
+
let raw;
|
|
192
|
+
try {
|
|
193
|
+
raw = fs.readFileSync(absPath, "utf8");
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return null; // existence/size is the caller's check
|
|
197
|
+
}
|
|
198
|
+
if (ext === ".json") {
|
|
199
|
+
try {
|
|
200
|
+
JSON.parse(raw);
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
return `not valid JSON (${errMsg(e)})`;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (ext === ".csv") {
|
|
208
|
+
const counts = csvFieldCounts(raw, 50);
|
|
209
|
+
if (!counts.length)
|
|
210
|
+
return "CSV has no records";
|
|
211
|
+
const expect = counts[0];
|
|
212
|
+
const bad = counts.findIndex((c) => c !== expect);
|
|
213
|
+
if (bad > 0)
|
|
214
|
+
return `inconsistent CSV: record 1 has ${expect} field(s), record ${bad + 1} has ${counts[bad]}`;
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
// .html / .htm — catch empty shells and plain text passed off as HTML.
|
|
218
|
+
if (raw.length < 200 || !/<[a-z!][^>]*>/i.test(raw) || !/<\/[a-z][a-z0-9]*>/i.test(raw)) {
|
|
219
|
+
return "HTML looks like a stub (too short or no real markup)";
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
/** Field count per CSV record (quote-aware, handles newlines inside quotes). */
|
|
224
|
+
function csvFieldCounts(raw, maxRecords) {
|
|
225
|
+
const counts = [];
|
|
226
|
+
let fields = 1;
|
|
227
|
+
let chars = 0; // non-separator chars seen in the current record
|
|
228
|
+
let inQ = false;
|
|
229
|
+
for (let i = 0; i < raw.length && counts.length < maxRecords; i++) {
|
|
230
|
+
const ch = raw[i];
|
|
231
|
+
if (inQ) {
|
|
232
|
+
if (ch === '"') {
|
|
233
|
+
if (raw[i + 1] === '"')
|
|
234
|
+
i++;
|
|
235
|
+
else
|
|
236
|
+
inQ = false;
|
|
237
|
+
}
|
|
238
|
+
chars++;
|
|
239
|
+
}
|
|
240
|
+
else if (ch === '"') {
|
|
241
|
+
inQ = true;
|
|
242
|
+
chars++;
|
|
243
|
+
}
|
|
244
|
+
else if (ch === ",") {
|
|
245
|
+
fields++;
|
|
246
|
+
chars++;
|
|
247
|
+
}
|
|
248
|
+
else if (ch === "\n" || ch === "\r") {
|
|
249
|
+
if (ch === "\r" && raw[i + 1] === "\n")
|
|
250
|
+
i++;
|
|
251
|
+
if (chars > 0)
|
|
252
|
+
counts.push(fields); // skip blank lines
|
|
253
|
+
fields = 1;
|
|
254
|
+
chars = 0;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
chars++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (chars > 0 && counts.length < maxRecords)
|
|
261
|
+
counts.push(fields);
|
|
262
|
+
return counts;
|
|
263
|
+
}
|
|
150
264
|
// ---------- html ----------
|
|
151
265
|
const ENTITIES = {
|
|
152
266
|
amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " ",
|
package/dist/webtools.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.webSearch = webSearch;
|
|
4
|
+
exports.searchEngines = searchEngines;
|
|
5
|
+
exports._resetEngineCooldowns = _resetEngineCooldowns;
|
|
6
|
+
exports.tinyfishSearch = tinyfishSearch;
|
|
7
|
+
exports.ddgSearch = ddgSearch;
|
|
8
|
+
exports.bingSearch = bingSearch;
|
|
9
|
+
exports.arxivSearch = arxivSearch;
|
|
10
|
+
exports.crossrefSearch = crossrefSearch;
|
|
4
11
|
exports.parseBingHtml = parseBingHtml;
|
|
5
12
|
exports.fetchUrl = fetchUrl;
|
|
6
13
|
const crawltools_1 = require("./crawltools");
|
|
14
|
+
const pdftext_1 = require("./pdftext");
|
|
7
15
|
const searchcore_1 = require("./searchcore");
|
|
8
16
|
const util_1 = require("./util");
|
|
9
17
|
const UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36 agentswarm/0.1";
|
|
@@ -20,35 +28,58 @@ const DEEP_PASSAGES = 3;
|
|
|
20
28
|
* and re-ranks by content quality. Ranking/passage algorithms live in
|
|
21
29
|
* searchcore.ts.
|
|
22
30
|
*/
|
|
23
|
-
async function webSearch(cfg, query, count, signal, deep = false, warn) {
|
|
31
|
+
async function webSearch(cfg, query, count, signal, deep = false, warn, _retried = false) {
|
|
24
32
|
// Deep searches widen recall by issuing complementary phrasings; the fast
|
|
25
33
|
// path stays a single query so an agent's tool loop isn't slowed.
|
|
26
34
|
const queries = deep ? (0, searchcore_1.expandQueries)(query) : [query];
|
|
27
35
|
const perEngine = Math.min(count, 15);
|
|
36
|
+
const engines = searchEngines(cfg);
|
|
28
37
|
const engineCalls = [];
|
|
29
38
|
for (const q of queries) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
39
|
+
for (const e of engines) {
|
|
40
|
+
let call = e.search(q, perEngine, signal);
|
|
41
|
+
// When TinyFish is the sole engine by configuration, an outage must not
|
|
42
|
+
// blank web research for the whole mission — fall back to the free
|
|
43
|
+
// scraping engines for this call.
|
|
44
|
+
if (engines.length === 1 && e.name === "tinyfish") {
|
|
45
|
+
call = call.catch(async (err) => {
|
|
46
|
+
warn?.(`tinyfish failed (${(0, util_1.errMsg)(err)}); falling back to duckduckgo/bing`);
|
|
47
|
+
const fallback = await Promise.allSettled([ddgSearch(q, perEngine, signal), bingSearch(q, perEngine, signal)]);
|
|
48
|
+
const hits = fallback.flatMap((s) => (s.status === "fulfilled" ? s.value : []));
|
|
49
|
+
if (!hits.length && fallback.every((s) => s.status === "rejected"))
|
|
50
|
+
throw err;
|
|
51
|
+
return hits;
|
|
52
|
+
});
|
|
37
53
|
}
|
|
54
|
+
engineCalls.push(call);
|
|
38
55
|
}
|
|
39
56
|
}
|
|
57
|
+
// Scholarly questions also sweep the keyless academic APIs (deep mode only).
|
|
58
|
+
if (deep && (0, searchcore_1.looksAcademic)(query)) {
|
|
59
|
+
engineCalls.push(arxivSearch(query, perEngine, signal), crossrefSearch(query, perEngine, signal));
|
|
60
|
+
}
|
|
40
61
|
const settled = await Promise.allSettled(engineCalls);
|
|
41
62
|
const candidates = settled.flatMap((s) => (s.status === "fulfilled" ? s.value : []));
|
|
42
63
|
if (!candidates.length) {
|
|
43
64
|
const firstErr = settled.find((s) => s.status === "rejected");
|
|
44
|
-
if (firstErr)
|
|
65
|
+
if (firstErr && settled.every((s) => s.status === "rejected"))
|
|
45
66
|
throw firstErr.reason;
|
|
67
|
+
// Engines answered but nothing parsed/matched: one retry with a
|
|
68
|
+
// simplified phrasing before giving up.
|
|
69
|
+
if (!_retried) {
|
|
70
|
+
const alt = (0, searchcore_1.reformulate)(query);
|
|
71
|
+
if (alt) {
|
|
72
|
+
warn?.(`no results for "${query}" — retrying as "${alt}"`);
|
|
73
|
+
return webSearch(cfg, alt, count, signal, deep, warn, true);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// At least one engine answered with a genuine empty result set: that is
|
|
77
|
+
// "no results", not an error, even if another engine failed alongside it.
|
|
78
|
+
if (firstErr)
|
|
79
|
+
warn?.(`no results (and ${(0, util_1.errMsg)(firstErr.reason)})`);
|
|
46
80
|
return [];
|
|
47
81
|
}
|
|
48
82
|
const failures = settled.filter((s) => s.status === "rejected").length;
|
|
49
|
-
if (failures && failures === settled.length) {
|
|
50
|
-
throw (settled.find((s) => s.status === "rejected")).reason;
|
|
51
|
-
}
|
|
52
83
|
if (failures) {
|
|
53
84
|
warn?.(`${failures}/${settled.length} search engine calls failed; results come from the rest`);
|
|
54
85
|
}
|
|
@@ -100,7 +131,7 @@ async function fetchReadable(url, signal) {
|
|
|
100
131
|
try {
|
|
101
132
|
const res = await fetch(`https://raw.githubusercontent.com/${gh[1]}/${gh[2]}/${branch}/README.md`, {
|
|
102
133
|
headers: { "user-agent": UA },
|
|
103
|
-
signal: mergeSignal(20_000, signal),
|
|
134
|
+
signal: (0, util_1.mergeSignal)(20_000, signal),
|
|
104
135
|
});
|
|
105
136
|
if (res.ok)
|
|
106
137
|
return clip(await res.text());
|
|
@@ -111,16 +142,23 @@ async function fetchReadable(url, signal) {
|
|
|
111
142
|
}
|
|
112
143
|
}
|
|
113
144
|
const res = await fetch(url, {
|
|
114
|
-
headers: { "user-agent": UA, accept: "text/html,text/*;q=0.9,*/*;q=0.5" },
|
|
115
|
-
signal: mergeSignal(20_000, signal),
|
|
145
|
+
headers: { "user-agent": UA, accept: "text/html,application/pdf,text/*;q=0.9,*/*;q=0.5" },
|
|
146
|
+
signal: (0, util_1.mergeSignal)(20_000, signal),
|
|
116
147
|
redirect: "follow",
|
|
117
148
|
});
|
|
118
149
|
if (!res.ok)
|
|
119
150
|
throw new Error(`HTTP ${res.status}`);
|
|
120
151
|
const ctype = res.headers.get("content-type") || "";
|
|
152
|
+
if (/application\/pdf/i.test(ctype)) {
|
|
153
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
154
|
+
const pdf = buf.length <= 20_000_000 ? (0, pdftext_1.extractPdfText)(buf) : null;
|
|
155
|
+
if (!pdf)
|
|
156
|
+
throw new Error("pdf with no extractable text");
|
|
157
|
+
return clip(pdf.text);
|
|
158
|
+
}
|
|
121
159
|
if (!/text\/|html|xml|json/i.test(ctype))
|
|
122
160
|
throw new Error(`not textual: ${ctype}`);
|
|
123
|
-
const body = await res.
|
|
161
|
+
const body = decodeBody(Buffer.from(await res.arrayBuffer()), ctype);
|
|
124
162
|
const text = /html/i.test(ctype) ? (0, util_1.htmlToText)(body) : body;
|
|
125
163
|
return clip(text);
|
|
126
164
|
}
|
|
@@ -128,18 +166,59 @@ function clip(text) {
|
|
|
128
166
|
const words = text.replace(/\s+/g, " ").trim().split(" ");
|
|
129
167
|
return words.slice(0, 3000).join(" ");
|
|
130
168
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
169
|
+
/**
|
|
170
|
+
* The engine set a web_search call fans out to under the given config —
|
|
171
|
+
* the single source of truth shared by webSearch and the settings
|
|
172
|
+
* diagnostics endpoint, so "Test search" probes exactly what runs use.
|
|
173
|
+
*/
|
|
174
|
+
function searchEngines(cfg) {
|
|
175
|
+
if (cfg.searchBackend === "tinyfish" && cfg.tinyfishApiKey) {
|
|
176
|
+
return [{ name: "tinyfish", search: (q, n, s) => tinyfishSearch(cfg, q, n, s) }];
|
|
177
|
+
}
|
|
178
|
+
const engines = [
|
|
179
|
+
{ name: "duckduckgo", search: ddgSearch },
|
|
180
|
+
{ name: "bing", search: bingSearch },
|
|
181
|
+
];
|
|
182
|
+
if (cfg.searchBackend === "auto" && cfg.tinyfishApiKey) {
|
|
183
|
+
engines.push({ name: "tinyfish", search: (q, n, s) => tinyfishSearch(cfg, q, n, s) });
|
|
184
|
+
}
|
|
185
|
+
return engines;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Per-engine rate-limit cooldowns: an engine that answers 429/403/503 sits
|
|
189
|
+
* out (60s, or the server's retry-after up to 120s) instead of getting
|
|
190
|
+
* hammered into a long block mid-research. A tiny retry-after (≤5s) is
|
|
191
|
+
* honored once in-call.
|
|
192
|
+
*/
|
|
193
|
+
const engineCooldown = new Map();
|
|
194
|
+
/** Test hook. */
|
|
195
|
+
function _resetEngineCooldowns() {
|
|
196
|
+
engineCooldown.clear();
|
|
197
|
+
}
|
|
198
|
+
async function engineFetch(engine, url, init, signal) {
|
|
199
|
+
const until = engineCooldown.get(engine) ?? 0;
|
|
200
|
+
if (until > Date.now()) {
|
|
201
|
+
throw new Error(`${engine} is cooling down after a rate limit (${Math.ceil((until - Date.now()) / 1000)}s left)`);
|
|
202
|
+
}
|
|
203
|
+
for (let attempt = 0;; attempt++) {
|
|
204
|
+
const res = await fetch(url, { ...init, signal: (0, util_1.mergeSignal)(20_000, signal) });
|
|
205
|
+
if (![429, 403, 503].includes(res.status))
|
|
206
|
+
return res;
|
|
207
|
+
const retryAfter = Number(res.headers.get("retry-after"));
|
|
208
|
+
if (attempt === 0 && Number.isFinite(retryAfter) && retryAfter > 0 && retryAfter <= 5) {
|
|
209
|
+
await new Promise((r) => setTimeout(r, retryAfter * 1000));
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const ms = Number.isFinite(retryAfter) && retryAfter > 0 ? Math.min(retryAfter, 120) * 1000 : 60_000;
|
|
213
|
+
engineCooldown.set(engine, Date.now() + ms);
|
|
214
|
+
throw new Error(`${engine} rate-limited (HTTP ${res.status}); cooling down ${Math.round(ms / 1000)}s`);
|
|
215
|
+
}
|
|
136
216
|
}
|
|
137
|
-
// ---------------------------------------------------------------- engines
|
|
138
217
|
async function tinyfishSearch(cfg, query, count, signal) {
|
|
139
218
|
const url = `https://api.search.tinyfish.ai?query=${encodeURIComponent(query)}`;
|
|
140
219
|
const res = await fetch(url, {
|
|
141
220
|
headers: { "X-API-Key": cfg.tinyfishApiKey },
|
|
142
|
-
signal: mergeSignal(20_000, signal),
|
|
221
|
+
signal: (0, util_1.mergeSignal)(20_000, signal),
|
|
143
222
|
});
|
|
144
223
|
if (!res.ok)
|
|
145
224
|
throw new Error(`tinyfish search ${res.status}`);
|
|
@@ -173,10 +252,9 @@ async function ddgSearch(query, count, signal) {
|
|
|
173
252
|
let reachedAny = false;
|
|
174
253
|
for (const ep of DDG_ENDPOINTS) {
|
|
175
254
|
try {
|
|
176
|
-
const res = await
|
|
255
|
+
const res = await engineFetch("duckduckgo", ep.url + encodeURIComponent(query), {
|
|
177
256
|
headers: { "user-agent": UA },
|
|
178
|
-
|
|
179
|
-
});
|
|
257
|
+
}, signal);
|
|
180
258
|
if (!res.ok)
|
|
181
259
|
throw new Error(`search failed: HTTP ${res.status}`);
|
|
182
260
|
reachedAny = true;
|
|
@@ -221,14 +299,56 @@ function parseDdgHtml(html, count, linkRe) {
|
|
|
221
299
|
}
|
|
222
300
|
/** Bing's HTML results page: each hit is an <li class="b_algo"> with an <h2><a> link. */
|
|
223
301
|
async function bingSearch(query, count, signal) {
|
|
224
|
-
const res = await
|
|
302
|
+
const res = await engineFetch("bing", `https://www.bing.com/search?q=${encodeURIComponent(query)}`, {
|
|
225
303
|
headers: { "user-agent": UA, "accept-language": "en-US,en;q=0.9" },
|
|
226
|
-
|
|
227
|
-
});
|
|
304
|
+
}, signal);
|
|
228
305
|
if (!res.ok)
|
|
229
306
|
throw new Error(`bing search ${res.status}`);
|
|
230
307
|
return parseBingHtml(await res.text(), count);
|
|
231
308
|
}
|
|
309
|
+
// ---------------------------------------------------------------- academic engines (keyless)
|
|
310
|
+
/** arXiv's Atom API — preprints with abstracts, no key needed. */
|
|
311
|
+
async function arxivSearch(query, count, signal) {
|
|
312
|
+
const url = `https://export.arxiv.org/api/query?search_query=all:${encodeURIComponent(query)}&max_results=${Math.min(count, 15)}`;
|
|
313
|
+
const res = await engineFetch("arxiv", url, { headers: { "user-agent": UA } }, signal);
|
|
314
|
+
if (!res.ok)
|
|
315
|
+
throw new Error(`arxiv search ${res.status}`);
|
|
316
|
+
const xml = await res.text();
|
|
317
|
+
const out = [];
|
|
318
|
+
for (const entry of xml.split(/<entry>/).slice(1)) {
|
|
319
|
+
if (out.length >= count)
|
|
320
|
+
break;
|
|
321
|
+
const title = strip((/<title>([\s\S]*?)<\/title>/.exec(entry) || [])[1] || "");
|
|
322
|
+
const id = ((/<id>([\s\S]*?)<\/id>/.exec(entry) || [])[1] || "").trim();
|
|
323
|
+
const summary = strip((/<summary>([\s\S]*?)<\/summary>/.exec(entry) || [])[1] || "");
|
|
324
|
+
const published = (/<published>(\d{4}-\d{2}-\d{2})/.exec(entry) || [])[1];
|
|
325
|
+
if (!id || !title || !/^https?:\/\//.test(id))
|
|
326
|
+
continue;
|
|
327
|
+
out.push({ title, url: id, snippet: summary.slice(0, 300), rank: out.length + 1, engine: "arxiv", date: published });
|
|
328
|
+
}
|
|
329
|
+
return out;
|
|
330
|
+
}
|
|
331
|
+
/** Crossref's works API — journal/conference metadata with DOIs, no key needed. */
|
|
332
|
+
async function crossrefSearch(query, count, signal) {
|
|
333
|
+
const url = `https://api.crossref.org/works?query=${encodeURIComponent(query)}&rows=${Math.min(count, 15)}&select=title,DOI,abstract,issued,container-title`;
|
|
334
|
+
const res = await engineFetch("crossref", url, { headers: { "user-agent": UA } }, signal);
|
|
335
|
+
if (!res.ok)
|
|
336
|
+
throw new Error(`crossref search ${res.status}`);
|
|
337
|
+
const data = await res.json();
|
|
338
|
+
const out = [];
|
|
339
|
+
for (const it of data?.message?.items ?? []) {
|
|
340
|
+
if (out.length >= count)
|
|
341
|
+
break;
|
|
342
|
+
const title = strip(String(Array.isArray(it.title) ? it.title[0] ?? "" : it.title ?? ""));
|
|
343
|
+
if (!title || !it.DOI)
|
|
344
|
+
continue;
|
|
345
|
+
const date = Array.isArray(it.issued?.["date-parts"]?.[0]) ? it.issued["date-parts"][0].join("-") : undefined;
|
|
346
|
+
const venue = Array.isArray(it["container-title"]) ? it["container-title"][0] : "";
|
|
347
|
+
const snippet = (strip(String(it.abstract ?? "")) || venue || "").slice(0, 300);
|
|
348
|
+
out.push({ title, url: `https://doi.org/${it.DOI}`, snippet, rank: out.length + 1, engine: "crossref", date });
|
|
349
|
+
}
|
|
350
|
+
return out;
|
|
351
|
+
}
|
|
232
352
|
function parseBingHtml(html, count) {
|
|
233
353
|
const hits = [];
|
|
234
354
|
const blocks = html.split(/<li class="b_algo[^"]*"/i).slice(1);
|
|
@@ -302,18 +422,51 @@ async function fetchUrl(cfg, url, raw, maxChars, signal) {
|
|
|
302
422
|
}
|
|
303
423
|
}
|
|
304
424
|
const res = await fetch(url, {
|
|
305
|
-
headers: { "user-agent": UA, accept: "text/html,application/json,text/*;q=0.9,*/*;q=0.5" },
|
|
425
|
+
headers: { "user-agent": UA, accept: "text/html,application/json,application/pdf,text/*;q=0.9,*/*;q=0.5" },
|
|
306
426
|
signal: signal ?? AbortSignal.timeout(25000),
|
|
307
427
|
redirect: "follow",
|
|
308
428
|
});
|
|
309
429
|
const ctype = res.headers.get("content-type") || "";
|
|
310
|
-
const body = await res.text();
|
|
311
430
|
if (!res.ok) {
|
|
312
|
-
|
|
431
|
+
// An error page is not content: returning it as a successful result lets
|
|
432
|
+
// "HTTP 403 ... subscribe to continue" become a "fact" in someone's report.
|
|
433
|
+
const body = await res.text().catch(() => "");
|
|
434
|
+
throw new Error(`HTTP ${res.status} ${res.statusText} — page is not usable as a source (paywall/login/blocked?). ` +
|
|
435
|
+
`Try web_search for an alternative source.${body ? ` Server said: ${(0, util_1.oneLine)((0, util_1.htmlToText)(body), 200)}` : ""}`);
|
|
313
436
|
}
|
|
437
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
438
|
+
if (/application\/pdf/i.test(ctype) || buf.subarray(0, 5).toString("latin1") === "%PDF-") {
|
|
439
|
+
if (buf.length > 20_000_000)
|
|
440
|
+
throw new Error(`PDF is ${Math.round(buf.length / 1e6)}MB — too large to extract`);
|
|
441
|
+
const pdf = (0, pdftext_1.extractPdfText)(buf);
|
|
442
|
+
if (!pdf) {
|
|
443
|
+
throw new Error("PDF contains no extractable text (likely scanned or encrypted) — find an HTML version of this source.");
|
|
444
|
+
}
|
|
445
|
+
return (0, util_1.truncateMiddle)(`[PDF, ${pdf.pages} page${pdf.pages > 1 ? "s" : ""}]\n${pdf.text}`, maxChars, "chars");
|
|
446
|
+
}
|
|
447
|
+
const body = decodeBody(buf, ctype);
|
|
314
448
|
const text = !raw && /html/i.test(ctype) ? (0, util_1.htmlToText)(body) : body;
|
|
449
|
+
if (!raw && /html/i.test(ctype)) {
|
|
450
|
+
const trimmed = text.trim();
|
|
451
|
+
if (trimmed.length < 400 && /subscrib|sign.?in|log.?in|enable javascript|access denied|are you a (human|robot)|captcha/i.test(trimmed)) {
|
|
452
|
+
return `WARNING: this page returned only a paywall/anti-bot shell — the text below is probably not the real content. Try web_search for an alternative source.\n\n${trimmed}`;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
315
455
|
return (0, util_1.truncateMiddle)(text, maxChars, "chars");
|
|
316
456
|
}
|
|
457
|
+
/** Decode a response body honoring its content-type charset (UTF-8 fallback). */
|
|
458
|
+
function decodeBody(buf, ctype) {
|
|
459
|
+
const charset = /charset=([\w-]+)/i.exec(ctype)?.[1]?.toLowerCase();
|
|
460
|
+
if (charset && charset !== "utf-8" && charset !== "utf8") {
|
|
461
|
+
try {
|
|
462
|
+
return new TextDecoder(charset).decode(buf);
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
/* unknown label — fall through to utf-8 */
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return buf.toString("utf8");
|
|
469
|
+
}
|
|
317
470
|
async function tinyfishFetch(cfg, url, signal) {
|
|
318
471
|
const res = await fetch("https://api.fetch.tinyfish.ai", {
|
|
319
472
|
method: "POST",
|
package/package.json
CHANGED
package/ui/out/404/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--JFkx5KtNi0DYyqm_THzbY--><html lang="en" class="__variable_73ee6c __variable_3c557b"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4c9affa5bc8f420e-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/d95c2ba395730031.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-38639c05c96dbeca.js"/><script src="/_next/static/chunks/4bd1b696-c023c6e3521b1417.js" async=""></script><script src="/_next/static/chunks/255-2aa030c9ba2867e3.js" async=""></script><script src="/_next/static/chunks/main-app-889ed884f8bc78e3.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><meta name="theme-color" content="#050505"/><title>agentswarm</title><meta name="description" content="A local agent swarm for long-horizon, autonomous work."/><link rel="icon" href="/icon.png?bdc9175d46e1d0aa" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><script>try{var t=localStorage.getItem("theme");if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}</script><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-38639c05c96dbeca.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4c9affa5bc8f420e-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/d95c2ba395730031.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"JFkx5KtNi0DYyqm_THzbY\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/d95c2ba395730031.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_73ee6c __variable_3c557b\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem(\\\"theme\\\");if(t===\\\"light\\\"||t===\\\"dark\\\")document.documentElement.dataset.theme=t}catch(e){}\"}}],[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#050505\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"agentswarm\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A local agent swarm for long-horizon, autonomous work.\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/icon.png?bdc9175d46e1d0aa\",\"type\":\"image/png\",\"sizes\":\"256x256\"}],[\"$\",\"$Le\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>
|
package/ui/out/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--JFkx5KtNi0DYyqm_THzbY--><html lang="en" class="__variable_73ee6c __variable_3c557b"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4c9affa5bc8f420e-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/d95c2ba395730031.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-38639c05c96dbeca.js"/><script src="/_next/static/chunks/4bd1b696-c023c6e3521b1417.js" async=""></script><script src="/_next/static/chunks/255-2aa030c9ba2867e3.js" async=""></script><script src="/_next/static/chunks/main-app-889ed884f8bc78e3.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><meta name="theme-color" content="#050505"/><title>agentswarm</title><meta name="description" content="A local agent swarm for long-horizon, autonomous work."/><link rel="icon" href="/icon.png?bdc9175d46e1d0aa" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><script>try{var t=localStorage.getItem("theme");if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}</script><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-38639c05c96dbeca.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4c9affa5bc8f420e-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/d95c2ba395730031.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"JFkx5KtNi0DYyqm_THzbY\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/d95c2ba395730031.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_73ee6c __variable_3c557b\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem(\\\"theme\\\");if(t===\\\"light\\\"||t===\\\"dark\\\")document.documentElement.dataset.theme=t}catch(e){}\"}}],[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#050505\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"agentswarm\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A local agent swarm for long-horizon, autonomous work.\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/icon.png?bdc9175d46e1d0aa\",\"type\":\"image/png\",\"sizes\":\"256x256\"}],[\"$\",\"$Le\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>
|