@steel-dev/atlas 0.1.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 +21 -0
- package/README.md +219 -0
- package/dist/agent.d.ts +34 -0
- package/dist/agent.js +133 -0
- package/dist/async.d.ts +19 -0
- package/dist/async.js +172 -0
- package/dist/atlas.d.ts +19 -0
- package/dist/atlas.js +69 -0
- package/dist/budget.d.ts +64 -0
- package/dist/budget.js +336 -0
- package/dist/checklist.d.ts +115 -0
- package/dist/checklist.js +297 -0
- package/dist/cli.js +38700 -0
- package/dist/config.d.ts +80 -0
- package/dist/config.js +109 -0
- package/dist/context.d.ts +26 -0
- package/dist/context.js +250 -0
- package/dist/custom-tools.d.ts +26 -0
- package/dist/custom-tools.js +33 -0
- package/dist/defaults.d.ts +10 -0
- package/dist/defaults.js +37 -0
- package/dist/economy.d.ts +12 -0
- package/dist/economy.js +6 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +8 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +11 -0
- package/dist/event-hub.d.ts +11 -0
- package/dist/event-hub.js +83 -0
- package/dist/events.d.ts +105 -0
- package/dist/events.js +1 -0
- package/dist/html-extract.d.ts +21 -0
- package/dist/html-extract.js +459 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +26 -0
- package/dist/memory.d.ts +2 -0
- package/dist/memory.js +38 -0
- package/dist/model.d.ts +49 -0
- package/dist/model.js +630 -0
- package/dist/orchestrate.d.ts +5 -0
- package/dist/orchestrate.js +277 -0
- package/dist/pdf-extract.d.ts +5 -0
- package/dist/pdf-extract.js +20 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +6 -0
- package/dist/providers/domain/arxiv.d.ts +6 -0
- package/dist/providers/domain/arxiv.js +83 -0
- package/dist/providers/domain/clinicaltrials.d.ts +6 -0
- package/dist/providers/domain/clinicaltrials.js +104 -0
- package/dist/providers/domain/edgar.d.ts +10 -0
- package/dist/providers/domain/edgar.js +92 -0
- package/dist/providers/domain/index.d.ts +14 -0
- package/dist/providers/domain/index.js +7 -0
- package/dist/providers/domain/openalex.d.ts +7 -0
- package/dist/providers/domain/openalex.js +128 -0
- package/dist/providers/domain/pubmed.d.ts +8 -0
- package/dist/providers/domain/pubmed.js +123 -0
- package/dist/providers/domain/semantic-scholar.d.ts +6 -0
- package/dist/providers/domain/semantic-scholar.js +112 -0
- package/dist/providers/domain/shared.d.ts +12 -0
- package/dist/providers/domain/shared.js +39 -0
- package/dist/providers/domain/wikipedia.d.ts +6 -0
- package/dist/providers/domain/wikipedia.js +71 -0
- package/dist/providers/exa-agent.d.ts +9 -0
- package/dist/providers/exa-agent.js +67 -0
- package/dist/providers/fetch.d.ts +66 -0
- package/dist/providers/fetch.js +675 -0
- package/dist/providers/parallel-agent.d.ts +11 -0
- package/dist/providers/parallel-agent.js +100 -0
- package/dist/providers/perplexity-agent.d.ts +17 -0
- package/dist/providers/perplexity-agent.js +86 -0
- package/dist/providers/search.d.ts +65 -0
- package/dist/providers/search.js +433 -0
- package/dist/providers/store.d.ts +48 -0
- package/dist/providers/store.js +217 -0
- package/dist/researcher.d.ts +20 -0
- package/dist/researcher.js +3 -0
- package/dist/robots.d.ts +16 -0
- package/dist/robots.js +146 -0
- package/dist/roles.d.ts +6 -0
- package/dist/roles.js +4 -0
- package/dist/run.d.ts +65 -0
- package/dist/run.js +371 -0
- package/dist/safe-dispatcher.d.ts +16 -0
- package/dist/safe-dispatcher.js +32 -0
- package/dist/safety.d.ts +23 -0
- package/dist/safety.js +206 -0
- package/dist/sandbox.d.ts +22 -0
- package/dist/sandbox.js +228 -0
- package/dist/search-normalize.d.ts +2 -0
- package/dist/search-normalize.js +13 -0
- package/dist/source-documents.d.ts +77 -0
- package/dist/source-documents.js +421 -0
- package/dist/sources.d.ts +57 -0
- package/dist/sources.js +1 -0
- package/dist/spine.d.ts +19 -0
- package/dist/spine.js +722 -0
- package/dist/state.d.ts +90 -0
- package/dist/state.js +27 -0
- package/dist/structured.d.ts +7 -0
- package/dist/structured.js +18 -0
- package/dist/tools.d.ts +33 -0
- package/dist/tools.js +1187 -0
- package/dist/trace-digest.d.ts +11 -0
- package/dist/trace-digest.js +309 -0
- package/dist/trace.d.ts +225 -0
- package/dist/trace.js +278 -0
- package/dist/trail.d.ts +15 -0
- package/dist/trail.js +74 -0
- package/dist/url.d.ts +1 -0
- package/dist/url.js +25 -0
- package/package.json +107 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { sleep, withTimeout } from "../async.js";
|
|
2
|
+
import { readEnv } from "../env.js";
|
|
3
|
+
const PARALLEL_PRICE_PER_RUN = {
|
|
4
|
+
lite: 0.005,
|
|
5
|
+
base: 0.01,
|
|
6
|
+
core: 0.025,
|
|
7
|
+
core2x: 0.05,
|
|
8
|
+
pro: 0.1,
|
|
9
|
+
ultra: 0.3,
|
|
10
|
+
ultra2x: 0.6,
|
|
11
|
+
ultra4x: 1.2,
|
|
12
|
+
ultra8x: 2.4,
|
|
13
|
+
};
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 15 * 60_000;
|
|
15
|
+
const DEFAULT_POLL_INTERVAL_MS = 3_000;
|
|
16
|
+
const TERMINAL_STATUSES = new Set([
|
|
17
|
+
"completed",
|
|
18
|
+
"failed",
|
|
19
|
+
"cancelled",
|
|
20
|
+
"cancelling",
|
|
21
|
+
"error",
|
|
22
|
+
]);
|
|
23
|
+
const DEFAULT_DESCRIPTION = "Parallel.ai task research: autonomous web research returning a citation-backed result. Strong on enrichment, structured/entity extraction, and broad gathering.";
|
|
24
|
+
export function parallelAgent(opts = {}) {
|
|
25
|
+
const apiKey = opts.apiKey ?? readEnv("ATLAS_PARALLEL_API_KEY", "PARALLEL_API_KEY");
|
|
26
|
+
const base = (opts.baseUrl ?? "https://api.parallel.ai").replace(/\/+$/, "");
|
|
27
|
+
return {
|
|
28
|
+
description: opts.description ?? DEFAULT_DESCRIPTION,
|
|
29
|
+
async research(query, ctx) {
|
|
30
|
+
if (!apiKey) {
|
|
31
|
+
throw new Error("parallel.agent: no API key (set ATLAS_PARALLEL_API_KEY / PARALLEL_API_KEY or pass { apiKey })");
|
|
32
|
+
}
|
|
33
|
+
const headers = {
|
|
34
|
+
"content-type": "application/json",
|
|
35
|
+
"x-api-key": apiKey,
|
|
36
|
+
};
|
|
37
|
+
const processor = opts.processor ?? "core";
|
|
38
|
+
const data = await withTimeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS, ctx.signal, "parallel.agent", async (signal) => {
|
|
39
|
+
const created = await fetch(`${base}/v1/tasks/runs`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
signal,
|
|
42
|
+
headers,
|
|
43
|
+
body: JSON.stringify({
|
|
44
|
+
input: query,
|
|
45
|
+
processor,
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
if (!created.ok) {
|
|
49
|
+
throw new Error(`parallel.agent: create HTTP ${created.status}`);
|
|
50
|
+
}
|
|
51
|
+
const run = (await created.json());
|
|
52
|
+
if (!run.run_id) {
|
|
53
|
+
throw new Error("parallel.agent: no run_id in create response");
|
|
54
|
+
}
|
|
55
|
+
let status = run.status ?? "queued";
|
|
56
|
+
while (!TERMINAL_STATUSES.has(status)) {
|
|
57
|
+
await sleep(opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS, signal);
|
|
58
|
+
const polled = await fetch(`${base}/v1/tasks/runs/${run.run_id}`, {
|
|
59
|
+
signal,
|
|
60
|
+
headers,
|
|
61
|
+
});
|
|
62
|
+
if (!polled.ok) {
|
|
63
|
+
throw new Error(`parallel.agent: poll HTTP ${polled.status}`);
|
|
64
|
+
}
|
|
65
|
+
status =
|
|
66
|
+
(await polled.json()).status ?? status;
|
|
67
|
+
}
|
|
68
|
+
if (status !== "completed") {
|
|
69
|
+
throw new Error(`parallel.agent: task run ${status}`);
|
|
70
|
+
}
|
|
71
|
+
const resultResp = await fetch(`${base}/v1/tasks/runs/${run.run_id}/result`, { signal, headers });
|
|
72
|
+
if (!resultResp.ok) {
|
|
73
|
+
throw new Error(`parallel.agent: result HTTP ${resultResp.status}`);
|
|
74
|
+
}
|
|
75
|
+
return (await resultResp.json());
|
|
76
|
+
});
|
|
77
|
+
const content = data.output?.content;
|
|
78
|
+
const report = (typeof content === "string" ? content : JSON.stringify(content ?? "")).trim();
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
const sources = [];
|
|
81
|
+
for (const field of data.output?.basis ?? []) {
|
|
82
|
+
for (const citation of field.citations ?? []) {
|
|
83
|
+
if (citation.url && !seen.has(citation.url)) {
|
|
84
|
+
seen.add(citation.url);
|
|
85
|
+
sources.push({
|
|
86
|
+
url: citation.url,
|
|
87
|
+
...(citation.title ? { title: citation.title } : {}),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const cost = opts.costPerRunUSD ?? PARALLEL_PRICE_PER_RUN[processor];
|
|
93
|
+
ctx.log(`parallel.agent: ${sources.length} sources` +
|
|
94
|
+
(cost != null
|
|
95
|
+
? `, $${cost.toFixed(4)}`
|
|
96
|
+
: " (cost unknown — set costPerRunUSD)"));
|
|
97
|
+
return { report, sources, ...(cost != null ? { cost } : {}) };
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Researcher } from "../researcher.js";
|
|
2
|
+
export interface PerplexityPricing {
|
|
3
|
+
inputPerMTok: number;
|
|
4
|
+
outputPerMTok: number;
|
|
5
|
+
citationPerMTok: number;
|
|
6
|
+
reasoningPerMTok: number;
|
|
7
|
+
perThousandSearches: number;
|
|
8
|
+
}
|
|
9
|
+
export interface PerplexityAgentOptions {
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
model?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
pricing?: Partial<PerplexityPricing>;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function perplexityAgent(opts?: PerplexityAgentOptions): Researcher;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { withTimeout } from "../async.js";
|
|
2
|
+
import { readEnv } from "../env.js";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 10 * 60_000;
|
|
4
|
+
const DEFAULT_DESCRIPTION = "Perplexity Sonar deep-research: fast web-grounded research with inline citations. Strong on current events, quick fact-checks, and broad Q&A.";
|
|
5
|
+
const PERPLEXITY_RATES = {
|
|
6
|
+
"sonar-deep-research": {
|
|
7
|
+
inputPerMTok: 2,
|
|
8
|
+
outputPerMTok: 8,
|
|
9
|
+
citationPerMTok: 2,
|
|
10
|
+
reasoningPerMTok: 3,
|
|
11
|
+
perThousandSearches: 5,
|
|
12
|
+
},
|
|
13
|
+
sonar: {
|
|
14
|
+
inputPerMTok: 1,
|
|
15
|
+
outputPerMTok: 1,
|
|
16
|
+
citationPerMTok: 0,
|
|
17
|
+
reasoningPerMTok: 0,
|
|
18
|
+
perThousandSearches: 0,
|
|
19
|
+
},
|
|
20
|
+
"sonar-pro": {
|
|
21
|
+
inputPerMTok: 3,
|
|
22
|
+
outputPerMTok: 15,
|
|
23
|
+
citationPerMTok: 0,
|
|
24
|
+
reasoningPerMTok: 0,
|
|
25
|
+
perThousandSearches: 0,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const FALLBACK_RATES = PERPLEXITY_RATES["sonar-deep-research"];
|
|
29
|
+
function perplexityCost(usage, model, override) {
|
|
30
|
+
if (!usage)
|
|
31
|
+
return undefined;
|
|
32
|
+
const r = { ...(PERPLEXITY_RATES[model] ?? FALLBACK_RATES), ...override };
|
|
33
|
+
return (((usage.prompt_tokens ?? 0) * r.inputPerMTok +
|
|
34
|
+
(usage.completion_tokens ?? 0) * r.outputPerMTok +
|
|
35
|
+
(usage.citation_tokens ?? 0) * r.citationPerMTok +
|
|
36
|
+
(usage.reasoning_tokens ?? 0) * r.reasoningPerMTok) /
|
|
37
|
+
1_000_000 +
|
|
38
|
+
((usage.num_search_queries ?? 0) / 1000) * r.perThousandSearches);
|
|
39
|
+
}
|
|
40
|
+
export function perplexityAgent(opts = {}) {
|
|
41
|
+
const apiKey = opts.apiKey ?? readEnv("ATLAS_PERPLEXITY_API_KEY", "PERPLEXITY_API_KEY");
|
|
42
|
+
const endpoint = `${(opts.baseUrl ?? "https://api.perplexity.ai").replace(/\/+$/, "")}/chat/completions`;
|
|
43
|
+
return {
|
|
44
|
+
description: opts.description ?? DEFAULT_DESCRIPTION,
|
|
45
|
+
async research(query, ctx) {
|
|
46
|
+
if (!apiKey) {
|
|
47
|
+
throw new Error("perplexity.agent: no API key (set ATLAS_PERPLEXITY_API_KEY / PERPLEXITY_API_KEY or pass { apiKey })");
|
|
48
|
+
}
|
|
49
|
+
const model = opts.model ?? "sonar-deep-research";
|
|
50
|
+
const data = await withTimeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS, ctx.signal, "perplexity.agent", async (signal) => {
|
|
51
|
+
const resp = await fetch(endpoint, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
signal,
|
|
54
|
+
headers: {
|
|
55
|
+
"content-type": "application/json",
|
|
56
|
+
authorization: `Bearer ${apiKey}`,
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
model,
|
|
60
|
+
messages: [{ role: "user", content: query }],
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
if (!resp.ok) {
|
|
64
|
+
throw new Error(`perplexity.agent: HTTP ${resp.status}`);
|
|
65
|
+
}
|
|
66
|
+
return (await resp.json());
|
|
67
|
+
});
|
|
68
|
+
if (!data.choices || data.choices.length === 0) {
|
|
69
|
+
throw new Error("perplexity.agent: response had no choices (HTTP 200 with an error body?)");
|
|
70
|
+
}
|
|
71
|
+
const report = (data.choices[0]?.message?.content ?? "").trim();
|
|
72
|
+
const fromResults = (data.search_results ?? [])
|
|
73
|
+
.filter((r) => Boolean(r.url))
|
|
74
|
+
.map((r) => ({ url: r.url, ...(r.title ? { title: r.title } : {}) }));
|
|
75
|
+
const sources = fromResults.length > 0
|
|
76
|
+
? fromResults
|
|
77
|
+
: (data.citations ?? []).map((url) => ({ url }));
|
|
78
|
+
const cost = perplexityCost(data.usage, model, opts.pricing);
|
|
79
|
+
ctx.log(`perplexity.agent: ${sources.length} sources` +
|
|
80
|
+
(cost != null
|
|
81
|
+
? `, $${cost.toFixed(4)}`
|
|
82
|
+
: " (cost unknown — no usage in response)"));
|
|
83
|
+
return { report, sources, ...(cost != null ? { cost } : {}) };
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type LanguageModel } from "ai";
|
|
2
|
+
export interface SearchResult {
|
|
3
|
+
position: number;
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
snippet: string;
|
|
7
|
+
domain: string;
|
|
8
|
+
meta?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface SearchQuery {
|
|
11
|
+
query: string;
|
|
12
|
+
maxResults?: number;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
export interface SearchProvider {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
search(q: SearchQuery): Promise<SearchResult[]>;
|
|
18
|
+
}
|
|
19
|
+
export declare function safeDomain(url: string): string;
|
|
20
|
+
export interface TavilyOptions {
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function tavily(opts?: TavilyOptions): SearchProvider;
|
|
25
|
+
export interface ExaOptions {
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
type?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function exa(opts?: ExaOptions): SearchProvider;
|
|
31
|
+
export interface BraveOptions {
|
|
32
|
+
apiKey?: string;
|
|
33
|
+
baseUrl?: string;
|
|
34
|
+
country?: string;
|
|
35
|
+
searchLang?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function brave(opts?: BraveOptions): SearchProvider;
|
|
38
|
+
export interface NativeModelSearchOptions {
|
|
39
|
+
model: Exclude<LanguageModel, string>;
|
|
40
|
+
}
|
|
41
|
+
export declare function nativeModelSearch(opts: NativeModelSearchOptions): SearchProvider;
|
|
42
|
+
export interface MergedSearchResult {
|
|
43
|
+
title: string;
|
|
44
|
+
url: string;
|
|
45
|
+
snippet: string;
|
|
46
|
+
provider: string;
|
|
47
|
+
providerRank: number;
|
|
48
|
+
providers: string[];
|
|
49
|
+
score: number;
|
|
50
|
+
meta?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
export declare function openUrlsOf(meta: Record<string, unknown> | undefined): string[];
|
|
53
|
+
export declare function mergeSearchResults(lists: Array<{
|
|
54
|
+
provider: string;
|
|
55
|
+
results: SearchResult[];
|
|
56
|
+
}>, limit: number): MergedSearchResult[];
|
|
57
|
+
export interface ResolvedSearch {
|
|
58
|
+
providers: SearchProvider[];
|
|
59
|
+
run(q: SearchQuery): Promise<{
|
|
60
|
+
merged: MergedSearchResult[];
|
|
61
|
+
warnings: string[];
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
64
|
+
export declare function combineSearchProviders(providers: SearchProvider[]): ResolvedSearch;
|
|
65
|
+
export declare function defaultSearchProviders(model: Exclude<LanguageModel, string>): SearchProvider[];
|