@inflexa-ai/harness 0.48.1 → 0.48.2
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/contracts/chat-events.d.ts +40 -0
- package/dist/contracts/chat-frame.js +11 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/message.d.ts +7 -1
- package/dist/contracts/schemas/chat-events.d.ts +319 -0
- package/dist/contracts/schemas/chat-events.js +29 -0
- package/dist/execution/run-synthesis.js +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/input-sanitization.d.ts +30 -2
- package/dist/input-sanitization.js +187 -2
- package/dist/loop/run-loop.js +50 -5
- package/dist/loop/tool-adapter.d.ts +8 -0
- package/dist/loop/tool-adapter.js +75 -4
- package/dist/loop/tool-detail.d.ts +5 -1
- package/dist/loop/tool-detail.js +7 -3
- package/dist/loop/tool-value.d.ts +57 -0
- package/dist/loop/tool-value.js +249 -0
- package/dist/loop/types.d.ts +9 -2
- package/dist/memory/conversation-display-storage.js +4 -1
- package/dist/memory/count-tokens.js +29 -2
- package/dist/sandbox/sandbox-step-translate.d.ts +5 -9
- package/dist/sandbox/sandbox-step-translate.js +5 -9
- package/dist/tasks/data-profile-activity.d.ts +3 -7
- package/dist/tasks/data-profile-activity.js +1 -1
- package/dist/tasks/data-profile.js +3 -6
- package/dist/tools/ad-hoc-router.js +1 -0
- package/dist/tools/bio/alphafold-prediction.js +1 -0
- package/dist/tools/bio/chembl.js +1 -0
- package/dist/tools/bio/comptox.js +1 -0
- package/dist/tools/bio/drug-gene-interactions.js +1 -0
- package/dist/tools/bio/gene-disease-evidence.js +1 -0
- package/dist/tools/bio/gene-preclinical-profile.js +1 -0
- package/dist/tools/bio/lookup-annotation.js +1 -0
- package/dist/tools/bio/opentargets.js +1 -0
- package/dist/tools/bio/pubchem.js +1 -0
- package/dist/tools/bio/pubmed.js +1 -0
- package/dist/tools/bio/search-clinical-trials.js +1 -0
- package/dist/tools/bio/search-faers.js +1 -0
- package/dist/tools/bio/search-gene.js +1 -0
- package/dist/tools/bio/search-geo-datasets.js +1 -0
- package/dist/tools/bio/search-interactions.js +1 -0
- package/dist/tools/bio/search-patents.js +1 -0
- package/dist/tools/bio/search-protein.js +1 -0
- package/dist/tools/bio/search-regulatory-approvals.js +1 -0
- package/dist/tools/bio/target-safety.js +1 -0
- package/dist/tools/capability-data.js +5 -0
- package/dist/tools/define-tool.d.ts +18 -0
- package/dist/tools/define-tool.js +2 -0
- package/dist/tools/display/show-user.js +1 -0
- package/dist/tools/execute-analysis.js +4 -0
- package/dist/tools/knowledge/check.d.ts +47 -1
- package/dist/tools/knowledge/check.js +10 -1
- package/dist/tools/knowledge/client.d.ts +1 -1
- package/dist/tools/knowledge/recommend.js +4 -3
- package/dist/tools/knowledge/situation.d.ts +39 -1
- package/dist/tools/knowledge/situation.js +80 -8
- package/dist/tools/knowledge/skeleton.d.ts +7 -0
- package/dist/tools/knowledge/skeleton.js +88 -2
- package/dist/tools/knowledge/template.js +1 -0
- package/dist/tools/memory/update-working-memory.js +5 -0
- package/dist/tools/read-tool-output.js +4 -0
- package/dist/tools/report-authoring/authoring-tools.js +8 -0
- package/dist/tools/report-session/examine-page.js +5 -0
- package/dist/tools/report-session/list-artifacts.js +5 -0
- package/dist/tools/report-session/preview-report.js +1 -0
- package/dist/tools/report-session/record-version.js +1 -0
- package/dist/tools/report-session/script-tools.js +2 -0
- package/dist/tools/research/context7-docs.js +2 -0
- package/dist/tools/research/generate-analogy-report.js +3 -0
- package/dist/tools/research/generate-plan.js +6 -0
- package/dist/tools/research/inspect-data-profile.js +5 -0
- package/dist/tools/research/inspect-run.js +5 -0
- package/dist/tools/research/resolve-citation.js +1 -0
- package/dist/tools/research/search-arxiv.js +1 -0
- package/dist/tools/research/search-github-repos.js +1 -0
- package/dist/tools/research/search-semantic-scholar.js +1 -0
- package/dist/tools/research/web-fetch.js +1 -0
- package/dist/tools/research/web-search.js +1 -0
- package/dist/tools/sandbox/lease-tools.js +2 -0
- package/dist/tools/sandbox/link-packages.js +1 -0
- package/dist/tools/sandbox/list-available-packages.js +5 -0
- package/dist/tools/sandbox/list-available-refs.js +5 -0
- package/dist/tools/sandbox/report-blocker.js +1 -0
- package/dist/tools/sandbox/skills.js +2 -0
- package/dist/tools/sandbox/submit-file-metadata.js +1 -0
- package/dist/tools/script/file-tools.js +6 -0
- package/dist/tools/script/run-script.js +20 -1
- package/dist/tools/start-report-session.js +1 -0
- package/dist/tools/tool-view.d.ts +63 -0
- package/dist/tools/tool-view.js +68 -0
- package/dist/tools/workspace/edit-file.js +5 -0
- package/dist/tools/workspace/execute-command.js +5 -2
- package/dist/tools/workspace/file-stat.js +5 -0
- package/dist/tools/workspace/grep.js +4 -0
- package/dist/tools/workspace/list-files.js +5 -0
- package/dist/tools/workspace/read-file.js +4 -0
- package/dist/tools/workspace/scan-inputs.js +5 -0
- package/dist/tools/workspace/show-file.js +1 -0
- package/dist/tools/workspace/show-plan.js +1 -0
- package/dist/tools/workspace/workspace-search.js +5 -0
- package/dist/tools/workspace/write-file.js +7 -2
- package/dist/workflows/execute-analysis.js +2 -1
- package/dist/workflows/sandbox-step.js +3 -7
- package/package.json +1 -1
- package/dist/tools/detail-resolver.d.ts +0 -40
- package/dist/tools/detail-resolver.js +0 -44
|
@@ -19,6 +19,13 @@
|
|
|
19
19
|
* one enrichment step on its own track, and one report step. A group with
|
|
20
20
|
* no step in the procedure is absent from the skeleton.
|
|
21
21
|
*
|
|
22
|
+
* A step whose own template reads the output of another template gets its
|
|
23
|
+
* own group, because a fold keeps the template of the central step alone and
|
|
24
|
+
* it would drop the others. Thus the four steps of the dose-response chain
|
|
25
|
+
* (the benchmark dose of each gene, the benchmark dose of each gene set, the
|
|
26
|
+
* point of departure, and the exposure margin) are four groups of one track,
|
|
27
|
+
* in that order, and each of the other four new steps is a group of its own.
|
|
28
|
+
*
|
|
22
29
|
* The central step of a group names the method of the skeleton step, and it
|
|
23
30
|
* gives the alternatives, the template, and the environment: an alternative
|
|
24
31
|
* of a folded step (a normalization in the differential expression group)
|
|
@@ -40,6 +47,21 @@ const GROUPS = [
|
|
|
40
47
|
steps: ["filter_low_counts", "normalize", "model_design", "differential_expression", "shrink_lfc", "multiple_testing"],
|
|
41
48
|
name: "Differential expression",
|
|
42
49
|
},
|
|
50
|
+
// The dose-response chain: each step reads the table that the step before
|
|
51
|
+
// it writes, thus the four are one track in the order of the chain. The
|
|
52
|
+
// track is its own, because the chain is a branch off the test and not a
|
|
53
|
+
// part of the core walk, and it ends in a regulatory quantity.
|
|
54
|
+
{ id: "T4S1", track: "T4", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["dose_response_fit"], name: "Benchmark dose of each gene" },
|
|
55
|
+
{
|
|
56
|
+
id: "T4S2",
|
|
57
|
+
track: "T4",
|
|
58
|
+
step_type: "analysis",
|
|
59
|
+
agent: "bulk-transcriptomics-agent",
|
|
60
|
+
steps: ["benchmark_dose_sets"],
|
|
61
|
+
name: "Benchmark dose of each gene set",
|
|
62
|
+
},
|
|
63
|
+
{ id: "T4S3", track: "T4", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["point_of_departure"], name: "Point of departure" },
|
|
64
|
+
{ id: "T4S4", track: "T4", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["exposure_margin"], name: "Exposure margin" },
|
|
43
65
|
{ id: "T2S1", track: "T2", step_type: "enrichment", agent: "enrichment-agent", steps: ["enrichment"], name: "Gene set enrichment" },
|
|
44
66
|
{
|
|
45
67
|
id: "T2S2",
|
|
@@ -49,12 +71,45 @@ const GROUPS = [
|
|
|
49
71
|
steps: ["tf_activity", "pathway_activity"],
|
|
50
72
|
name: "Regulator and pathway activity",
|
|
51
73
|
},
|
|
74
|
+
// The connectivity reads the contrast of the study against a reference
|
|
75
|
+
// resource, which is the shape and the agent of this track. The resource
|
|
76
|
+
// is a compendium of contrasts and not a gene set collection, thus the
|
|
77
|
+
// step is a group of its own beside the enrichment and the activity.
|
|
78
|
+
{
|
|
79
|
+
id: "T2S3",
|
|
80
|
+
track: "T2",
|
|
81
|
+
step_type: "analysis",
|
|
82
|
+
agent: "enrichment-agent",
|
|
83
|
+
steps: ["compendium_connectivity"],
|
|
84
|
+
name: "Compendium connectivity",
|
|
85
|
+
},
|
|
52
86
|
{ id: "T1S4", track: "T1", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["variance_partition"], name: "Variance partition" },
|
|
53
87
|
{ id: "T3S1", track: "T3", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["signature_scoring"], name: "Signature scoring" },
|
|
54
88
|
{ id: "T3S2", track: "T3", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["deconvolution"], name: "Cell type deconvolution" },
|
|
55
89
|
{ id: "T3S3", track: "T3", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["coexpression"], name: "Co-expression modules" },
|
|
56
90
|
{ id: "T3S4", track: "T3", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["clustering"], name: "Sample clustering" },
|
|
57
91
|
{ id: "T3S5", track: "T3", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["survival"], name: "Outcome association" },
|
|
92
|
+
// Three computations over the value matrix and the sample table, each
|
|
93
|
+
// independent of the others and of the chain, thus each is a group of
|
|
94
|
+
// this track: a class per gene over the time points, a score per sample
|
|
95
|
+
// against a reference module set, and a call per sample.
|
|
96
|
+
{
|
|
97
|
+
id: "T3S6",
|
|
98
|
+
track: "T3",
|
|
99
|
+
step_type: "analysis",
|
|
100
|
+
agent: "bulk-transcriptomics-agent",
|
|
101
|
+
steps: ["trajectory_classification"],
|
|
102
|
+
name: "Trajectory classification",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "T3S7",
|
|
106
|
+
track: "T3",
|
|
107
|
+
step_type: "analysis",
|
|
108
|
+
agent: "bulk-transcriptomics-agent",
|
|
109
|
+
steps: ["reference_module_score"],
|
|
110
|
+
name: "Reference module score",
|
|
111
|
+
},
|
|
112
|
+
{ id: "T3S8", track: "T3", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["classifier_call"], name: "Classifier call" },
|
|
58
113
|
{ id: "T1S5", track: "T1", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["transcript_level"], name: "Transcript-level analysis" },
|
|
59
114
|
{ id: "T1S6", track: "T1", step_type: "analysis", agent: "bulk-transcriptomics-agent", steps: ["annotation"], name: "Identifier annotation" },
|
|
60
115
|
{ id: "T1S3", track: "T1", step_type: "report", agent: "bulk-transcriptomics-agent", steps: ["report"], name: "Report" },
|
|
@@ -63,23 +118,54 @@ const GROUPS = [
|
|
|
63
118
|
* The dependencies of each group. The QC depends on the cohort assembly when
|
|
64
119
|
* one is present, a group depends on the QC, on the differential expression
|
|
65
120
|
* when its input is a results table, and the report depends on every group
|
|
66
|
-
* that is present.
|
|
121
|
+
* that is present. A step of the dose-response chain depends on the step
|
|
122
|
+
* whose table it reads: the fit reads the genes that passed the test, the
|
|
123
|
+
* gene sets read the gene table of the fit, the point of departure reads the
|
|
124
|
+
* set table and the gene table, and the margin reads the point of departure.
|
|
67
125
|
*/
|
|
68
126
|
const DEPENDS = {
|
|
69
127
|
T0S1: [],
|
|
70
128
|
T1S1: ["T0S1"],
|
|
71
129
|
T1S2: ["T1S1"],
|
|
130
|
+
T4S1: ["T1S2"],
|
|
131
|
+
T4S2: ["T4S1"],
|
|
132
|
+
T4S3: ["T4S2", "T4S1"],
|
|
133
|
+
T4S4: ["T4S3"],
|
|
72
134
|
T2S1: ["T1S2"],
|
|
73
135
|
T2S2: ["T1S2", "T1S1"],
|
|
136
|
+
T2S3: ["T1S2"],
|
|
74
137
|
T1S4: ["T1S1"],
|
|
75
138
|
T3S1: ["T1S1"],
|
|
76
139
|
T3S2: ["T1S1"],
|
|
77
140
|
T3S3: ["T1S1"],
|
|
78
141
|
T3S4: ["T1S1"],
|
|
79
142
|
T3S5: ["T3S1", "T1S1"],
|
|
143
|
+
T3S6: ["T1S1"],
|
|
144
|
+
T3S7: ["T1S1"],
|
|
145
|
+
T3S8: ["T1S1"],
|
|
80
146
|
T1S5: ["T1S1"],
|
|
81
147
|
T1S6: ["T1S1"],
|
|
82
|
-
T1S3: [
|
|
148
|
+
T1S3: [
|
|
149
|
+
"T1S2",
|
|
150
|
+
"T4S1",
|
|
151
|
+
"T4S2",
|
|
152
|
+
"T4S3",
|
|
153
|
+
"T4S4",
|
|
154
|
+
"T2S1",
|
|
155
|
+
"T2S2",
|
|
156
|
+
"T2S3",
|
|
157
|
+
"T1S4",
|
|
158
|
+
"T3S1",
|
|
159
|
+
"T3S2",
|
|
160
|
+
"T3S3",
|
|
161
|
+
"T3S4",
|
|
162
|
+
"T3S5",
|
|
163
|
+
"T3S6",
|
|
164
|
+
"T3S7",
|
|
165
|
+
"T3S8",
|
|
166
|
+
"T1S5",
|
|
167
|
+
"T1S6",
|
|
168
|
+
],
|
|
83
169
|
};
|
|
84
170
|
/** A parameter value as a setting: a scalar stays, a list becomes a list of strings, anything else its text. */
|
|
85
171
|
function settingValue(value) {
|
|
@@ -124,6 +124,7 @@ export function createKnowledgeTemplateTool(deps) {
|
|
|
124
124
|
"A change the slots do not cover: use `edit_file` on a line marked `# [adaptable: ...]` in the rendered script, and keep the edit small; the record lists each such edit. " +
|
|
125
125
|
"`match: unavailable` means the service did not answer, and `match: snapshot_mismatch` means the service moved to another release than the plan pinned; in both cases write the script yourself as you would without this tool, and state it in your summary.",
|
|
126
126
|
inputSchema: KnowledgeTemplateInputSchema,
|
|
127
|
+
view: "none",
|
|
127
128
|
describeCall: ({ template }) => template,
|
|
128
129
|
describeResult: (_input, result) => "status" in result ? (result.status === "ok" ? `${result.script_path} (${result.environment_match})` : result.status) : result.match,
|
|
129
130
|
execute: async ({ template, slots, overrides, script_name }, ctx) => {
|
|
@@ -165,6 +165,11 @@ export function createUpdateWorkingMemoryTool(workingMemory, pool, opts = DEFAUL
|
|
|
165
165
|
"user's last message, run contents (tables, gene lists, file paths), or anything you can retrieve " +
|
|
166
166
|
"again with inspect_run, read_file, or search.",
|
|
167
167
|
inputSchema,
|
|
168
|
+
view: {
|
|
169
|
+
input: (input) => input,
|
|
170
|
+
result: (_input, result) => result,
|
|
171
|
+
error: true,
|
|
172
|
+
},
|
|
168
173
|
// Four writes in one turn are four identical chips without this. The
|
|
169
174
|
// entry id rides along on revise/retire because it is the only thing
|
|
170
175
|
// separating two retirements from the same section.
|
|
@@ -122,6 +122,10 @@ export function createReadToolOutputTool(store) {
|
|
|
122
122
|
`${MAX_MATCHES} matches, each with its offset and the text around it. When a result gives \`more: true\`, ` +
|
|
123
123
|
"call again with `offset` set to its `end`.",
|
|
124
124
|
inputSchema: ReadToolOutputInputSchema,
|
|
125
|
+
view: {
|
|
126
|
+
input: (input) => input,
|
|
127
|
+
error: true,
|
|
128
|
+
},
|
|
125
129
|
// The reference alone repeats across the pages of one text, and the pattern is what tells two searches apart.
|
|
126
130
|
describeCall: ({ ref, pattern }) => (pattern === undefined ? ref : `${pattern} in ${ref}`),
|
|
127
131
|
execute: async ({ ref, offset = 0, limit, pattern }, ctx) => {
|
|
@@ -524,6 +524,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
524
524
|
"A reference names the path of a pinned artifact, and the session stamps the hash from the pinned evidence.",
|
|
525
525
|
inputSchema: addBlockInput,
|
|
526
526
|
outputSchema: MutationOutputSchema,
|
|
527
|
+
view: "none",
|
|
527
528
|
describeCall: (input) => {
|
|
528
529
|
const block = decodeBlockPayload(input.block);
|
|
529
530
|
const kind = readKind(block);
|
|
@@ -559,6 +560,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
559
560
|
"A reference names the path of a pinned artifact, and the session stamps the hash from the pinned evidence.",
|
|
560
561
|
inputSchema: changeBlockInput,
|
|
561
562
|
outputSchema: MutationOutputSchema,
|
|
563
|
+
view: "none",
|
|
562
564
|
describeCall: (input) => `change ${input.targetId}`,
|
|
563
565
|
execute: async (input, ctx) => {
|
|
564
566
|
const opening = await openMutation(ctx);
|
|
@@ -582,6 +584,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
582
584
|
description: "Remove one block by its id. A removed section takes its whole subtree with it, and the id is free for a later add.",
|
|
583
585
|
inputSchema: removeBlockInput,
|
|
584
586
|
outputSchema: MutationOutputSchema,
|
|
587
|
+
view: "none",
|
|
585
588
|
describeCall: (input) => `remove ${input.targetId}`,
|
|
586
589
|
execute: async (input, ctx) => {
|
|
587
590
|
const opening = await openMutation(ctx);
|
|
@@ -602,6 +605,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
602
605
|
"A section cannot move into its own subtree.",
|
|
603
606
|
inputSchema: moveBlockInput,
|
|
604
607
|
outputSchema: MutationOutputSchema,
|
|
608
|
+
view: "none",
|
|
605
609
|
describeCall: (input) => `move ${input.targetId}`,
|
|
606
610
|
execute: async (input, ctx) => {
|
|
607
611
|
const opening = await openMutation(ctx);
|
|
@@ -622,6 +626,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
622
626
|
description: "Set the title of the whole report, not the title of a section. A draft starts with no title, and a document needs one.",
|
|
623
627
|
inputSchema: setTitleInput,
|
|
624
628
|
outputSchema: MutationOutputSchema,
|
|
629
|
+
view: "none",
|
|
625
630
|
describeCall: (input) => `title the report ${input.title}`,
|
|
626
631
|
// The title sits on the document, thus no container changes its child order.
|
|
627
632
|
execute: async (input, ctx) => {
|
|
@@ -648,6 +653,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
648
653
|
"and read one block when the label is not enough.",
|
|
649
654
|
inputSchema: readOutlineInput,
|
|
650
655
|
outputSchema: OutlineOutputSchema,
|
|
656
|
+
view: "none",
|
|
651
657
|
// The input carries no field, thus a hook can only restate the name of the tool.
|
|
652
658
|
describeCall: "none",
|
|
653
659
|
execute: async (_input, ctx) => {
|
|
@@ -665,6 +671,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
665
671
|
"because the outline already names every block under it. Use it when the outline label is not enough.",
|
|
666
672
|
inputSchema: readBlockInput,
|
|
667
673
|
outputSchema: ReadBlockOutputSchema,
|
|
674
|
+
view: "none",
|
|
668
675
|
describeCall: (input) => `read ${input.targetId}`,
|
|
669
676
|
execute: async (input, ctx) => {
|
|
670
677
|
const opened = await openThread(ctx);
|
|
@@ -685,6 +692,7 @@ export function createReportAuthoringTools(gateway, deps = {}) {
|
|
|
685
692
|
"preview_report and record_report_version run the same check before they act, thus a finish directly before one of them does that check a second time. " +
|
|
686
693
|
"Use it to make sure that the draft passes the whole document schema, the id rule, and the structural tier.",
|
|
687
694
|
inputSchema: finishDraftInput,
|
|
695
|
+
view: "none",
|
|
688
696
|
// The input carries no field, thus a hook can only restate the name of the tool.
|
|
689
697
|
describeCall: "none",
|
|
690
698
|
execute: async (_input, ctx) => {
|
|
@@ -254,6 +254,11 @@ export function createExaminePageTool(deps) {
|
|
|
254
254
|
"The outcomes no-page and missed-stamp mean that no preview rendered the current page: run preview_report, then look again. " +
|
|
255
255
|
"The outcome no-browser means that this host gives no browser, and a repeat gives the same outcome.",
|
|
256
256
|
inputSchema: examinePageInput,
|
|
257
|
+
view: {
|
|
258
|
+
input: (input) => input,
|
|
259
|
+
result: (_input, result) => result,
|
|
260
|
+
error: true,
|
|
261
|
+
},
|
|
257
262
|
describeCall: (input) => {
|
|
258
263
|
const blockId = input.blockId ?? undefined;
|
|
259
264
|
return blockId === undefined ? "look at the page" : `look at ${blockId}`;
|
|
@@ -148,6 +148,11 @@ export function createListPinnedArtifactsTool(deps) {
|
|
|
148
148
|
"Read the listing to orient before you bind a block. Read the columns of one artifact to choose the column that a locator names. " +
|
|
149
149
|
"A reference names the path alone: the session stamps the hash from this evidence, thus the tool gives no hash.",
|
|
150
150
|
inputSchema: listPinnedArtifactsInput,
|
|
151
|
+
view: {
|
|
152
|
+
input: (input) => input,
|
|
153
|
+
result: (_input, result) => result,
|
|
154
|
+
error: true,
|
|
155
|
+
},
|
|
151
156
|
describeCall: (input) => input.path ?? "the pinned set",
|
|
152
157
|
// The size of the listing is what a watcher reads, and the cap makes that size differ from the
|
|
153
158
|
// pinned set. Thus a truncated listing names the total beside the count, and a whole listing names
|
|
@@ -376,6 +376,7 @@ export function createPreviewReportTool(deps) {
|
|
|
376
376
|
"The render marks the page that examine_page looks at next. " +
|
|
377
377
|
"Use it to see the report, and to confirm that each reference resolves.",
|
|
378
378
|
inputSchema: previewReportInput,
|
|
379
|
+
view: "none",
|
|
379
380
|
describeCall: "none",
|
|
380
381
|
// The page path is the one fact of a preview that a watcher wants, and it exists only in the
|
|
381
382
|
// result. Each other arm is a degraded condition whose kind already names it, thus the kind
|
|
@@ -138,6 +138,7 @@ export function createRecordVersionTool(deps) {
|
|
|
138
138
|
"A thread holds one version, thus a later record replaces it whole. Amend the draft, look at the page again, and record again. " +
|
|
139
139
|
"After the version lands, the tool removes the file of each derived table that no block of the recorded report binds.",
|
|
140
140
|
inputSchema: recordVersionInput,
|
|
141
|
+
view: "none",
|
|
141
142
|
describeCall: "none",
|
|
142
143
|
// The version id is the one durable product of the first record, thus the created arm names it. A
|
|
143
144
|
// later record writes over that same id, thus the line names the update and never reads as a
|
|
@@ -40,6 +40,7 @@ function createReadTableTool(deps) {
|
|
|
40
40
|
"A larger table does not derive; tell the user which table is absent.",
|
|
41
41
|
inputSchema: readTableInput,
|
|
42
42
|
outputSchema: ReadTableOutputSchema,
|
|
43
|
+
view: "none",
|
|
43
44
|
describeCall: ({ path }) => path,
|
|
44
45
|
describeResult: (_input, result) => `${String(result.rowCount)} rows`,
|
|
45
46
|
execute: async ({ path, columns }, ctx) => {
|
|
@@ -100,6 +101,7 @@ function createWriteDerivedTool(deps) {
|
|
|
100
101
|
"Name each pinned table that the script read in `inputs`. A name that this session already holds is refused, thus a second derivation of one table takes a new name.",
|
|
101
102
|
inputSchema: writeDerivedInput,
|
|
102
103
|
outputSchema: DerivedOutputSchema,
|
|
104
|
+
view: "none",
|
|
103
105
|
describeCall: ({ name }) => name,
|
|
104
106
|
describeResult: (_input, result) => result.path,
|
|
105
107
|
execute: async ({ name, rows, inputs }, ctx) => {
|
|
@@ -51,6 +51,7 @@ export const resolveLibraryIdTool = defineTool({
|
|
|
51
51
|
libraryName: z.string().describe("Package or library name to search for (e.g., 'scanpy', 'pysam', 'lifelines')."),
|
|
52
52
|
query: z.string().describe("What you need help with — used to rank results by relevance (e.g., 'how to run differential expression')."),
|
|
53
53
|
}),
|
|
54
|
+
view: "none",
|
|
54
55
|
describeCall: "none",
|
|
55
56
|
execute: async ({ libraryName, query }) => {
|
|
56
57
|
const result = await apiFetchValidated(`${CONTEXT7_BASE}/search?query=${encodeURIComponent(libraryName)}&topic=${encodeURIComponent(query)}`, Context7SearchResponseSchema, { maxRetries: 1 });
|
|
@@ -80,6 +81,7 @@ export const queryDocsTool = defineTool({
|
|
|
80
81
|
libraryId: z.string().describe("Context7 library ID exactly as `resolve_library_id` gave it — an owner and a library, for example '/scverse/scanpy'."),
|
|
81
82
|
query: z.string().describe("Specific question about the library (e.g., 'rank_genes_groups function parameters and usage')."),
|
|
82
83
|
}),
|
|
84
|
+
view: "none",
|
|
83
85
|
describeCall: "none",
|
|
84
86
|
execute: async ({ libraryId, query }) => {
|
|
85
87
|
// The library id is the path of the route, not a query parameter. Each
|
|
@@ -47,6 +47,7 @@ function createRecordProblemTool() {
|
|
|
47
47
|
description: "Record the extraction of phase 1: the problem summary, objects, relations, key terms, and the analogies " +
|
|
48
48
|
"that phase 2 searches. A later call replaces the record.",
|
|
49
49
|
inputSchema: RecordProblemInputSchema,
|
|
50
|
+
view: "none",
|
|
50
51
|
describeCall: "none",
|
|
51
52
|
execute: () => Promise.resolve(ok({ recorded: true })),
|
|
52
53
|
});
|
|
@@ -57,6 +58,7 @@ function createRecordAnalogyTool() {
|
|
|
57
58
|
description: "Record one analogy with its coverage and its cited solutions, when its search is done. A later call " +
|
|
58
59
|
"with the same analogyTitle replaces the record.",
|
|
59
60
|
inputSchema: AnalogySchema,
|
|
61
|
+
view: "none",
|
|
60
62
|
describeCall: ({ analogyTitle }) => analogyTitle,
|
|
61
63
|
execute: () => Promise.resolve(ok({ recorded: true })),
|
|
62
64
|
});
|
|
@@ -268,6 +270,7 @@ export function createGenerateAnalogyReportTool(deps, registerSubAgent) {
|
|
|
268
270
|
"A retry with the same or a similar problem statement meets the same " +
|
|
269
271
|
"failure, thus surface the message and ask the user to narrow the problem.",
|
|
270
272
|
inputSchema: generateAnalogyReportInputSchema,
|
|
273
|
+
view: "none",
|
|
271
274
|
describeCall: "none",
|
|
272
275
|
startsWorkflow: true,
|
|
273
276
|
execute: async (input, ctx) => ok(await research(input, ctx)),
|
|
@@ -602,6 +602,7 @@ function buildInnerTools(logger, memory) {
|
|
|
602
602
|
// structured issue reporting.
|
|
603
603
|
plan: z.union([PlannerPlanSchema, z.unknown()]).describe("Candidate plan; malformed values are reported in issues."),
|
|
604
604
|
}),
|
|
605
|
+
view: "none",
|
|
605
606
|
describeCall: "none",
|
|
606
607
|
execute: (input) => {
|
|
607
608
|
// The host owns the grounding fields: it fills them from the last answer of the run.
|
|
@@ -639,6 +640,7 @@ function buildInnerTools(logger, memory) {
|
|
|
639
640
|
question: terminalTextSchema("One short question that names each missing fact, and the step that needs it."),
|
|
640
641
|
questionContext: z.string().optional().describe("Optional context: why the plan needs the fact, and what the inputs already say about it."),
|
|
641
642
|
}),
|
|
643
|
+
view: "none",
|
|
642
644
|
describeCall: "none",
|
|
643
645
|
execute: (input) => Promise.resolve(ok({
|
|
644
646
|
kind: "clarification",
|
|
@@ -1181,6 +1183,10 @@ export function createGeneratePlanTool(deps, registerSubAgent) {
|
|
|
1181
1183
|
"when the planner is missing a fact it cannot infer; or `error` with {error} when no plan was saved (the planner reported " +
|
|
1182
1184
|
"a blocker, the save failed, the call timed out or was cancelled, or parentPlanId is not a plan of this analysis).",
|
|
1183
1185
|
inputSchema: generatePlanInputSchema,
|
|
1186
|
+
view: {
|
|
1187
|
+
input: (input) => input,
|
|
1188
|
+
error: true,
|
|
1189
|
+
},
|
|
1184
1190
|
describeCall: ({ researchQuestion }) => researchQuestion,
|
|
1185
1191
|
startsWorkflow: true,
|
|
1186
1192
|
execute: async (input, ctx) => {
|
|
@@ -136,6 +136,11 @@ export function createInspectDataProfileTool(pool) {
|
|
|
136
136
|
"against when the input set last changed before you conclude anything: if the data moved since, say the profile " +
|
|
137
137
|
"needs re-running rather than diagnosing the data itself.",
|
|
138
138
|
inputSchema: InspectDataProfileInputSchema,
|
|
139
|
+
view: {
|
|
140
|
+
input: (input) => input,
|
|
141
|
+
result: (_input, result) => result,
|
|
142
|
+
error: true,
|
|
143
|
+
},
|
|
139
144
|
// `execute` defaults both fields internally, and the hook applies the same
|
|
140
145
|
// defaults. Without them the ordinary call, which names no field at all,
|
|
141
146
|
// gives no detail. `page` acts only on the `files` scope, as in `execute`.
|
|
@@ -109,6 +109,11 @@ export function createInspectRunTool(pool, clock = systemClock) {
|
|
|
109
109
|
"For a user-directed check, waitForTerminalSeconds can wait once for 1-30 seconds; if the cutoff returns in_progress, stop polling for that turn and tell the user that the run still runs. " +
|
|
110
110
|
"Default response is lightweight — pass includeDiagnostics:true to add error/duration/retry telemetry.",
|
|
111
111
|
inputSchema,
|
|
112
|
+
view: {
|
|
113
|
+
input: (input) => input,
|
|
114
|
+
result: (_input, result) => result,
|
|
115
|
+
error: true,
|
|
116
|
+
},
|
|
112
117
|
// The two calls do different work: one inspects a named run, the other
|
|
113
118
|
// pages the list. Naming the run id is what separates repeated polls of
|
|
114
119
|
// the same run from polls of different ones.
|
|
@@ -14,6 +14,7 @@ export function createResolveCitationTool(resolver) {
|
|
|
14
14
|
"not_found, unverifiable, or inconclusive. Source failure never becomes not_found — an unreachable authority reports unavailable, and " +
|
|
15
15
|
"not_found means the authorities that answered hold no such record.",
|
|
16
16
|
inputSchema: CitationInputSchema,
|
|
17
|
+
view: "none",
|
|
17
18
|
describeCall: ({ citation }) => `verify ${citation}`,
|
|
18
19
|
execute: async (input, ctx) => ok(await resolver.resolveOne(input, { signal: ctx.signal })),
|
|
19
20
|
});
|
|
@@ -39,6 +39,7 @@ export const searchArxivTool = defineTool({
|
|
|
39
39
|
"and that filter is combined with the query using AND."),
|
|
40
40
|
limit: z.number().int().min(1).max(20).default(10).describe("Maximum results (1–20, default 10)."),
|
|
41
41
|
}),
|
|
42
|
+
view: "none",
|
|
42
43
|
describeCall: "none",
|
|
43
44
|
execute: async ({ query, categories, limit }, context) => {
|
|
44
45
|
const result = await source.search({ query, categories, limit }, context.signal);
|
|
@@ -87,6 +87,7 @@ export function createSearchGithubReposTool(deps) {
|
|
|
87
87
|
"lands here). Report either one and continue, do not retry unchanged.",
|
|
88
88
|
outputSchema: SearchGithubReposOutputSchema,
|
|
89
89
|
inputSchema: SearchGithubReposInputSchema,
|
|
90
|
+
view: "none",
|
|
90
91
|
describeCall: "none",
|
|
91
92
|
execute: async ({ query, language, limit }) => {
|
|
92
93
|
const q = language ? `${query} language:${language}` : query;
|
|
@@ -46,6 +46,7 @@ export function createSearchSemanticScholarTool(options = {}) {
|
|
|
46
46
|
'"reinforcement learning for control" or "feedback stabilisation in oscillators".'),
|
|
47
47
|
limit: z.number().int().min(1).max(20).default(10).describe("Maximum number of results to return (1–20, default 10)."),
|
|
48
48
|
}),
|
|
49
|
+
view: "none",
|
|
49
50
|
describeCall: "none",
|
|
50
51
|
execute: async ({ query, limit }, context) => {
|
|
51
52
|
const result = await source.search(query, limit, context.signal);
|
|
@@ -614,6 +614,7 @@ export function createWebFetchTool(deps = {}) {
|
|
|
614
614
|
"private, link-local, or reserved), http_error, redirect_limit, body_too_large, unextractable, and request_failed each name what " +
|
|
615
615
|
"happened. Report the status and continue, do not retry unchanged.",
|
|
616
616
|
inputSchema: WebFetchInputSchema,
|
|
617
|
+
view: "none",
|
|
617
618
|
describeCall: ({ url }) => url,
|
|
618
619
|
execute: async ({ url }, ctx) => ok(await fetchOneUrl(url, deps, ctx)),
|
|
619
620
|
});
|
|
@@ -77,6 +77,7 @@ export function createWebSearchTool(deps) {
|
|
|
77
77
|
"ABSENCE IS NORMAL: an empty results array means no page matched, and a status of http_error, retryable_status, " +
|
|
78
78
|
"schema_mismatch, or not_json names a search that did not answer. Report either one and continue, do not retry unchanged.",
|
|
79
79
|
inputSchema: WebSearchInputSchema,
|
|
80
|
+
view: "none",
|
|
80
81
|
describeCall: "none",
|
|
81
82
|
execute: async ({ query, queries, numResults, recencyFilter, domainFilter }) => {
|
|
82
83
|
const filter = parseDomainFilter(domainFilter);
|
|
@@ -24,6 +24,7 @@ export function createAcquireSandboxTool(lease) {
|
|
|
24
24
|
"size replaces your sandbox: the files of your working directory stay, and the next command runs on the new " +
|
|
25
25
|
"size. Your files and your outputs live in the workspace, not in the sandbox.",
|
|
26
26
|
inputSchema: AcquireSandboxInputSchema,
|
|
27
|
+
view: "none",
|
|
27
28
|
describeCall: ({ cpu, memoryGb }) => `Waiting for a sandbox (${cpu} CPU, ${memoryGb} GB)`,
|
|
28
29
|
execute: async ({ cpu, memoryGb, gpuCount }) => {
|
|
29
30
|
const size = gpuCount === undefined || gpuCount === 0 ? { cpu, memoryGb } : { cpu, memoryGb, gpu: { count: gpuCount } };
|
|
@@ -51,6 +52,7 @@ export function createReleaseSandboxTool(lease) {
|
|
|
51
52
|
description: "Release your sandbox when your commands are done and you work only with files or research. The files stay. " +
|
|
52
53
|
"A later `execute_command` needs `acquire_sandbox` again.",
|
|
53
54
|
inputSchema: ReleaseSandboxInputSchema,
|
|
55
|
+
view: "none",
|
|
54
56
|
describeCall: () => "Releasing the sandbox",
|
|
55
57
|
execute: async () => {
|
|
56
58
|
await lease.release();
|
|
@@ -70,6 +70,7 @@ export function createLinkPackagesTool(deps) {
|
|
|
70
70
|
"After a `collision` of one name that BOTH tracks hold, call this tool again for that package with the prefixed form, `python:<name>` or `r:<name>`. " +
|
|
71
71
|
"A collision is terminal only after that second call also refuses, or when it names two versions of one distribution — then report it and continue without the package.",
|
|
72
72
|
inputSchema: LinkPackagesInputSchema,
|
|
73
|
+
view: "none",
|
|
73
74
|
describeCall: ({ packages }) => packages.join(", "),
|
|
74
75
|
execute: async (input) => {
|
|
75
76
|
// Every entry parses before any link lands. A partial link over a
|
|
@@ -495,6 +495,11 @@ export function createListAvailablePackagesTool(deps = {}) {
|
|
|
495
495
|
"`limit`: cap the packages listed; the response always carries the true `total` and a `hasMore` flag, so truncation is never silent. " +
|
|
496
496
|
"Each entry renders as `name==version` where the source pins a version, and a `names` check also reports the store directory and the content hash where the source records them.",
|
|
497
497
|
inputSchema: ListAvailablePackagesInputSchema,
|
|
498
|
+
view: {
|
|
499
|
+
input: (input) => input,
|
|
500
|
+
result: (_input, result) => result,
|
|
501
|
+
error: true,
|
|
502
|
+
},
|
|
498
503
|
// `queryPackages` returns on `names` before it reads another field, thus
|
|
499
504
|
// the presence check comes first. An empty array is not a presence check.
|
|
500
505
|
// `names` are exact identifiers a caller checks for, thus they name the
|
|
@@ -600,6 +600,11 @@ export function createListAvailableRefsTool(deps) {
|
|
|
600
600
|
"An empty result means the dataset is absent right now — not that it is unobtainable. Say so; never guess a path, and never silently substitute a different dataset. " +
|
|
601
601
|
"The store is provisioned by the host and is NOT frozen: datasets can be added through the host's own provisioning path between runs, and whatever is added shows up in a later run. Within one run the listing does not change, thus one call per question is enough.",
|
|
602
602
|
inputSchema: ListAvailableRefsInputSchema,
|
|
603
|
+
view: {
|
|
604
|
+
input: (input) => input,
|
|
605
|
+
result: (_input, result) => result,
|
|
606
|
+
error: true,
|
|
607
|
+
},
|
|
603
608
|
// `execute` resolves `path ?? category` for the subtree it inspects, and
|
|
604
609
|
// it ignores `category` when `path` is present. `query` is an ADDITIVE
|
|
605
610
|
// filter over that subtree, thus the target keeps naming the call and the
|
|
@@ -37,6 +37,7 @@ export function createReportBlockerToolFor(deps) {
|
|
|
37
37
|
id: REPORT_BLOCKER_TOOL_ID,
|
|
38
38
|
description: `Terminal. ${deps.blockedWhen} Pass a clear reason. Stop immediately after calling — take no further actions.`,
|
|
39
39
|
inputSchema: ReportBlockerInputSchema,
|
|
40
|
+
view: "none",
|
|
40
41
|
describeCall: "none",
|
|
41
42
|
execute: (input) => Promise.resolve(ok({ kind: "blocker", reason: input.reason, message: "Blocker recorded. You are done — stop now and do not take further actions." })),
|
|
42
43
|
});
|
|
@@ -63,6 +63,7 @@ export function createSkillTools(deps) {
|
|
|
63
63
|
"and the first line that holds a query word — ranked by how many distinct query words the file " +
|
|
64
64
|
"holds. Then `skill_read` the file. No matches returns a data variant.",
|
|
65
65
|
inputSchema: SkillSearchInputSchema,
|
|
66
|
+
view: "none",
|
|
66
67
|
describeCall: "none",
|
|
67
68
|
execute: async ({ query, topK }) => {
|
|
68
69
|
if (allowed.size === 0) {
|
|
@@ -121,6 +122,7 @@ export function createSkillTools(deps) {
|
|
|
121
122
|
"found via skill_search). Confined to your declared skills. Undeclared " +
|
|
122
123
|
"skills and missing paths return a data variant.",
|
|
123
124
|
inputSchema: SkillReadInputSchema,
|
|
125
|
+
view: "none",
|
|
124
126
|
describeCall: "none",
|
|
125
127
|
execute: async ({ skill, path }) => {
|
|
126
128
|
if (!allowed.has(skill)) {
|
|
@@ -43,6 +43,7 @@ export function createSubmitFileMetadataTool(cell) {
|
|
|
43
43
|
"accepted=true means every file now has metadata — STOP. Otherwise drop " +
|
|
44
44
|
"the unknownPaths and describe the remaining files.",
|
|
45
45
|
inputSchema: SubmitFileMetadataInputSchema,
|
|
46
|
+
view: "none",
|
|
46
47
|
describeCall: "none",
|
|
47
48
|
execute: (input) => {
|
|
48
49
|
const knownPaths = cell.knownPaths;
|
|
@@ -165,6 +165,7 @@ function createReadTableTool(deps) {
|
|
|
165
165
|
"A larger table, or another format such as h5ad, is work for an analysis run.",
|
|
166
166
|
inputSchema: readTableInput,
|
|
167
167
|
outputSchema: ReadTableOutputSchema,
|
|
168
|
+
view: "none",
|
|
168
169
|
describeCall: ({ path, entry }) => (entry === undefined ? path : `${path} : ${entry}`),
|
|
169
170
|
describeResult: (_input, result) => `${String(result.rowCount)} rows`,
|
|
170
171
|
execute: async ({ path, entry, columns }, ctx) => {
|
|
@@ -201,6 +202,7 @@ function createListArchiveTool(deps) {
|
|
|
201
202
|
"`read_table` and `read_pdf` then read one of them as their `entry`.",
|
|
202
203
|
inputSchema: listArchiveInput,
|
|
203
204
|
outputSchema: ListArchiveOutputSchema,
|
|
205
|
+
view: "none",
|
|
204
206
|
describeCall: ({ path }) => path,
|
|
205
207
|
describeResult: (_input, result) => `${String(result.entries.length)} files`,
|
|
206
208
|
execute: async ({ path }, ctx) => {
|
|
@@ -266,6 +268,7 @@ export function createReadPdfTool(deps) {
|
|
|
266
268
|
"A scanned page with no text layer reads as an empty text.",
|
|
267
269
|
inputSchema: readPdfInput,
|
|
268
270
|
outputSchema: ReadPdfOutputSchema,
|
|
271
|
+
view: "none",
|
|
269
272
|
describeCall: ({ path, entry, firstPage, lastPage }) => {
|
|
270
273
|
const file = entry === undefined ? path : `${path} : ${entry}`;
|
|
271
274
|
return firstPage === undefined && lastPage === undefined ? file : `${file}, pages ${String(firstPage ?? 1)}-${String(lastPage ?? "")}`;
|
|
@@ -359,6 +362,7 @@ function createWriteDerivedTool(deps) {
|
|
|
359
362
|
"A name holds one file: a second write of the name with other content is refused.",
|
|
360
363
|
inputSchema: writeDerivedInput,
|
|
361
364
|
outputSchema: WrittenOutputSchema,
|
|
365
|
+
view: "none",
|
|
362
366
|
describeCall: ({ name }) => name,
|
|
363
367
|
describeResult: (_input, result) => result.path,
|
|
364
368
|
execute: async ({ name, content, rows }, ctx) => {
|
|
@@ -400,6 +404,7 @@ function createRenderChartTool(deps) {
|
|
|
400
404
|
"To show a chart in the chat, use `show_user`.",
|
|
401
405
|
inputSchema: renderChartInput,
|
|
402
406
|
outputSchema: WrittenOutputSchema,
|
|
407
|
+
view: "none",
|
|
403
408
|
describeCall: ({ name }) => name,
|
|
404
409
|
describeResult: (_input, result) => result.path,
|
|
405
410
|
execute: async ({ name, spec, width }, ctx) => {
|
|
@@ -447,6 +452,7 @@ function createExportPdfTool(deps) {
|
|
|
447
452
|
"Charts that `render_chart` wrote can appear in it as images. The PDF reads no URL.",
|
|
448
453
|
inputSchema: exportPdfInput,
|
|
449
454
|
outputSchema: ExportPdfOutputSchema,
|
|
455
|
+
view: "none",
|
|
450
456
|
describeCall: ({ name }) => name,
|
|
451
457
|
describeResult: (_input, result) => result.path,
|
|
452
458
|
execute: async ({ name, markdown, title }, ctx) => {
|