@inflexa-ai/harness 0.15.1 → 0.17.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/dist/agents/conversation-agent.d.ts +3 -0
- package/dist/agents/conversation-agent.js +5 -2
- package/dist/agents/sandbox/shared.d.ts +3 -0
- package/dist/agents/sandbox/shared.js +5 -0
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/app/chat-turn.d.ts +2 -0
- package/dist/app/chat-turn.js +11 -2
- package/dist/app/synthesize-run.d.ts +3 -0
- package/dist/app/synthesize-run.js +2 -1
- package/dist/citations/__fixtures__/resolver.d.ts +3 -0
- package/dist/citations/__fixtures__/resolver.js +9 -0
- package/dist/citations/aggregate.d.ts +3 -0
- package/dist/citations/aggregate.js +44 -0
- package/dist/citations/clients/arxiv.d.ts +6 -0
- package/dist/citations/clients/arxiv.js +34 -0
- package/dist/citations/clients/common.d.ts +11 -0
- package/dist/citations/clients/common.js +43 -0
- package/dist/citations/clients/crossref.d.ts +8 -0
- package/dist/citations/clients/crossref.js +98 -0
- package/dist/citations/clients/doi-registry.d.ts +3 -0
- package/dist/citations/clients/doi-registry.js +95 -0
- package/dist/citations/clients/pubmed.d.ts +6 -0
- package/dist/citations/clients/pubmed.js +83 -0
- package/dist/citations/clients/semantic-scholar.d.ts +6 -0
- package/dist/citations/clients/semantic-scholar.js +60 -0
- package/dist/citations/compare.d.ts +9 -0
- package/dist/citations/compare.js +72 -0
- package/dist/citations/match.d.ts +11 -0
- package/dist/citations/match.js +173 -0
- package/dist/citations/normalize.d.ts +31 -0
- package/dist/citations/normalize.js +187 -0
- package/dist/citations/plan.d.ts +2 -0
- package/dist/citations/plan.js +59 -0
- package/dist/citations/resolve.d.ts +28 -0
- package/dist/citations/resolve.js +238 -0
- package/dist/citations/types.d.ts +583 -0
- package/dist/citations/types.js +129 -0
- package/dist/contracts/chat-events.d.ts +16 -0
- package/dist/contracts/message.d.ts +13 -8
- package/dist/contracts/schemas/chat-events.d.ts +7 -0
- package/dist/contracts/schemas/chat-events.js +2 -0
- package/dist/contracts/schemas/chat-parts.d.ts +8 -8
- package/dist/contracts/target-dossier.d.ts +20 -20
- package/dist/execution/run-synthesis.d.ts +3 -0
- package/dist/execution/run-synthesis.js +1 -0
- package/dist/index.d.ts +14 -10
- package/dist/index.js +20 -16
- package/dist/lib/cache.d.ts +8 -0
- package/dist/lib/cache.js +35 -0
- package/dist/lib/rate-limit.d.ts +35 -0
- package/dist/lib/rate-limit.js +121 -0
- package/dist/literature/sources/arxiv.d.ts +22 -0
- package/dist/literature/sources/arxiv.js +103 -0
- package/dist/literature/sources/http.d.ts +28 -0
- package/dist/literature/sources/http.js +97 -0
- package/dist/literature/sources/pubmed.d.ts +68 -0
- package/dist/literature/sources/pubmed.js +266 -0
- package/dist/literature/sources/semantic-scholar.d.ts +24 -0
- package/dist/literature/sources/semantic-scholar.js +71 -0
- package/dist/memory/content-to-cortex.d.ts +12 -11
- package/dist/memory/content-to-cortex.js +17 -14
- package/dist/memory/conversation-display-backfill.d.ts +25 -0
- package/dist/memory/conversation-display-backfill.js +97 -0
- package/dist/memory/conversation-display-recorder.d.ts +17 -0
- package/dist/memory/conversation-display-recorder.js +156 -0
- package/dist/memory/conversation-display-replay.d.ts +19 -0
- package/dist/memory/conversation-display-replay.js +39 -0
- package/dist/memory/conversation-display-storage.d.ts +86 -0
- package/dist/memory/conversation-display-storage.js +168 -0
- package/dist/memory/reconstruct-cards.d.ts +7 -1
- package/dist/memory/reconstruct-cards.js +5 -1
- package/dist/memory/thread-history.d.ts +46 -11
- package/dist/memory/thread-history.js +55 -13
- package/dist/memory/thread-store.d.ts +142 -25
- package/dist/memory/thread-store.js +228 -40
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +2 -0
- package/dist/runtime/assemble.d.ts +50 -4
- package/dist/runtime/assemble.js +47 -3
- package/dist/runtime/boot.d.ts +8 -2
- package/dist/runtime/boot.js +20 -2
- package/dist/state/init.js +50 -1
- package/dist/state/schema.d.ts +2 -2
- package/dist/tools/bio/gene-preclinical-profile.d.ts +1 -1
- package/dist/tools/bio/keys.d.ts +1 -0
- package/dist/tools/bio/pubmed.js +4 -4
- package/dist/tools/lib/ncbi-utils.d.ts +3 -58
- package/dist/tools/lib/ncbi-utils.js +2 -286
- package/dist/tools/lib/pubmed-client.d.ts +5 -12
- package/dist/tools/lib/pubmed-client.js +20 -79
- package/dist/tools/research/generate-analogy-report.js +2 -2
- package/dist/tools/research/index.d.ts +1 -0
- package/dist/tools/research/index.js +1 -0
- package/dist/tools/research/inspect-run.d.ts +1 -1
- package/dist/tools/research/literature-reviewer.d.ts +3 -0
- package/dist/tools/research/literature-reviewer.js +2 -0
- package/dist/tools/research/resolve-citation.d.ts +3 -0
- package/dist/tools/research/resolve-citation.js +15 -0
- package/dist/tools/research/search-arxiv.d.ts +3 -19
- package/dist/tools/research/search-arxiv.js +9 -105
- package/dist/tools/research/search-semantic-scholar.d.ts +8 -33
- package/dist/tools/research/search-semantic-scholar.js +29 -88
- package/dist/tools/sandbox/list-available-refs.js +1 -2
- package/dist/workflows/execute-analysis.d.ts +3 -0
- package/dist/workflows/execute-analysis.js +1 -0
- package/dist/workflows/sandbox-step.d.ts +5 -0
- package/dist/workflows/sandbox-step.js +1 -0
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +2 -2
- package/dist/workflows/target-assessment/schemas.d.ts +2 -2
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +1 -1
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +1 -1
- package/package.json +1 -1
|
@@ -53,7 +53,7 @@ declare function formatRun(r: CortexRunRow, verbose: boolean, exposePaths?: bool
|
|
|
53
53
|
synthesisReason?: string | undefined;
|
|
54
54
|
runId: string;
|
|
55
55
|
workflowName: string;
|
|
56
|
-
status: "
|
|
56
|
+
status: "partial" | "running" | "completed" | "failed" | "canceled" | "suspended_insufficient_funds";
|
|
57
57
|
startedAt: string;
|
|
58
58
|
completedAt: string | null;
|
|
59
59
|
planId: string | null;
|
|
@@ -19,6 +19,7 @@ import { type Tool } from "../define-tool.js";
|
|
|
19
19
|
import { type BioToolKeys } from "../bio/keys.js";
|
|
20
20
|
import type { Logger } from "../../lib/logger.js";
|
|
21
21
|
import type { UsageRecorder } from "../../billing/usage-recorder.js";
|
|
22
|
+
import type { CitationResolver } from "../../citations/types.js";
|
|
22
23
|
export interface LiteratureReviewerDeps {
|
|
23
24
|
/** Operational logging seam; omitted falls back to no-op. */
|
|
24
25
|
readonly logger?: Logger;
|
|
@@ -30,6 +31,8 @@ export interface LiteratureReviewerDeps {
|
|
|
30
31
|
readonly bioKeys: BioToolKeys;
|
|
31
32
|
/** LLM usage-accounting seam for the child loop; omitted falls back to the no-op recorder. */
|
|
32
33
|
readonly usageRecorder?: UsageRecorder;
|
|
34
|
+
/** Shared bibliographic verification service; all agent surfaces share its pacing/cache. */
|
|
35
|
+
readonly citationResolver: CitationResolver;
|
|
33
36
|
}
|
|
34
37
|
/** Build the `literature_reviewer` delegation tool bound to its provider. */
|
|
35
38
|
export declare function createLiteratureReviewerTool(deps: LiteratureReviewerDeps): Tool;
|
|
@@ -27,6 +27,7 @@ import { genePreclinicalProfileTool } from "../bio/gene-preclinical-profile.js";
|
|
|
27
27
|
import { lookupAnnotationTool } from "../bio/lookup-annotation.js";
|
|
28
28
|
import { searchGeneTool } from "../bio/search-gene.js";
|
|
29
29
|
import { searchInteractionsTool } from "../bio/search-interactions.js";
|
|
30
|
+
import { createResolveCitationTool } from "./resolve-citation.js";
|
|
30
31
|
/** Sub-agent identity — appended to `callPath`, set as `agentId`. */
|
|
31
32
|
const AGENT_ID = "literature-reviewer";
|
|
32
33
|
/** Multi-tool research budget — search → read → synthesize over many genes. */
|
|
@@ -40,6 +41,7 @@ export function createLiteratureReviewerTool(deps) {
|
|
|
40
41
|
lookupAnnotationTool,
|
|
41
42
|
searchInteractionsTool,
|
|
42
43
|
ncbi.pubmed,
|
|
44
|
+
createResolveCitationTool(deps.citationResolver),
|
|
43
45
|
chemDb.drugGeneInteractions,
|
|
44
46
|
genePreclinicalProfileTool,
|
|
45
47
|
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ok } from "neverthrow";
|
|
2
|
+
import { CitationInputSchema } from "../../citations/types.js";
|
|
3
|
+
import { defineTool } from "../define-tool.js";
|
|
4
|
+
export function createResolveCitationTool(resolver) {
|
|
5
|
+
return defineTool({
|
|
6
|
+
id: "resolve_citation",
|
|
7
|
+
description: "Verify one supplied citation against applicable bibliographic authorities. " +
|
|
8
|
+
"Use this for 'does this reference exist and does its metadata agree?', not for topical literature discovery. " +
|
|
9
|
+
"Returns source-labelled records, field comparisons, conflicts, coverage, and one of verified, metadata_mismatch, " +
|
|
10
|
+
"not_found, unverifiable, or inconclusive. Source failure never becomes not_found.",
|
|
11
|
+
inputSchema: CitationInputSchema,
|
|
12
|
+
describeCall: ({ citation }) => `verify ${citation}`,
|
|
13
|
+
execute: async (input, ctx) => ok(await resolver.resolveOne(input, { signal: ctx.signal })),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* control-theory preprints; Semantic Scholar lags it by months.
|
|
5
|
-
*
|
|
6
|
-
* Same wire call and envelope as the legacy tool. Stateless HTTP; no deps.
|
|
7
|
-
*/
|
|
1
|
+
/** Search arXiv for preprints through the shared authority client. */
|
|
2
|
+
import { type ArxivPaper } from "../../literature/sources/arxiv.js";
|
|
3
|
+
export { parseArxivAtom, type ArxivPaper } from "../../literature/sources/arxiv.js";
|
|
8
4
|
type SearchArxivOutput = {
|
|
9
5
|
success: false;
|
|
10
6
|
error: string;
|
|
@@ -13,20 +9,8 @@ type SearchArxivOutput = {
|
|
|
13
9
|
success: true;
|
|
14
10
|
papers: ArxivPaper[];
|
|
15
11
|
};
|
|
16
|
-
export interface ArxivPaper {
|
|
17
|
-
id: string;
|
|
18
|
-
title: string;
|
|
19
|
-
abstract: string;
|
|
20
|
-
authors: string[];
|
|
21
|
-
published: string;
|
|
22
|
-
categories: string[];
|
|
23
|
-
url: string;
|
|
24
|
-
pdfUrl?: string;
|
|
25
|
-
}
|
|
26
|
-
export declare function parseArxivAtom(xml: string): ArxivPaper[];
|
|
27
12
|
export declare const searchArxivTool: import("../define-tool.js").Tool<{
|
|
28
13
|
query: string;
|
|
29
14
|
limit: number;
|
|
30
15
|
categories?: string[] | undefined;
|
|
31
16
|
}, SearchArxivOutput>;
|
|
32
|
-
export {};
|
|
@@ -1,96 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search arXiv for preprints. Returns Atom XML which we parse without a
|
|
3
|
-
* dependency. arXiv is the primary source for ML / physics / math /
|
|
4
|
-
* control-theory preprints; Semantic Scholar lags it by months.
|
|
5
|
-
*
|
|
6
|
-
* Same wire call and envelope as the legacy tool. Stateless HTTP; no deps.
|
|
7
|
-
*/
|
|
1
|
+
/** Search arXiv for preprints through the shared authority client. */
|
|
8
2
|
import { ok } from "neverthrow";
|
|
9
3
|
import { z } from "zod";
|
|
4
|
+
import { createArxivSource } from "../../literature/sources/arxiv.js";
|
|
10
5
|
import { defineTool } from "../define-tool.js";
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const stripCdata = (s) => s.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, "$1");
|
|
14
|
-
const decodeXmlEntities = (s) => s
|
|
15
|
-
.replace(/</g, "<")
|
|
16
|
-
.replace(/>/g, ">")
|
|
17
|
-
.replace(/"/g, '"')
|
|
18
|
-
.replace(/'/g, "'")
|
|
19
|
-
.replace(/&#x([0-9a-fA-F]+);/g, (_, h) => String.fromCodePoint(parseInt(h, 16)))
|
|
20
|
-
.replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(parseInt(d, 10)))
|
|
21
|
-
.replace(/&/g, "&"); // amp last so we don't double-decode
|
|
22
|
-
const collapseWs = (s) => decodeXmlEntities(stripCdata(s)).replace(/\s+/g, " ").trim();
|
|
23
|
-
const extractEntries = (xml) => {
|
|
24
|
-
const re = /<entry\b[^>]*>([\s\S]*?)<\/entry>/g;
|
|
25
|
-
const out = [];
|
|
26
|
-
let m;
|
|
27
|
-
while ((m = re.exec(xml)) !== null)
|
|
28
|
-
out.push(m[1]);
|
|
29
|
-
return out;
|
|
30
|
-
};
|
|
31
|
-
const firstMatch = (entry, tag) => {
|
|
32
|
-
const re = new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)</${tag}>`);
|
|
33
|
-
const m = entry.match(re);
|
|
34
|
-
return m?.[1];
|
|
35
|
-
};
|
|
36
|
-
const allMatches = (entry, tag) => {
|
|
37
|
-
const re = new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)</${tag}>`, "g");
|
|
38
|
-
const out = [];
|
|
39
|
-
let m;
|
|
40
|
-
while ((m = re.exec(entry)) !== null)
|
|
41
|
-
out.push(m[1]);
|
|
42
|
-
return out;
|
|
43
|
-
};
|
|
44
|
-
const linkAttr = (entry, predicate) => {
|
|
45
|
-
const re = /<link\b([^>]*)\/>/g;
|
|
46
|
-
let m;
|
|
47
|
-
while ((m = re.exec(entry)) !== null) {
|
|
48
|
-
if (predicate(m[1])) {
|
|
49
|
-
const hrefMatch = m[1].match(/href="([^"]+)"/);
|
|
50
|
-
if (hrefMatch)
|
|
51
|
-
return hrefMatch[1];
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return undefined;
|
|
55
|
-
};
|
|
56
|
-
const categoryTerms = (entry) => {
|
|
57
|
-
const re = /<category\b([^>]*)\/>/g;
|
|
58
|
-
const out = [];
|
|
59
|
-
let m;
|
|
60
|
-
while ((m = re.exec(entry)) !== null) {
|
|
61
|
-
const termMatch = m[1].match(/term="([^"]+)"/);
|
|
62
|
-
if (termMatch)
|
|
63
|
-
out.push(termMatch[1]);
|
|
64
|
-
}
|
|
65
|
-
return out;
|
|
66
|
-
};
|
|
67
|
-
export function parseArxivAtom(xml) {
|
|
68
|
-
return extractEntries(xml).flatMap((entry) => {
|
|
69
|
-
const idRaw = firstMatch(entry, "id");
|
|
70
|
-
const title = firstMatch(entry, "title");
|
|
71
|
-
if (!idRaw || !title)
|
|
72
|
-
return [];
|
|
73
|
-
const idMatch = idRaw.match(/abs\/(.+)$/);
|
|
74
|
-
const authors = allMatches(entry, "author")
|
|
75
|
-
.map((a) => firstMatch(a, "name"))
|
|
76
|
-
.filter((n) => !!n)
|
|
77
|
-
.map(collapseWs);
|
|
78
|
-
const htmlUrl = linkAttr(entry, (a) => /rel="alternate"/.test(a) && /type="text\/html"/.test(a));
|
|
79
|
-
const pdfUrl = linkAttr(entry, (a) => /title="pdf"/.test(a));
|
|
80
|
-
return [
|
|
81
|
-
{
|
|
82
|
-
id: idMatch?.[1] ?? collapseWs(idRaw),
|
|
83
|
-
title: collapseWs(title),
|
|
84
|
-
abstract: collapseWs(firstMatch(entry, "summary") ?? ""),
|
|
85
|
-
authors,
|
|
86
|
-
published: collapseWs(firstMatch(entry, "published") ?? ""),
|
|
87
|
-
categories: categoryTerms(entry),
|
|
88
|
-
url: htmlUrl ?? collapseWs(idRaw),
|
|
89
|
-
pdfUrl,
|
|
90
|
-
},
|
|
91
|
-
];
|
|
92
|
-
});
|
|
93
|
-
}
|
|
6
|
+
export { parseArxivAtom } from "../../literature/sources/arxiv.js";
|
|
7
|
+
const source = createArxivSource({ maxRetries: 3, retryDelayMs: 1_000, timeoutMs: 90_000 });
|
|
94
8
|
export const searchArxivTool = defineTool({
|
|
95
9
|
id: "search_arxiv",
|
|
96
10
|
description: "Search arXiv for preprints in ML, physics, math, control theory, " +
|
|
@@ -104,20 +18,10 @@ export const searchArxivTool = defineTool({
|
|
|
104
18
|
.describe('Optional arXiv category filters (e.g., ["cs.LG", "math.OC"]). ' + "Combined with the query using AND."),
|
|
105
19
|
limit: z.number().int().min(1).max(20).default(10).describe("Maximum results (1–20, default 10)."),
|
|
106
20
|
}),
|
|
107
|
-
execute: async ({ query, categories, limit }) => {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
sortBy: "relevance",
|
|
113
|
-
sortOrder: "descending",
|
|
114
|
-
});
|
|
115
|
-
const res = await apiFetch(`${BASE_URL}?${params}`, {
|
|
116
|
-
parseAs: "text",
|
|
117
|
-
});
|
|
118
|
-
if (res.isErr()) {
|
|
119
|
-
return ok({ success: false, error: describeApiError(res.error), papers: [] });
|
|
120
|
-
}
|
|
121
|
-
return ok({ success: true, papers: parseArxivAtom(res.value) });
|
|
21
|
+
execute: async ({ query, categories, limit }, context) => {
|
|
22
|
+
const result = await source.search({ query, ...(categories === undefined ? {} : { categories }), limit }, context.signal);
|
|
23
|
+
if (result.status !== "ok")
|
|
24
|
+
return ok({ success: false, error: result.detail, papers: [] });
|
|
25
|
+
return ok({ success: true, papers: result.value });
|
|
122
26
|
},
|
|
123
27
|
});
|
|
@@ -1,33 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export interface SemanticScholarPaper {
|
|
10
|
-
id: string;
|
|
11
|
-
title: string;
|
|
12
|
-
abstract?: string;
|
|
13
|
-
year?: number;
|
|
14
|
-
venue?: string;
|
|
15
|
-
citationCount?: number;
|
|
16
|
-
url?: string;
|
|
17
|
-
authors: string[];
|
|
18
|
-
externalIds?: Record<string, string>;
|
|
19
|
-
}
|
|
20
|
-
type SearchSemanticScholarOutput = {
|
|
21
|
-
success: false;
|
|
22
|
-
error: string;
|
|
23
|
-
papers: SemanticScholarPaper[];
|
|
24
|
-
} | {
|
|
25
|
-
success: true;
|
|
26
|
-
papers: SemanticScholarPaper[];
|
|
27
|
-
};
|
|
28
|
-
export declare function parseSemanticScholarResponse(raw: unknown): SemanticScholarPaper[];
|
|
29
|
-
export declare const searchSemanticScholarTool: import("../define-tool.js").Tool<{
|
|
30
|
-
query: string;
|
|
31
|
-
limit: number;
|
|
32
|
-
}, SearchSemanticScholarOutput>;
|
|
33
|
-
export {};
|
|
1
|
+
/** Search Semantic Scholar through the shared authority client. */
|
|
2
|
+
import { type SemanticScholarSearchPaper } from "../../literature/sources/semantic-scholar.js";
|
|
3
|
+
import { type Tool } from "../define-tool.js";
|
|
4
|
+
export { parseSemanticScholarResponse } from "../../literature/sources/semantic-scholar.js";
|
|
5
|
+
export type SemanticScholarPaper = SemanticScholarSearchPaper;
|
|
6
|
+
export declare function createSearchSemanticScholarTool(options?: {
|
|
7
|
+
readonly apiKey?: string;
|
|
8
|
+
}): Tool;
|
|
@@ -1,93 +1,34 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search Semantic Scholar Graph API for academic papers across all
|
|
3
|
-
* sciences. No API key required; rate-limited but reasonable for agent
|
|
4
|
-
* use. Used by the analogical-reasoner for cross-domain analogical search.
|
|
5
|
-
*
|
|
6
|
-
* Same wire call and envelope as the legacy tool, packaged as `defineTool`.
|
|
7
|
-
* Stateless HTTP; no deps.
|
|
8
|
-
*/
|
|
1
|
+
/** Search Semantic Scholar through the shared authority client. */
|
|
9
2
|
import { ok } from "neverthrow";
|
|
10
3
|
import { z } from "zod";
|
|
4
|
+
import { createSemanticScholarSource } from "../../literature/sources/semantic-scholar.js";
|
|
11
5
|
import { defineTool } from "../define-tool.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (!Array.isArray(data))
|
|
40
|
-
return [];
|
|
41
|
-
return data
|
|
42
|
-
.filter((p) => typeof p === "object" && p !== null && "paperId" in p && "title" in p)
|
|
43
|
-
.map((p) => {
|
|
44
|
-
const authors = Array.isArray(p.authors)
|
|
45
|
-
? p.authors.map((a) => a?.name).filter((n) => typeof n === "string")
|
|
46
|
-
: [];
|
|
47
|
-
return {
|
|
48
|
-
id: String(p.paperId),
|
|
49
|
-
title: String(p.title),
|
|
50
|
-
abstract: typeof p.abstract === "string" ? p.abstract : undefined,
|
|
51
|
-
year: typeof p.year === "number" ? p.year : undefined,
|
|
52
|
-
venue: typeof p.venue === "string" ? p.venue : undefined,
|
|
53
|
-
citationCount: typeof p.citationCount === "number" ? p.citationCount : undefined,
|
|
54
|
-
url: typeof p.url === "string" ? p.url : undefined,
|
|
55
|
-
authors,
|
|
56
|
-
externalIds: p.externalIds && typeof p.externalIds === "object" ? p.externalIds : undefined,
|
|
57
|
-
};
|
|
6
|
+
export { parseSemanticScholarResponse } from "../../literature/sources/semantic-scholar.js";
|
|
7
|
+
export function createSearchSemanticScholarTool(options = {}) {
|
|
8
|
+
const source = createSemanticScholarSource({
|
|
9
|
+
maxRetries: 3,
|
|
10
|
+
retryDelayMs: 1_000,
|
|
11
|
+
timeoutMs: 90_000,
|
|
12
|
+
...(options.apiKey === undefined ? {} : { apiKey: options.apiKey }),
|
|
13
|
+
});
|
|
14
|
+
return defineTool({
|
|
15
|
+
id: "search_semantic_scholar",
|
|
16
|
+
description: "Search Semantic Scholar for academic papers across all sciences " +
|
|
17
|
+
"(biology, ML, physics, math, economics, engineering, etc.). Returns " +
|
|
18
|
+
"paper id, title, abstract, year, venue, citation count, authors, and " +
|
|
19
|
+
"external IDs (DOI, ArXiv). Best for cross-domain analogical search.",
|
|
20
|
+
inputSchema: z.object({
|
|
21
|
+
query: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe("Free-text query. Use natural language phrases such as " +
|
|
24
|
+
'"reinforcement learning for control" or "feedback stabilisation in oscillators".'),
|
|
25
|
+
limit: z.number().int().min(1).max(20).default(10).describe("Maximum number of results to return (1–20, default 10)."),
|
|
26
|
+
}),
|
|
27
|
+
execute: async ({ query, limit }, context) => {
|
|
28
|
+
const result = await source.search(query, limit, context.signal);
|
|
29
|
+
if (result.status !== "ok")
|
|
30
|
+
return ok({ success: false, error: result.detail, papers: [] });
|
|
31
|
+
return ok({ success: true, papers: result.value });
|
|
32
|
+
},
|
|
58
33
|
});
|
|
59
34
|
}
|
|
60
|
-
export const searchSemanticScholarTool = defineTool({
|
|
61
|
-
id: "search_semantic_scholar",
|
|
62
|
-
description: "Search Semantic Scholar for academic papers across all sciences " +
|
|
63
|
-
"(biology, ML, physics, math, economics, engineering, etc.). Returns " +
|
|
64
|
-
"paper id, title, abstract, year, venue, citation count, authors, and " +
|
|
65
|
-
"external IDs (DOI, ArXiv). Best for cross-domain analogical search.",
|
|
66
|
-
inputSchema: z.object({
|
|
67
|
-
query: z
|
|
68
|
-
.string()
|
|
69
|
-
.describe("Free-text query. Use natural language phrases such as " + '"reinforcement learning for control" or "feedback stabilisation in oscillators".'),
|
|
70
|
-
limit: z.number().int().min(1).max(20).default(10).describe("Maximum number of results to return (1–20, default 10)."),
|
|
71
|
-
}),
|
|
72
|
-
execute: async ({ query, limit }) => {
|
|
73
|
-
const params = new URLSearchParams({
|
|
74
|
-
query,
|
|
75
|
-
limit: String(limit),
|
|
76
|
-
fields: DEFAULT_FIELDS,
|
|
77
|
-
});
|
|
78
|
-
const apiKey = process.env.SEMANTIC_SCHOLAR_API_KEY;
|
|
79
|
-
const headers = {};
|
|
80
|
-
if (apiKey)
|
|
81
|
-
headers["x-api-key"] = apiKey;
|
|
82
|
-
const res = await apiFetchValidated(`${BASE_URL}/paper/search?${params}`, SemanticScholarResponseSchema, {
|
|
83
|
-
headers,
|
|
84
|
-
});
|
|
85
|
-
if (res.isErr()) {
|
|
86
|
-
return ok({ success: false, error: describeApiError(res.error), papers: [] });
|
|
87
|
-
}
|
|
88
|
-
return ok({
|
|
89
|
-
success: true,
|
|
90
|
-
papers: parseSemanticScholarResponse(res.value),
|
|
91
|
-
});
|
|
92
|
-
},
|
|
93
|
-
});
|
|
@@ -318,9 +318,8 @@ async function scanStore(root, relative, recursive = false) {
|
|
|
318
318
|
const entries = [];
|
|
319
319
|
let scanned = 0;
|
|
320
320
|
let pathBytes = 0;
|
|
321
|
-
let truncated = false;
|
|
322
321
|
const { values: children, cut } = await cappedEntries(target, Math.min(MAX_ENTRIES + 2, MAX_SCANNED_ENTRIES));
|
|
323
|
-
truncated = cut;
|
|
322
|
+
let truncated = cut;
|
|
324
323
|
for (const child of children) {
|
|
325
324
|
const childRelative = relative === "." ? child.name : `${relative}/${child.name}`;
|
|
326
325
|
if (childRelative === ".inflexa" || childRelative.startsWith(".inflexa/") || childRelative === "registry.json")
|
|
@@ -64,6 +64,7 @@ import type { RunSession } from "../auth/types.js";
|
|
|
64
64
|
import type { RunAuthorizer } from "../execution/run-authorizer.js";
|
|
65
65
|
import type { Logger } from "../lib/logger.js";
|
|
66
66
|
import type { UsageRecorder } from "../billing/usage-recorder.js";
|
|
67
|
+
import type { CitationResolver } from "../citations/types.js";
|
|
67
68
|
import type { SynthesisStatus, UpdateStepExecutionInput } from "../state/index.js";
|
|
68
69
|
import type { AnalysisStep } from "../schemas/workflow-state.js";
|
|
69
70
|
import type { ChatProvider, EmbeddingProvider } from "../providers/types.js";
|
|
@@ -277,6 +278,8 @@ export interface ExecuteAnalysisDeps {
|
|
|
277
278
|
readonly synthesisModel: string;
|
|
278
279
|
/** API keys for the bio/chem tools the embedded literature reviewer uses. */
|
|
279
280
|
readonly bioKeys: BioToolKeys;
|
|
281
|
+
/** Shared resolver for the literature reviewer used during synthesis. */
|
|
282
|
+
readonly citationResolver: CitationResolver;
|
|
280
283
|
/** Run-level billing-bracket seam (managed: external bracket; OSS: no-op). */
|
|
281
284
|
readonly runCharge: RunCharge;
|
|
282
285
|
/** Run-authorization seam — the terminal path revokes through `revoke`. */
|
|
@@ -320,6 +320,7 @@ export function synthesizeFindings(args) {
|
|
|
320
320
|
resolveWorkspaceRoot: deps.resolveWorkspaceRoot,
|
|
321
321
|
synthesisModel: deps.synthesisModel,
|
|
322
322
|
bioKeys: deps.bioKeys,
|
|
323
|
+
citationResolver: deps.citationResolver,
|
|
323
324
|
usageRecorder: deps.usageRecorder,
|
|
324
325
|
}, {
|
|
325
326
|
analysisId,
|
|
@@ -30,6 +30,7 @@ import type { TokenUsageRollup } from "@inflexa-ai/harness/contracts/usage.js";
|
|
|
30
30
|
import type { Pool } from "pg";
|
|
31
31
|
import type { Logger } from "../lib/logger.js";
|
|
32
32
|
import type { UsageRecorder } from "../billing/usage-recorder.js";
|
|
33
|
+
import type { CitationResolver } from "../citations/types.js";
|
|
33
34
|
import type { AgentDefinition, LoopMessage } from "../loop/types.js";
|
|
34
35
|
import type { AgentChat, EmbeddingProvider } from "../providers/types.js";
|
|
35
36
|
import { type RunSession } from "../auth/types.js";
|
|
@@ -200,6 +201,8 @@ export interface SandboxAgentBuildContext {
|
|
|
200
201
|
* bound to this holder.
|
|
201
202
|
*/
|
|
202
203
|
readonly blockerHolder: BlockerHolder;
|
|
204
|
+
/** Shared host-side citation resolver for allowlisted sandbox agents. */
|
|
205
|
+
readonly citationResolver: CitationResolver;
|
|
203
206
|
}
|
|
204
207
|
/**
|
|
205
208
|
* Inversion of control: the parent supplies the live agent, the parent's
|
|
@@ -222,6 +225,8 @@ export interface SandboxStepDeps {
|
|
|
222
225
|
* post-step sub-agent loops alike; omitted falls back to the no-op recorder.
|
|
223
226
|
*/
|
|
224
227
|
readonly usageRecorder?: UsageRecorder;
|
|
228
|
+
/** Shared resolver threaded from `assembleCoreRuntime`. */
|
|
229
|
+
readonly citationResolver: CitationResolver;
|
|
225
230
|
/** Non-streaming chat — drives the agent loop + the post-step sub-agents. */
|
|
226
231
|
readonly provider: AgentChat;
|
|
227
232
|
/** Write-side embedder for the post-step vector index. */
|
|
@@ -193,6 +193,7 @@ export async function runSandboxStepBody(input, deps) {
|
|
|
193
193
|
deadlineMs: () => stepDeadlineMs,
|
|
194
194
|
lineageCollector,
|
|
195
195
|
blockerHolder,
|
|
196
|
+
citationResolver: deps.citationResolver,
|
|
196
197
|
});
|
|
197
198
|
// Built over THIS agent's tools, not a shared table: a sandbox agent's roster
|
|
198
199
|
// differs per agent type, and each tool describes its own calls.
|
|
@@ -1703,11 +1703,11 @@ export declare const Phase4OutputSchema: z.ZodObject<{
|
|
|
1703
1703
|
dog: "dog";
|
|
1704
1704
|
}>;
|
|
1705
1705
|
rank: z.ZodEnum<{
|
|
1706
|
+
no_data: "no_data";
|
|
1707
|
+
absent: "absent";
|
|
1706
1708
|
high: "high";
|
|
1707
1709
|
medium: "medium";
|
|
1708
1710
|
low: "low";
|
|
1709
|
-
absent: "absent";
|
|
1710
|
-
no_data: "no_data";
|
|
1711
1711
|
not_loaded: "not_loaded";
|
|
1712
1712
|
}>;
|
|
1713
1713
|
}, z.core.$strip>>;
|
|
@@ -250,10 +250,10 @@ export declare const ExpressionMultiSpeciesBundleSchema: z.ZodObject<{
|
|
|
250
250
|
tissues: z.ZodArray<z.ZodObject<{
|
|
251
251
|
tissue: z.ZodString;
|
|
252
252
|
rank: z.ZodEnum<{
|
|
253
|
+
absent: "absent";
|
|
253
254
|
high: "high";
|
|
254
255
|
medium: "medium";
|
|
255
256
|
low: "low";
|
|
256
|
-
absent: "absent";
|
|
257
257
|
}>;
|
|
258
258
|
expressionScore: z.ZodNullable<z.ZodNumber>;
|
|
259
259
|
}, z.core.$strip>>;
|
|
@@ -669,10 +669,10 @@ export declare const Phase1BundleSchema: z.ZodObject<{
|
|
|
669
669
|
tissues: z.ZodArray<z.ZodObject<{
|
|
670
670
|
tissue: z.ZodString;
|
|
671
671
|
rank: z.ZodEnum<{
|
|
672
|
+
absent: "absent";
|
|
672
673
|
high: "high";
|
|
673
674
|
medium: "medium";
|
|
674
675
|
low: "low";
|
|
675
|
-
absent: "absent";
|
|
676
676
|
}>;
|
|
677
677
|
expressionScore: z.ZodNullable<z.ZodNumber>;
|
|
678
678
|
}, z.core.$strip>>;
|
|
@@ -336,10 +336,10 @@ export declare const Phase2BundleSchema: z.ZodObject<{
|
|
|
336
336
|
tissues: z.ZodArray<z.ZodObject<{
|
|
337
337
|
tissue: z.ZodString;
|
|
338
338
|
rank: z.ZodEnum<{
|
|
339
|
+
absent: "absent";
|
|
339
340
|
high: "high";
|
|
340
341
|
medium: "medium";
|
|
341
342
|
low: "low";
|
|
342
|
-
absent: "absent";
|
|
343
343
|
}>;
|
|
344
344
|
expressionScore: z.ZodNullable<z.ZodNumber>;
|
|
345
345
|
}, z.core.$strip>>;
|
|
@@ -421,10 +421,10 @@ export declare const Phase3BundleSchema: z.ZodObject<{
|
|
|
421
421
|
tissues: z.ZodArray<z.ZodObject<{
|
|
422
422
|
tissue: z.ZodString;
|
|
423
423
|
rank: z.ZodEnum<{
|
|
424
|
+
absent: "absent";
|
|
424
425
|
high: "high";
|
|
425
426
|
medium: "medium";
|
|
426
427
|
low: "low";
|
|
427
|
-
absent: "absent";
|
|
428
428
|
}>;
|
|
429
429
|
expressionScore: z.ZodNullable<z.ZodNumber>;
|
|
430
430
|
}, z.core.$strip>>;
|
package/package.json
CHANGED