@inflexa-ai/harness 0.42.1 → 0.43.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 (217) hide show
  1. package/README.md +2 -2
  2. package/dist/agents/conversation-agent.js +5 -1
  3. package/dist/agents/sandbox/drug-repurposing-agent.js +1 -0
  4. package/dist/agents/sandbox/shared.d.ts +1 -6
  5. package/dist/agents/sandbox/shared.js +3 -16
  6. package/dist/agents/sandbox/types.d.ts +1 -1
  7. package/dist/app/chat-turn.js +13 -1
  8. package/dist/config/environment-stores.d.ts +4 -2
  9. package/dist/contracts/chat-events.d.ts +9 -1
  10. package/dist/contracts/chat-frame.d.ts +3 -3
  11. package/dist/contracts/chat-frame.js +8 -3
  12. package/dist/contracts/chat-parts.d.ts +4 -1
  13. package/dist/contracts/data-profile.d.ts +4 -6
  14. package/dist/contracts/index.d.ts +1 -1
  15. package/dist/contracts/report-blocks.d.ts +1364 -75
  16. package/dist/contracts/report-blocks.js +221 -29
  17. package/dist/contracts/report-reference.js +1 -1
  18. package/dist/contracts/schemas/chat-events.d.ts +13 -0
  19. package/dist/contracts/schemas/chat-events.js +5 -0
  20. package/dist/contracts/schemas/chat-parts.d.ts +2 -2
  21. package/dist/contracts/schemas/index.d.ts +1 -1
  22. package/dist/contracts/schemas/index.js +1 -1
  23. package/dist/execution/input-signature.d.ts +7 -13
  24. package/dist/execution/input-signature.js +0 -0
  25. package/dist/execution/run-canceler.d.ts +3 -2
  26. package/dist/execution/run-canceler.js +3 -2
  27. package/dist/execution/run-event-stream.d.ts +16 -2
  28. package/dist/execution/run-event-stream.js +54 -3
  29. package/dist/index.d.ts +1 -8
  30. package/dist/index.js +5 -16
  31. package/dist/input-scan/enrich.d.ts +0 -2
  32. package/dist/input-scan/enrich.js +0 -1
  33. package/dist/lib/metrics.js +6 -7
  34. package/dist/lib/otel-spans.d.ts +4 -9
  35. package/dist/lib/otel-spans.js +3 -8
  36. package/dist/loop/run-agent.d.ts +4 -2
  37. package/dist/loop/run-agent.js +38 -23
  38. package/dist/memory/thread-history.d.ts +1 -1
  39. package/dist/prompts/report-session.d.ts +1 -1
  40. package/dist/prompts/report-session.js +17 -0
  41. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  42. package/dist/prompts/sandbox/drug-repurposing-agent.js +7 -0
  43. package/dist/provenance/exec-frame.d.ts +1 -1
  44. package/dist/report-model/authoring-grammar.d.ts +416 -17
  45. package/dist/report-model/authoring-grammar.js +25 -4
  46. package/dist/report-model/block-walk.d.ts +20 -4
  47. package/dist/report-model/block-walk.js +64 -7
  48. package/dist/report-model/draft-finish.d.ts +6 -2
  49. package/dist/report-model/draft-finish.js +6 -1
  50. package/dist/report-model/production-resolver.d.ts +8 -0
  51. package/dist/report-model/production-resolver.js +1 -1
  52. package/dist/report-model/validate.d.ts +20 -10
  53. package/dist/report-model/validate.js +29 -13
  54. package/dist/report-render/chart-export.d.ts +52 -0
  55. package/dist/report-render/chart-export.js +192 -0
  56. package/dist/report-render/chart-presets.d.ts +46 -47
  57. package/dist/report-render/chart-presets.js +31 -101
  58. package/dist/report-render/chart-renderers.d.ts +163 -0
  59. package/dist/report-render/chart-renderers.js +1055 -0
  60. package/dist/report-render/chart-toolbox.d.ts +124 -0
  61. package/dist/report-render/chart-toolbox.js +595 -0
  62. package/dist/report-render/chart.d.ts +60 -27
  63. package/dist/report-render/chart.js +2323 -524
  64. package/dist/report-render/design.d.ts +476 -16
  65. package/dist/report-render/design.js +390 -56
  66. package/dist/report-render/figures/common.d.ts +321 -0
  67. package/dist/report-render/figures/common.js +759 -0
  68. package/dist/report-render/figures/dendrogram.d.ts +36 -0
  69. package/dist/report-render/figures/dendrogram.js +130 -0
  70. package/dist/report-render/figures/dense.d.ts +111 -0
  71. package/dist/report-render/figures/dense.js +204 -0
  72. package/dist/report-render/figures/dotplot.d.ts +28 -0
  73. package/dist/report-render/figures/dotplot.js +234 -0
  74. package/dist/report-render/figures/embedding.d.ts +43 -0
  75. package/dist/report-render/figures/embedding.js +360 -0
  76. package/dist/report-render/figures/equal-units.d.ts +101 -0
  77. package/dist/report-render/figures/equal-units.js +215 -0
  78. package/dist/report-render/figures/forest.d.ts +20 -0
  79. package/dist/report-render/figures/forest.js +398 -0
  80. package/dist/report-render/figures/gsea.d.ts +30 -0
  81. package/dist/report-render/figures/gsea.js +391 -0
  82. package/dist/report-render/figures/heatmap.d.ts +40 -0
  83. package/dist/report-render/figures/heatmap.js +395 -0
  84. package/dist/report-render/figures/index.d.ts +135 -0
  85. package/dist/report-render/figures/index.js +100 -0
  86. package/dist/report-render/figures/km.d.ts +16 -0
  87. package/dist/report-render/figures/km.js +406 -0
  88. package/dist/report-render/figures/label-room.d.ts +130 -0
  89. package/dist/report-render/figures/label-room.js +341 -0
  90. package/dist/report-render/figures/locuszoom.d.ts +50 -0
  91. package/dist/report-render/figures/locuszoom.js +675 -0
  92. package/dist/report-render/figures/lollipop.d.ts +16 -0
  93. package/dist/report-render/figures/lollipop.js +247 -0
  94. package/dist/report-render/figures/ma.d.ts +20 -0
  95. package/dist/report-render/figures/ma.js +114 -0
  96. package/dist/report-render/figures/manhattan.d.ts +60 -0
  97. package/dist/report-render/figures/manhattan.js +343 -0
  98. package/dist/report-render/figures/oncoprint.d.ts +41 -0
  99. package/dist/report-render/figures/oncoprint.js +420 -0
  100. package/dist/report-render/figures/pca.d.ts +37 -0
  101. package/dist/report-render/figures/pca.js +241 -0
  102. package/dist/report-render/figures/qq.d.ts +30 -0
  103. package/dist/report-render/figures/qq.js +182 -0
  104. package/dist/report-render/figures/roc.d.ts +17 -0
  105. package/dist/report-render/figures/roc.js +116 -0
  106. package/dist/report-render/figures/sankey.d.ts +48 -0
  107. package/dist/report-render/figures/sankey.js +353 -0
  108. package/dist/report-render/figures/upset.d.ts +60 -0
  109. package/dist/report-render/figures/upset.js +316 -0
  110. package/dist/report-render/figures/volcano.d.ts +25 -0
  111. package/dist/report-render/figures/volcano.js +166 -0
  112. package/dist/report-render/hybrid-svg.d.ts +75 -0
  113. package/dist/report-render/hybrid-svg.js +504 -0
  114. package/dist/report-render/number-format.d.ts +19 -0
  115. package/dist/report-render/number-format.js +25 -1
  116. package/dist/report-render/page.d.ts +41 -4
  117. package/dist/report-render/page.js +247 -12
  118. package/dist/report-render/render.d.ts +13 -4
  119. package/dist/report-render/render.js +37 -6
  120. package/dist/report-render/types.d.ts +23 -2
  121. package/dist/report-render/value-bridge.d.ts +38 -3
  122. package/dist/report-render/value-bridge.js +137 -6
  123. package/dist/report-render/views/chart-view.d.ts +42 -6
  124. package/dist/report-render/views/chart-view.js +70 -9
  125. package/dist/report-render/views/page-view.js +9 -10
  126. package/dist/runtime/assemble.js +2 -2
  127. package/dist/sandbox/client.d.ts +23 -32
  128. package/dist/sandbox/client.js +3 -11
  129. package/dist/sandbox/create-sandbox.d.ts +9 -24
  130. package/dist/sandbox/create-sandbox.js +15 -30
  131. package/dist/sandbox/docker-client.d.ts +12 -22
  132. package/dist/sandbox/docker-client.js +29 -43
  133. package/dist/sandbox/exec.d.ts +58 -0
  134. package/dist/sandbox/exec.js +197 -0
  135. package/dist/sandbox/identity.d.ts +5 -5
  136. package/dist/sandbox/identity.js +7 -10
  137. package/dist/sandbox/k8s-client.d.ts +4 -10
  138. package/dist/sandbox/k8s-client.js +5 -12
  139. package/dist/sandbox/liveness.d.ts +5 -12
  140. package/dist/sandbox/liveness.js +5 -12
  141. package/dist/sandbox/notification-sweep.d.ts +4 -7
  142. package/dist/sandbox/notification-sweep.js +4 -7
  143. package/dist/sandbox/reaper.d.ts +3 -3
  144. package/dist/sandbox/reaper.js +3 -3
  145. package/dist/sandbox/sandbox-error.d.ts +10 -11
  146. package/dist/sandbox/sandbox-error.js +10 -11
  147. package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
  148. package/dist/sandbox/sandbox-step-translate.js +1 -1
  149. package/dist/sandbox/types.d.ts +31 -99
  150. package/dist/sandbox/types.js +17 -84
  151. package/dist/state/active-sandboxes.d.ts +7 -32
  152. package/dist/state/active-sandboxes.js +11 -46
  153. package/dist/state/index.d.ts +1 -2
  154. package/dist/state/index.js +1 -1
  155. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.d.ts +7 -0
  156. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.js +12 -0
  157. package/dist/state/migrations/index.js +2 -0
  158. package/dist/state/schema.d.ts +1 -5
  159. package/dist/state/schema.js +1 -6
  160. package/dist/state/step-executions.js +1 -2
  161. package/dist/tasks/data-profile.js +7 -20
  162. package/dist/tasks/derive-table-exec.d.ts +4 -14
  163. package/dist/tasks/derive-table-exec.js +9 -24
  164. package/dist/tasks/extract-values.d.ts +2 -2
  165. package/dist/tasks/extract-values.js +4 -7
  166. package/dist/tools/bio/index.d.ts +2 -0
  167. package/dist/tools/bio/index.js +3 -0
  168. package/dist/tools/bio/keys.d.ts +11 -0
  169. package/dist/tools/bio/keys.js +15 -0
  170. package/dist/tools/bio/search-clinical-trials.d.ts +1 -1
  171. package/dist/tools/bio/search-patents.d.ts +46 -0
  172. package/dist/tools/bio/search-patents.js +134 -0
  173. package/dist/tools/bio/search-regulatory-approvals.d.ts +49 -0
  174. package/dist/tools/bio/search-regulatory-approvals.js +158 -0
  175. package/dist/tools/define-tool.d.ts +56 -13
  176. package/dist/tools/define-tool.js +28 -1
  177. package/dist/tools/execute-analysis.js +3 -3
  178. package/dist/tools/lib/amass-client.d.ts +586 -0
  179. package/dist/tools/lib/amass-client.js +492 -0
  180. package/dist/tools/lib/amass-config.d.ts +2 -0
  181. package/dist/tools/lib/amass-config.js +10 -0
  182. package/dist/tools/report-session/derive-table.d.ts +8 -9
  183. package/dist/tools/report-session/derive-table.js +3 -4
  184. package/dist/tools/report-session/preview-report.js +4 -49
  185. package/dist/tools/sandbox/list-available-packages.d.ts +1 -1
  186. package/dist/tools/sandbox/list-available-packages.js +5 -4
  187. package/dist/tools/workspace/edit-file.d.ts +5 -4
  188. package/dist/tools/workspace/edit-file.js +10 -13
  189. package/dist/tools/workspace/execute-command.d.ts +27 -42
  190. package/dist/tools/workspace/execute-command.js +42 -38
  191. package/dist/tools/workspace/index.d.ts +5 -6
  192. package/dist/tools/workspace/index.js +5 -6
  193. package/dist/tools/workspace/mutator.d.ts +43 -8
  194. package/dist/tools/workspace/mutator.js +45 -34
  195. package/dist/tools/workspace/run-exec.d.ts +3 -12
  196. package/dist/tools/workspace/run-exec.js +7 -24
  197. package/dist/tools/workspace/scan-inputs.d.ts +0 -3
  198. package/dist/tools/workspace/scan-inputs.js +0 -1
  199. package/dist/tools/workspace/write-file.d.ts +12 -3
  200. package/dist/tools/workspace/write-file.js +17 -13
  201. package/dist/workflows/sandbox-step.d.ts +7 -11
  202. package/dist/workflows/sandbox-step.js +24 -27
  203. package/package.json +3 -1
  204. package/dist/sandbox/await-exec.d.ts +0 -143
  205. package/dist/sandbox/await-exec.js +0 -417
  206. package/dist/sandbox/deliver-exec-event.d.ts +0 -25
  207. package/dist/sandbox/deliver-exec-event.js +0 -29
  208. package/dist/sandbox/digest.d.ts +0 -14
  209. package/dist/sandbox/digest.js +0 -17
  210. package/dist/sandbox/exec-id.d.ts +0 -12
  211. package/dist/sandbox/exec-id.js +0 -20
  212. package/dist/sandbox/hmac.d.ts +0 -62
  213. package/dist/sandbox/hmac.js +0 -72
  214. package/dist/sandbox/submit-exec.d.ts +0 -38
  215. package/dist/sandbox/submit-exec.js +0 -80
  216. package/dist/sandbox/watchdog.d.ts +0 -71
  217. package/dist/sandbox/watchdog.js +0 -161
@@ -0,0 +1,492 @@
1
+ /**
2
+ * Pure async client functions for the Amass Data Platform API: RegulatoryCore
3
+ * (the FDA and EMA authorizations, with the parsed sections of their labels,
4
+ * reviews, SmPCs and EPARs) and PatentCore (patents).
5
+ *
6
+ * The schemas mirror the published OpenAPI document
7
+ * (`https://api.amass.tech/api/doc/openapi.json`). A live key verified them on
8
+ * 2026-09-30, and the golden fixtures under `__fixtures__/amass/` hold those
9
+ * answers.
10
+ *
11
+ * Absence policy: a base field is always present, and an absent value is an
12
+ * explicit `null` (`therapeuticIndication`, `grantDate`). A field that only an
13
+ * `include` parameter adds (`fdaDetails`, `emaDetails`, `claims`,
14
+ * `description`) is an omitted key when the request does not ask for it. Thus
15
+ * a base field carries `.nullable()`, and an include field carries
16
+ * `.nullable().optional()`. A lookup item omits `amassIds` when it carries
17
+ * `error`, and omits `error` when it carries `amassIds`.
18
+ *
19
+ * A response enum is a plain string here. Amass grows those vocabularies, and
20
+ * one unknown value would otherwise reject a whole search. The input filters
21
+ * of the tools carry the enums of the OpenAPI document.
22
+ *
23
+ * Status policy: only a 404 and a lookup item with `NOT_FOUND` are an absence.
24
+ * `isUnexpectedApiError` reads every 4xx as an absence, which would turn a
25
+ * rejected key (401) or a refused organization (403) into "no such record".
26
+ * Thus this client classifies each status itself.
27
+ *
28
+ * Every call spends credits: a search costs 5 credits for each 20 records of
29
+ * `limit`, and a get, a lookup (whatever its item count) or a 404 costs 1.
30
+ */
31
+ import { err, ok } from "neverthrow";
32
+ import { z } from "zod";
33
+ import { apiFetchValidated, describeApiError } from "./api-utils.js";
34
+ import { AMASS_BASE } from "./amass-config.js";
35
+ /** Render an `AmassError` as a one-line message for the model or for a throw. */
36
+ export function describeAmassError(e) {
37
+ switch (e.type) {
38
+ case "invalid_input":
39
+ return `Amass rejected the request (HTTP ${e.status}): ${e.message}`;
40
+ case "unauthorized":
41
+ return `Amass rejected the API key (HTTP 401): ${e.message}. Make sure that AMASS_API_KEY is correct.`;
42
+ case "forbidden":
43
+ return (`Amass refused the request (HTTP 403): ${e.message}. ` +
44
+ "Make sure that AMASS_API_KEY is correct and that the organization of the key has Amass credits.");
45
+ case "rejected":
46
+ return `Amass answered ${e.code}${e.status === null ? "" : ` (HTTP ${e.status})`}: ${e.message}`;
47
+ case "api":
48
+ return describeApiError(e.error);
49
+ }
50
+ }
51
+ // Every error of Amass has this one shape. A 400 adds `fields`, the reason for
52
+ // each rejected parameter.
53
+ export const AmassErrorEnvelopeSchema = z.object({
54
+ error: z.object({
55
+ status: z.number(),
56
+ code: z.string(),
57
+ message: z.string(),
58
+ fields: z.record(z.string(), z.string()).optional(),
59
+ }),
60
+ });
61
+ /** Read the message of an Amass error body, with the per-field reasons of a 400. */
62
+ function envelopeOf(body) {
63
+ let parsed;
64
+ try {
65
+ parsed = JSON.parse(body);
66
+ }
67
+ catch {
68
+ return { code: null, message: body || "no message" };
69
+ }
70
+ const envelope = AmassErrorEnvelopeSchema.safeParse(parsed);
71
+ if (!envelope.success)
72
+ return { code: null, message: body || "no message" };
73
+ const { code, message, fields } = envelope.data.error;
74
+ const reasons = fields ? Object.entries(fields).map(([field, reason]) => `${field}: ${reason}`) : [];
75
+ return { code, message: reasons.length > 0 ? `${message} (${reasons.join("; ")})` : message };
76
+ }
77
+ /**
78
+ * Classify a failed call. A 404 is the one absence, thus it resolves to `ok(null)`.
79
+ * A 429 that outlived the retries arrives as `exhausted`, never as `http_status`.
80
+ */
81
+ function classify(e) {
82
+ if (e.type !== "http_status")
83
+ return err({ type: "api", error: e });
84
+ if (e.status === 404)
85
+ return ok(null);
86
+ const { code, message } = envelopeOf(e.body);
87
+ if (e.status === 400 || e.status === 422)
88
+ return err({ type: "invalid_input", status: e.status, message });
89
+ if (e.status === 401)
90
+ return err({ type: "unauthorized", message });
91
+ if (e.status === 403)
92
+ return err({ type: "forbidden", message });
93
+ if (e.status >= 400 && e.status < 500)
94
+ return err({ type: "rejected", status: e.status, code: code ?? "UNKNOWN", message });
95
+ return err({ type: "api", error: e });
96
+ }
97
+ function amassFetch(url, schema, headers, body) {
98
+ const options = body === undefined ? { headers } : { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify(body) };
99
+ return apiFetchValidated(url.toString(), schema, options).orElse(classify);
100
+ }
101
+ /** Append each defined value; an array repeats the parameter, which Amass reads as "match any". */
102
+ function urlOf(path, params) {
103
+ const url = new URL(`${AMASS_BASE}${path}`);
104
+ for (const [key, value] of Object.entries(params)) {
105
+ if (value === undefined)
106
+ continue;
107
+ if (Array.isArray(value)) {
108
+ for (const item of value)
109
+ url.searchParams.append(key, item);
110
+ }
111
+ else {
112
+ url.searchParams.append(key, String(value));
113
+ }
114
+ }
115
+ return url;
116
+ }
117
+ // ---------------------------------------------------------------------------
118
+ // Lookup
119
+ // ---------------------------------------------------------------------------
120
+ export const AmassLookupResponseSchema = z.object({
121
+ data: z.array(z.object({
122
+ input: z.record(z.string(), z.string()),
123
+ amassIds: z.array(z.string()).optional(),
124
+ error: z.object({ code: z.string(), message: z.string() }).optional(),
125
+ })),
126
+ });
127
+ /**
128
+ * Resolve external identifiers to Amass IDs in one lookup request. The IDs of every
129
+ * item are merged, in order and without duplicates. An item with `NOT_FOUND`
130
+ * contributes no ID; an item with any other error code rejects the whole lookup.
131
+ */
132
+ function lookup(core, items, headers) {
133
+ return amassFetch(urlOf(`/cores/${core}/records/lookup`, {}), AmassLookupResponseSchema, headers, { items }).andThen((response) => {
134
+ const ids = [];
135
+ for (const item of response?.data ?? []) {
136
+ if (item.error && item.error.code !== "NOT_FOUND") {
137
+ return err({ type: "rejected", status: null, code: item.error.code, message: item.error.message });
138
+ }
139
+ for (const id of item.amassIds ?? []) {
140
+ if (!ids.includes(id))
141
+ ids.push(id);
142
+ }
143
+ }
144
+ return ok(ids);
145
+ });
146
+ }
147
+ // ---------------------------------------------------------------------------
148
+ // Identifier forms
149
+ // ---------------------------------------------------------------------------
150
+ const FDA_APPLICATION_PREFIXES = ["NDA", "BLA", "ANDA"];
151
+ /**
152
+ * The lookup forms of an FDA application number. Amass stores the number with its
153
+ * prefix (`NDA021588`) and answers `NOT_FOUND` for the bare `021588`. A bare number
154
+ * thus goes as all three prefixes, in one request at the price of one.
155
+ */
156
+ export function fdaApplicationForms(input) {
157
+ const compact = input.replace(/[\s-]/g, "").toUpperCase();
158
+ if (/^\d+$/.test(compact))
159
+ return FDA_APPLICATION_PREFIXES.map((prefix) => `${prefix}${compact}`);
160
+ return [compact];
161
+ }
162
+ /**
163
+ * The lookup form of an NDC. Amass stores the two-segment product NDC (`0078-0401`)
164
+ * and answers `NOT_FOUND` for the package NDC (`0078-0401-05`).
165
+ */
166
+ export function productNdcOf(input) {
167
+ const trimmed = input.trim();
168
+ const segments = trimmed.split("-");
169
+ return segments.length === 3 && segments.every((segment) => /^\d+$/.test(segment)) ? `${segments[0]}-${segments[1]}` : trimmed;
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // RegulatoryCore
173
+ // ---------------------------------------------------------------------------
174
+ export const REGULATORY_AGENCIES = ["FDA", "EMA"];
175
+ export const REGULATORY_MOLECULE_TYPES = [
176
+ "SMALL_MOLECULE",
177
+ "ANTIBODY",
178
+ "PROTEIN",
179
+ "ENZYME",
180
+ "OLIGONUCLEOTIDE",
181
+ "GENE",
182
+ "CELL",
183
+ "ANTIBODY_DRUG_CONJUGATE",
184
+ "VACCINE_COMPONENT",
185
+ "VACCINE",
186
+ "OLIGOSACCHARIDE",
187
+ "UNKNOWN",
188
+ ];
189
+ export const REGULATORY_AUTHORIZATION_STATUSES = [
190
+ "ACTIVE",
191
+ "APPROVED_NOT_MARKETED",
192
+ "CONDITIONAL",
193
+ "SUSPENDED",
194
+ "WITHDRAWN_VOLUNTARY",
195
+ "WITHDRAWN_FORCED",
196
+ "REVOKED",
197
+ "LAPSED_SUNSET",
198
+ "REFUSED",
199
+ "WITHDRAWN_DURING_REVIEW",
200
+ "EXPIRED",
201
+ "UNKNOWN",
202
+ ];
203
+ export const REGULATORY_DESIGNATIONS = [
204
+ "PRIORITY_REVIEW",
205
+ "BREAKTHROUGH_THERAPY",
206
+ "FAST_TRACK",
207
+ "RMAT",
208
+ "ACCELERATED_APPROVAL",
209
+ "ACCELERATED_ASSESSMENT",
210
+ "PRIME",
211
+ "CONDITIONAL_MA",
212
+ "EXCEPTIONAL_CIRCUMSTANCES",
213
+ ];
214
+ const DocumentSectionSchema = z.object({
215
+ documentSectionId: z.string(),
216
+ amassId: z.string(),
217
+ docType: z.string(),
218
+ path: z.string().nullable(),
219
+ title: z.string().nullable(),
220
+ textType: z.string().nullable(),
221
+ sourceUrl: z.string().nullable(),
222
+ sourceDate: z.string().nullable(),
223
+ });
224
+ const MatchedSectionSchema = DocumentSectionSchema.extend({ matchedText: z.string().nullable() });
225
+ const DesignationSchema = z.object({
226
+ axis: z.string(),
227
+ type: z.string(),
228
+ agency: z.string(),
229
+ nativeName: z.string().nullable(),
230
+ basis: z.string().nullable(),
231
+ indication: z.string().nullable(),
232
+ postMarketingObligation: z.boolean().nullable(),
233
+ });
234
+ const OtherAuthorizationSchema = z.object({
235
+ amassId: z.string(),
236
+ agency: z.string(),
237
+ name: z.string().nullable(),
238
+ authorizationStatus: z.string().nullable(),
239
+ });
240
+ const FdaDetailsSchema = z.object({
241
+ applicationNumber: z.string().nullable(),
242
+ prescriptionClass: z.string().nullable(),
243
+ submissionClassCode: z.string().nullable(),
244
+ labelDate: z.string().nullable(),
245
+ labelUrl: z.string().nullable(),
246
+ ndc: z.array(z.string()),
247
+ splSetId: z.array(z.string()),
248
+ withdrawalDate: z.string().nullable(),
249
+ withdrawalReason: z.string().nullable(),
250
+ withdrawalSourceUrl: z.string().nullable(),
251
+ });
252
+ const EmaDetailsSchema = z.object({
253
+ productNumber: z.string().nullable(),
254
+ category: z.string().nullable(),
255
+ opinionStatus: z.string().nullable(),
256
+ isBiosimilar: z.boolean().nullable(),
257
+ isAdvancedTherapy: z.boolean().nullable(),
258
+ isGenericOrHybrid: z.boolean().nullable(),
259
+ additionalMonitoring: z.boolean().nullable(),
260
+ pharmacotherapeuticGroup: z.string().nullable(),
261
+ patientSafety: z.string().nullable(),
262
+ latestProcedure: z.string().nullable(),
263
+ revisionNumber: z.number().nullable(),
264
+ smpcUrl: z.string().nullable(),
265
+ smpcDate: z.string().nullable(),
266
+ opinionAdoptedDate: z.string().nullable(),
267
+ europeanCommissionDecisionDate: z.string().nullable(),
268
+ withdrawalOfApplicationDate: z.string().nullable(),
269
+ refusalOfMarketingAuthorisationDate: z.string().nullable(),
270
+ withdrawalExpiryRevocationLapseDate: z.string().nullable(),
271
+ firstPublishedDate: z.string().nullable(),
272
+ });
273
+ const RegulatoryBaseSchema = z.object({
274
+ amassId: z.string(),
275
+ agency: z.string(),
276
+ name: z.string().nullable(),
277
+ activeSubstance: z.string().nullable(),
278
+ moleculeType: z.string().nullable(),
279
+ authorizationStatus: z.string().nullable(),
280
+ procedureType: z.string().nullable(),
281
+ therapeuticIndication: z.string().nullable(),
282
+ marketingAuthorisationHolder: z.string().nullable(),
283
+ authorizationDate: z.string().nullable(),
284
+ firstAuthorizationDate: z.string().nullable(),
285
+ sourceUrl: z.string().nullable(),
286
+ isOrphan: z.boolean().nullable(),
287
+ designations: z.array(DesignationSchema),
288
+ authorizationsByAgency: z.array(OtherAuthorizationSchema),
289
+ fdaDetails: FdaDetailsSchema.nullable().optional(),
290
+ emaDetails: EmaDetailsSchema.nullable().optional(),
291
+ });
292
+ export const RegulatorySearchResponseSchema = z.object({
293
+ data: z.array(RegulatoryBaseSchema.extend({ documentSections: z.array(MatchedSectionSchema) })),
294
+ });
295
+ export const RegulatoryRecordResponseSchema = z.object({
296
+ data: RegulatoryBaseSchema.extend({ documentSections: z.array(DocumentSectionSchema) }),
297
+ });
298
+ export const RegulatorySectionResponseSchema = z.object({
299
+ data: DocumentSectionSchema.extend({ content: z.string().nullable() }),
300
+ });
301
+ /**
302
+ * Group sections by their source document, in the order of first appearance. An
303
+ * FDA label has a hundred sections or more, and each raw entry repeats the record
304
+ * ID, the PDF URL and the revision date; the group states the last two once.
305
+ */
306
+ function groupSections(sections, entryOf) {
307
+ const groups = new Map();
308
+ for (const section of sections) {
309
+ const key = `${section.docType}\u0000${section.sourceUrl ?? ""}\u0000${section.sourceDate ?? ""}`;
310
+ let group = groups.get(key);
311
+ if (!group) {
312
+ group = { docType: section.docType, sourceUrl: section.sourceUrl, sourceDate: section.sourceDate, sections: [] };
313
+ groups.set(key, group);
314
+ }
315
+ group.sections.push(entryOf(section));
316
+ }
317
+ return [...groups.values()];
318
+ }
319
+ function summaryOf(record) {
320
+ return {
321
+ amassId: record.amassId,
322
+ agency: record.agency,
323
+ name: record.name,
324
+ activeSubstance: record.activeSubstance,
325
+ moleculeType: record.moleculeType,
326
+ authorizationStatus: record.authorizationStatus,
327
+ procedureType: record.procedureType,
328
+ therapeuticIndication: record.therapeuticIndication,
329
+ marketingAuthorisationHolder: record.marketingAuthorisationHolder,
330
+ authorizationDate: record.authorizationDate,
331
+ firstAuthorizationDate: record.firstAuthorizationDate,
332
+ isOrphan: record.isOrphan,
333
+ designations: record.designations,
334
+ otherAuthorizations: record.authorizationsByAgency,
335
+ sourceUrl: record.sourceUrl,
336
+ };
337
+ }
338
+ /** The matched sections that a search row keeps. The count still reports all of them. */
339
+ export const MAX_MATCHED_SECTIONS = 5;
340
+ export function mapRegulatorySearchRow(record) {
341
+ return {
342
+ ...summaryOf(record),
343
+ matchedSectionCount: record.documentSections.length,
344
+ matchedDocuments: groupSections(record.documentSections.slice(0, MAX_MATCHED_SECTIONS), (section) => ({
345
+ documentSectionId: section.documentSectionId,
346
+ path: section.path,
347
+ title: section.title,
348
+ matchedText: section.matchedText,
349
+ })),
350
+ };
351
+ }
352
+ export function mapRegulatoryRecord(record) {
353
+ return {
354
+ ...summaryOf(record),
355
+ fdaDetails: record.fdaDetails ?? null,
356
+ emaDetails: record.emaDetails ?? null,
357
+ sectionCount: record.documentSections.length,
358
+ documents: groupSections(record.documentSections, (section) => ({
359
+ documentSectionId: section.documentSectionId,
360
+ path: section.path,
361
+ title: section.title,
362
+ })),
363
+ };
364
+ }
365
+ export function searchRegulatoryRecords(params, headers) {
366
+ const url = urlOf("/cores/regulatorycore/records", { ...params });
367
+ return amassFetch(url, RegulatorySearchResponseSchema, headers).map((response) => (response?.data ?? []).map(mapRegulatorySearchRow));
368
+ }
369
+ /** One authorization with its table of contents, or `null` when Amass holds no such ID. */
370
+ export function getRegulatoryRecord(amassId, headers) {
371
+ const url = urlOf(`/cores/regulatorycore/records/${encodeURIComponent(amassId)}`, { include: ["fdaDetails", "emaDetails"] });
372
+ return amassFetch(url, RegulatoryRecordResponseSchema, headers).map((response) => (response ? mapRegulatoryRecord(response.data) : null));
373
+ }
374
+ /** The full text of one document section, or `null` when Amass holds no such section. */
375
+ export function getRegulatorySection(amassId, documentSectionId, headers) {
376
+ const url = urlOf(`/cores/regulatorycore/records/${encodeURIComponent(amassId)}/document-sections/${encodeURIComponent(documentSectionId)}`, {});
377
+ return amassFetch(url, RegulatorySectionResponseSchema, headers).map((response) => {
378
+ if (!response)
379
+ return null;
380
+ const { textType: _textType, ...section } = response.data;
381
+ return section;
382
+ });
383
+ }
384
+ export function regulatoryLookupItems(id) {
385
+ if (id.fdaApplicationNumber !== undefined)
386
+ return fdaApplicationForms(id.fdaApplicationNumber).map((form) => ({ fdaApplicationNumber: form }));
387
+ if (id.ndc !== undefined)
388
+ return [{ ndc: productNdcOf(id.ndc) }];
389
+ if (id.emaProductNumber !== undefined)
390
+ return [{ emaProductNumber: id.emaProductNumber.trim() }];
391
+ if (id.splSetId !== undefined)
392
+ return [{ splSetId: id.splSetId.trim() }];
393
+ return [];
394
+ }
395
+ export function lookupRegulatoryIds(id, headers) {
396
+ return lookup("regulatorycore", regulatoryLookupItems(id), headers);
397
+ }
398
+ // ---------------------------------------------------------------------------
399
+ // PatentCore
400
+ // ---------------------------------------------------------------------------
401
+ const PatentBaseSchema = z.object({
402
+ amassId: z.string(),
403
+ publicationNumber: z.string().nullable(),
404
+ url: z.string().nullable(),
405
+ applicationNumber: z.string().nullable(),
406
+ countryCode: z.string().nullable(),
407
+ kindCode: z.string().nullable(),
408
+ familyId: z.string().nullable(),
409
+ familyMembers: z.array(z.string()),
410
+ title: z.string().nullable(),
411
+ abstract: z.string().nullable(),
412
+ language: z.string().nullable(),
413
+ nonEnglishFallback: z.boolean().nullable(),
414
+ cpcCodes: z.array(z.string()),
415
+ inventors: z.array(z.string()),
416
+ assignees: z.array(z.string()),
417
+ publicationDate: z.string().nullable(),
418
+ filingDate: z.string().nullable(),
419
+ grantDate: z.string().nullable(),
420
+ priorityDate: z.string().nullable(),
421
+ citedPatents: z.array(z.string()),
422
+ hasClaims: z.boolean().nullable(),
423
+ hasDescription: z.boolean().nullable(),
424
+ nplCount: z.number().nullable(),
425
+ citedByCount: z.number().nullable(),
426
+ claims: z.string().nullable().optional(),
427
+ description: z.string().nullable().optional(),
428
+ });
429
+ export const PatentSearchResponseSchema = z.object({ data: z.array(PatentBaseSchema) });
430
+ export const PatentRecordResponseSchema = z.object({ data: PatentBaseSchema });
431
+ export function mapPatentSummary(record) {
432
+ return {
433
+ amassId: record.amassId,
434
+ publicationNumber: record.publicationNumber,
435
+ applicationNumber: record.applicationNumber,
436
+ countryCode: record.countryCode,
437
+ kindCode: record.kindCode,
438
+ familyId: record.familyId,
439
+ familyMemberCount: record.familyMembers.length,
440
+ title: record.title,
441
+ abstract: record.abstract,
442
+ assignees: record.assignees,
443
+ inventors: record.inventors,
444
+ cpcCodes: record.cpcCodes,
445
+ publicationDate: record.publicationDate,
446
+ filingDate: record.filingDate,
447
+ grantDate: record.grantDate,
448
+ priorityDate: record.priorityDate,
449
+ citedPatentCount: record.citedPatents.length,
450
+ citedByCount: record.citedByCount,
451
+ nplCount: record.nplCount,
452
+ hasClaims: record.hasClaims,
453
+ hasDescription: record.hasDescription,
454
+ url: record.url,
455
+ };
456
+ }
457
+ export function mapPatentRecord(record) {
458
+ return {
459
+ ...mapPatentSummary(record),
460
+ familyMembers: record.familyMembers,
461
+ language: record.language,
462
+ nonEnglishFallback: record.nonEnglishFallback,
463
+ ...(record.claims === undefined ? {} : { claims: record.claims }),
464
+ ...(record.description === undefined ? {} : { description: record.description }),
465
+ };
466
+ }
467
+ /** PatentCore reads a list filter as one comma-separated value, not as a repeated parameter. */
468
+ function commaList(values) {
469
+ return values && values.length > 0 ? values.join(",") : undefined;
470
+ }
471
+ export function searchPatentRecords(params, headers) {
472
+ const url = urlOf("/cores/patentcore/records", {
473
+ ...params,
474
+ assignee: commaList(params.assignee),
475
+ cpcCodes: commaList(params.cpcCodes),
476
+ countryCode: commaList(params.countryCode),
477
+ });
478
+ return amassFetch(url, PatentSearchResponseSchema, headers).map((response) => (response?.data ?? []).map(mapPatentSummary));
479
+ }
480
+ export function getPatentRecord(amassId, include, headers) {
481
+ const includes = [...(include.claims ? ["claims"] : []), ...(include.description ? ["description"] : [])];
482
+ const url = urlOf(`/cores/patentcore/records/${encodeURIComponent(amassId)}`, { include: includes });
483
+ return amassFetch(url, PatentRecordResponseSchema, headers).map((response) => (response ? mapPatentRecord(response.data) : null));
484
+ }
485
+ export function lookupPatentIds(id, headers) {
486
+ const items = id.publicationNumber !== undefined
487
+ ? [{ publicationNumber: id.publicationNumber.trim() }]
488
+ : id.applicationNumber !== undefined
489
+ ? [{ applicationNumber: id.applicationNumber.trim() }]
490
+ : [];
491
+ return lookup("patentcore", items, headers);
492
+ }
@@ -0,0 +1,2 @@
1
+ export declare const AMASS_BASE = "https://api.amass.tech/api/v1";
2
+ export declare function getAmassHeaders(apiKey: string): Record<string, string>;
@@ -0,0 +1,10 @@
1
+ export const AMASS_BASE = "https://api.amass.tech/api/v1";
2
+ export function getAmassHeaders(apiKey) {
3
+ if (!apiKey) {
4
+ throw new Error("AMASS_API_KEY environment variable is not set. " + "Obtain a key from https://platform.amass.tech/api-keys");
5
+ }
6
+ return {
7
+ Authorization: `Bearer ${apiKey}`,
8
+ Accept: "application/json",
9
+ };
10
+ }
@@ -29,9 +29,9 @@
29
29
  * condition one time, up front, the same discipline as the eyes. A per-attempt failure would instead read as
30
30
  * a transient fault, and it would invite a repeat of a call that can never pass.
31
31
  *
32
- * The container runs behind a seam, and never in the turn. An await of an exec is a workflow-body call
33
- * under the callback transport, and a report turn is not a body. Thus the tool takes an injected runner,
34
- * and a registered workflow owns the container. The tool holds no sandbox client, and it imports no DBOS.
32
+ * The container runs behind a seam, and never in the turn. An exec is a durable step of a workflow, and a
33
+ * report turn is not a workflow. Thus the tool takes an injected runner, and a registered workflow owns the
34
+ * container. The tool holds no sandbox client, and it imports no DBOS.
35
35
  */
36
36
  import { type Result } from "neverthrow";
37
37
  import { z } from "zod";
@@ -40,7 +40,7 @@ import type { Suspension } from "../../workflows/suspension.js";
40
40
  import type { RunAuthorizer } from "../../execution/run-authorizer.js";
41
41
  import { type Logger } from "../../lib/logger.js";
42
42
  import type { ResourceSpec } from "../../config/resource-limits.js";
43
- import type { ExecResult, SubmitExecBody } from "../../sandbox/types.js";
43
+ import type { ExecRequest, ExecResult } from "../../sandbox/types.js";
44
44
  import type { DerivationSource, ReportSessionStateStore } from "../../state/report-session-state.js";
45
45
  import { type ResolveWorkspaceRoot } from "../../workspace/paths.js";
46
46
  import { type Tool } from "../define-tool.js";
@@ -156,11 +156,10 @@ export interface DerivationInputMount {
156
156
  */
157
157
  export declare function buildDerivationExec(args: {
158
158
  readonly script: string;
159
- readonly execId: string;
160
159
  readonly workingDir: string;
161
160
  readonly inputs: readonly DerivationInputMount[];
162
161
  readonly output: string;
163
- }): SubmitExecBody;
162
+ }): ExecRequest;
164
163
  /**
165
164
  * Give the failure of an exec result, or `undefined` when the script ran to a clean exit.
166
165
  *
@@ -190,9 +189,9 @@ export interface DeriveTableExecInput {
190
189
  /**
191
190
  * Run one derivation exec and give the terminal result back.
192
191
  *
193
- * The composition realizes it over a registered workflow, thus the container lives inside a workflow body
194
- * and the await is legal under each transport. A fault of the sandbox rejects the promise, and the tool
195
- * turns that rejection into one short detail.
192
+ * The composition realizes it over a registered workflow, thus the container and its exec live inside a
193
+ * workflow. A fault of the sandbox rejects the promise, and the tool turns that rejection into one short
194
+ * detail.
196
195
  */
197
196
  export type DeriveTableRunner = (input: DeriveTableExecInput) => Promise<Result<ExecResult, Suspension>>;
198
197
  /**
@@ -29,9 +29,9 @@
29
29
  * condition one time, up front, the same discipline as the eyes. A per-attempt failure would instead read as
30
30
  * a transient fault, and it would invite a repeat of a call that can never pass.
31
31
  *
32
- * The container runs behind a seam, and never in the turn. An await of an exec is a workflow-body call
33
- * under the callback transport, and a report turn is not a body. Thus the tool takes an injected runner,
34
- * and a registered workflow owns the container. The tool holds no sandbox client, and it imports no DBOS.
32
+ * The container runs behind a seam, and never in the turn. An exec is a durable step of a workflow, and a
33
+ * report turn is not a workflow. Thus the tool takes an injected runner, and a registered workflow owns the
34
+ * container. The tool holds no sandbox client, and it imports no DBOS.
35
35
  */
36
36
  import { ok } from "neverthrow";
37
37
  import { unlink } from "node:fs/promises";
@@ -90,7 +90,6 @@ const NO_SANDBOX_DETAIL = "the composition gives no sandbox, thus this session c
90
90
  export function buildDerivationExec(args) {
91
91
  return {
92
92
  command: ["python3", "-c", args.script],
93
- execId: args.execId,
94
93
  cwd: args.workingDir,
95
94
  env: {
96
95
  [DERIVE_INPUT_ENV]: JSON.stringify(args.inputs.map((input) => ({ path: input.path, hash: input.hash }))),
@@ -52,7 +52,7 @@ import { referencedPaths, walkBlocks } from "../../report-model/block-walk.js";
52
52
  import { computeDraftHash } from "../../report-model/draft-hash.js";
53
53
  import { finishDraft } from "../../report-model/draft-finish.js";
54
54
  import { resolveDocumentReferences } from "../../report-model/validate.js";
55
- import { bridgeValues } from "../../report-render/value-bridge.js";
55
+ import { bridgeValues, collectResolutions } from "../../report-render/value-bridge.js";
56
56
  import { resolvePageAssetFromInstallation } from "../../report-render/asset-lookup.js";
57
57
  import { ASSETS_DIR, DEPS_DIR, derivationScriptName, PAGE_ASSETS, stagedSource, tableSidecarName } from "../../report-render/assets.js";
58
58
  import { renderReportPage } from "../../report-render/render.js";
@@ -77,51 +77,6 @@ function assetFileName(file) {
77
77
  function figureSourcePolicy(file) {
78
78
  return `assets/${assetFileName(file)}`;
79
79
  }
80
- /**
81
- * Pair each block with the resolved value of its binding, in document order.
82
- *
83
- * A value-bearing kind carries the resolved value of its one reference, looked up by the block id from
84
- * the map that the resolution pass filled. A no-value kind carries none. Where a reference sits in a
85
- * block is the knowledge of `block-walk.ts`, thus this walk reads the block id alone and never a binding
86
- * field.
87
- *
88
- * The switch is exhaustive over the eight block kinds. A ninth kind reaches the end with no return, and
89
- * the declared return type fails the build. Thus the walk cannot drop a kind in silence. A value-bearing
90
- * block reaches here only when its reference resolved, because an unresolved reference short-circuits
91
- * before this walk.
92
- */
93
- function collectResolutions(blocks, resolvedByBlock) {
94
- const resolutions = [];
95
- const visit = (block) => {
96
- switch (block.kind) {
97
- case "section":
98
- resolutions.push({ blockId: block.id, kind: "section" });
99
- for (const child of block.blocks) {
100
- visit(child);
101
- }
102
- return;
103
- case "text":
104
- case "claim":
105
- case "citation":
106
- resolutions.push({ blockId: block.id, kind: block.kind });
107
- return;
108
- case "metric":
109
- case "table":
110
- case "chart":
111
- case "figure": {
112
- const resolved = resolvedByBlock.get(block.id);
113
- if (resolved !== undefined) {
114
- resolutions.push({ blockId: block.id, kind: block.kind, resolved });
115
- }
116
- return;
117
- }
118
- }
119
- };
120
- for (const block of blocks) {
121
- visit(block);
122
- }
123
- return resolutions;
124
- }
125
80
  /**
126
81
  * The sidecar of each table block of the document, in document order.
127
82
  *
@@ -201,11 +156,11 @@ function scriptAssets(records) {
201
156
  * references. On a clean pass the resolutions map onto the render model in document order.
202
157
  */
203
158
  async function resolveDocument(document, resolver, snapshot) {
204
- const { resolvedByBlock, failures } = await resolveDocumentReferences(document.sections, snapshot, resolver);
159
+ const { resolvedByBlock, resolvedBySlot, failures } = await resolveDocumentReferences(document.sections, snapshot, resolver);
205
160
  if (failures.length > 0) {
206
161
  return { resolutions: [], unresolved: failures };
207
162
  }
208
- return { resolutions: collectResolutions(document.sections, resolvedByBlock), unresolved: [] };
163
+ return { resolutions: collectResolutions(document.sections, resolvedByBlock, resolvedBySlot), unresolved: [] };
209
164
  }
210
165
  /**
211
166
  * Resolve the page root, stage each bound image and each manifest entry, and write the page.
@@ -456,7 +411,7 @@ export function createPreviewReportTool(deps) {
456
411
  // the renderer moves it into a data asset and no part of this path reads a field of it. Absence
457
412
  // gives a page with no provenance asset, and each other part of the render is unchanged.
458
413
  const provenance = await readProvenance(analysisId);
459
- const rendered = renderReportPage(document, bridged.value, {
414
+ const rendered = await renderReportPage(document, bridged.value, {
460
415
  records: snapshot.citationRecords,
461
416
  derivations: used.map((record) => chainOf(record, sessionDir)),
462
417
  provenance,
@@ -140,7 +140,7 @@ export type InventoryRead = {
140
140
  * here, thus the census a model sees and the check a launch runs never
141
141
  * disagree about what the source holds.
142
142
  */
143
- export declare function readInventorySections(deps: ListAvailablePackagesDeps): Promise<InventoryRead>;
143
+ export declare function readInventorySections(deps: ListAvailablePackagesDeps, analysisId: string): Promise<InventoryRead>;
144
144
  /**
145
145
  * Create the package inventory over the bound source: the pool-scope reader
146
146
  * when the embedder binds one (a conversation or planning surface), the