@inflexa-ai/harness 0.16.0 → 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.
Files changed (93) hide show
  1. package/dist/agents/conversation-agent.d.ts +3 -0
  2. package/dist/agents/conversation-agent.js +5 -2
  3. package/dist/agents/sandbox/shared.d.ts +3 -0
  4. package/dist/agents/sandbox/shared.js +5 -0
  5. package/dist/agents/sandbox/types.d.ts +1 -1
  6. package/dist/app/chat-turn.d.ts +2 -0
  7. package/dist/app/chat-turn.js +11 -2
  8. package/dist/app/synthesize-run.d.ts +3 -0
  9. package/dist/app/synthesize-run.js +2 -1
  10. package/dist/citations/__fixtures__/resolver.d.ts +3 -0
  11. package/dist/citations/__fixtures__/resolver.js +9 -0
  12. package/dist/citations/aggregate.d.ts +3 -0
  13. package/dist/citations/aggregate.js +44 -0
  14. package/dist/citations/clients/arxiv.d.ts +6 -0
  15. package/dist/citations/clients/arxiv.js +34 -0
  16. package/dist/citations/clients/common.d.ts +11 -0
  17. package/dist/citations/clients/common.js +43 -0
  18. package/dist/citations/clients/crossref.d.ts +8 -0
  19. package/dist/citations/clients/crossref.js +98 -0
  20. package/dist/citations/clients/doi-registry.d.ts +3 -0
  21. package/dist/citations/clients/doi-registry.js +95 -0
  22. package/dist/citations/clients/pubmed.d.ts +6 -0
  23. package/dist/citations/clients/pubmed.js +83 -0
  24. package/dist/citations/clients/semantic-scholar.d.ts +6 -0
  25. package/dist/citations/clients/semantic-scholar.js +60 -0
  26. package/dist/citations/compare.d.ts +9 -0
  27. package/dist/citations/compare.js +72 -0
  28. package/dist/citations/match.d.ts +11 -0
  29. package/dist/citations/match.js +173 -0
  30. package/dist/citations/normalize.d.ts +31 -0
  31. package/dist/citations/normalize.js +187 -0
  32. package/dist/citations/plan.d.ts +2 -0
  33. package/dist/citations/plan.js +59 -0
  34. package/dist/citations/resolve.d.ts +28 -0
  35. package/dist/citations/resolve.js +238 -0
  36. package/dist/citations/types.d.ts +583 -0
  37. package/dist/citations/types.js +129 -0
  38. package/dist/contracts/schemas/chat-parts.d.ts +8 -8
  39. package/dist/contracts/target-dossier.d.ts +20 -20
  40. package/dist/execution/run-synthesis.d.ts +3 -0
  41. package/dist/execution/run-synthesis.js +1 -0
  42. package/dist/index.d.ts +6 -1
  43. package/dist/index.js +3 -0
  44. package/dist/lib/cache.d.ts +8 -0
  45. package/dist/lib/cache.js +35 -0
  46. package/dist/lib/rate-limit.d.ts +35 -0
  47. package/dist/lib/rate-limit.js +121 -0
  48. package/dist/literature/sources/arxiv.d.ts +22 -0
  49. package/dist/literature/sources/arxiv.js +103 -0
  50. package/dist/literature/sources/http.d.ts +28 -0
  51. package/dist/literature/sources/http.js +97 -0
  52. package/dist/literature/sources/pubmed.d.ts +68 -0
  53. package/dist/literature/sources/pubmed.js +266 -0
  54. package/dist/literature/sources/semantic-scholar.d.ts +24 -0
  55. package/dist/literature/sources/semantic-scholar.js +71 -0
  56. package/dist/memory/thread-store.d.ts +142 -25
  57. package/dist/memory/thread-store.js +228 -40
  58. package/dist/prompts/literature-reviewer.d.ts +1 -1
  59. package/dist/prompts/literature-reviewer.js +2 -0
  60. package/dist/runtime/assemble.d.ts +50 -4
  61. package/dist/runtime/assemble.js +47 -3
  62. package/dist/runtime/boot.js +7 -1
  63. package/dist/state/init.js +46 -1
  64. package/dist/state/schema.d.ts +2 -2
  65. package/dist/tools/bio/gene-preclinical-profile.d.ts +1 -1
  66. package/dist/tools/bio/keys.d.ts +1 -0
  67. package/dist/tools/bio/pubmed.js +4 -4
  68. package/dist/tools/lib/ncbi-utils.d.ts +3 -58
  69. package/dist/tools/lib/ncbi-utils.js +2 -286
  70. package/dist/tools/lib/pubmed-client.d.ts +5 -12
  71. package/dist/tools/lib/pubmed-client.js +20 -79
  72. package/dist/tools/research/generate-analogy-report.js +2 -2
  73. package/dist/tools/research/index.d.ts +1 -0
  74. package/dist/tools/research/index.js +1 -0
  75. package/dist/tools/research/inspect-run.d.ts +1 -1
  76. package/dist/tools/research/literature-reviewer.d.ts +3 -0
  77. package/dist/tools/research/literature-reviewer.js +2 -0
  78. package/dist/tools/research/resolve-citation.d.ts +3 -0
  79. package/dist/tools/research/resolve-citation.js +15 -0
  80. package/dist/tools/research/search-arxiv.d.ts +3 -19
  81. package/dist/tools/research/search-arxiv.js +9 -105
  82. package/dist/tools/research/search-semantic-scholar.d.ts +8 -33
  83. package/dist/tools/research/search-semantic-scholar.js +29 -88
  84. package/dist/tools/sandbox/list-available-refs.js +1 -2
  85. package/dist/workflows/execute-analysis.d.ts +3 -0
  86. package/dist/workflows/execute-analysis.js +1 -0
  87. package/dist/workflows/sandbox-step.d.ts +5 -0
  88. package/dist/workflows/sandbox-step.js +1 -0
  89. package/dist/workflows/target-assessment/phase4-assemble.d.ts +2 -2
  90. package/dist/workflows/target-assessment/schemas.d.ts +2 -2
  91. package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +1 -1
  92. package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +1 -1
  93. package/package.json +1 -1
@@ -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
- import { apiFetch, describeApiError } from "../lib/api-utils.js";
12
- const BASE_URL = "https://export.arxiv.org/api/query";
13
- const stripCdata = (s) => s.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, "$1");
14
- const decodeXmlEntities = (s) => s
15
- .replace(/&lt;/g, "<")
16
- .replace(/&gt;/g, ">")
17
- .replace(/&quot;/g, '"')
18
- .replace(/&apos;/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(/&amp;/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 catPart = categories && categories.length > 0 ? ` AND (${categories.map((c) => `cat:${c}`).join(" OR ")})` : "";
109
- const params = new URLSearchParams({
110
- search_query: `all:${query}${catPart}`,
111
- max_results: String(limit),
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
- * 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
- */
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
- import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
13
- const BASE_URL = "https://api.semanticscholar.org/graph/v1";
14
- const DEFAULT_FIELDS = "paperId,title,abstract,year,venue,citationCount,url,authors,externalIds";
15
- // Raw Semantic Scholar wire shape, validated at the fetch boundary. Every field
16
- // is optional — `parseSemanticScholarResponse` already filters/coerces defensively,
17
- // so a partial-but-valid response must still parse; `externalIds` values stay
18
- // unconstrained (`z.unknown`) since the mapper only checks the container is an object.
19
- // The scalar fields are also `.nullable()`: Semantic Scholar sends an explicit
20
- // `null` for a missing abstract/year/venue/url/externalIds (very common), which a
21
- // bare `.optional()` would reject — failing the whole `data` array on one such paper.
22
- const SemanticScholarResponseSchema = z.object({
23
- data: z
24
- .array(z.object({
25
- paperId: z.string().optional(),
26
- title: z.string().optional(),
27
- abstract: z.string().nullable().optional(),
28
- year: z.number().nullable().optional(),
29
- venue: z.string().nullable().optional(),
30
- citationCount: z.number().nullable().optional(),
31
- url: z.string().nullable().optional(),
32
- authors: z.array(z.object({ name: z.string().nullable().optional() })).optional(),
33
- externalIds: z.record(z.string(), z.unknown()).nullable().optional(),
34
- }))
35
- .optional(),
36
- });
37
- export function parseSemanticScholarResponse(raw) {
38
- const data = raw?.data;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inflexa-ai/harness",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Host-agnostic bioinformatics agent harness \u2014 hand-rolled agent loop, DBOS-durable workflows, sandboxed compute.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",