@inflexa-ai/harness 0.45.0 → 0.45.1

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 (122) hide show
  1. package/dist/agents/conversation-agent.d.ts +10 -0
  2. package/dist/agents/conversation-agent.js +19 -1
  3. package/dist/agents/sandbox/shared.d.ts +23 -2
  4. package/dist/agents/sandbox/shared.js +51 -18
  5. package/dist/agents/sandbox/translational-safety-agent.js +26 -0
  6. package/dist/agents/sandbox/types.d.ts +24 -1
  7. package/dist/agents/sandbox-catalog.d.ts +14 -0
  8. package/dist/agents/sandbox-catalog.js +19 -0
  9. package/dist/app/approve-plan.d.ts +5 -2
  10. package/dist/app/approve-plan.js +1 -1
  11. package/dist/app/chat-turn.js +6 -3
  12. package/dist/config/environment-stores.d.ts +4 -2
  13. package/dist/contracts/chat-events.d.ts +12 -2
  14. package/dist/contracts/chat-events.js +1 -1
  15. package/dist/contracts/chat-frame.js +6 -2
  16. package/dist/contracts/index.d.ts +1 -1
  17. package/dist/contracts/schemas/chat-events.d.ts +25 -0
  18. package/dist/contracts/schemas/chat-events.js +7 -0
  19. package/dist/contracts/schemas/chat-parts.d.ts +39 -0
  20. package/dist/contracts/schemas/chat-parts.js +17 -0
  21. package/dist/contracts/schemas/index.d.ts +1 -1
  22. package/dist/contracts/schemas/index.js +1 -1
  23. package/dist/execution/dbos-workflow-purger.d.ts +2 -0
  24. package/dist/execution/dbos-workflow-purger.js +21 -14
  25. package/dist/execution/run-canceler.d.ts +33 -11
  26. package/dist/execution/run-canceler.js +129 -27
  27. package/dist/execution/run-end-record.d.ts +30 -0
  28. package/dist/execution/run-end-record.js +27 -0
  29. package/dist/index.d.ts +9 -5
  30. package/dist/index.js +11 -1
  31. package/dist/loop/call-guard.d.ts +50 -0
  32. package/dist/loop/call-guard.js +90 -0
  33. package/dist/loop/compaction.d.ts +5 -0
  34. package/dist/loop/compaction.js +17 -0
  35. package/dist/loop/run-agent.d.ts +9 -0
  36. package/dist/loop/run-agent.js +15 -1
  37. package/dist/loop/run-to-terminal.js +4 -1
  38. package/dist/loop/types.d.ts +6 -0
  39. package/dist/memory/conversation-display-recorder.d.ts +0 -2
  40. package/dist/memory/conversation-display-recorder.js +28 -3
  41. package/dist/memory/thread-history.d.ts +34 -7
  42. package/dist/memory/thread-history.js +151 -42
  43. package/dist/prompts/briefing.d.ts +57 -3
  44. package/dist/prompts/briefing.js +129 -2
  45. package/dist/prompts/planner.js +13 -2
  46. package/dist/provenance/seam.d.ts +23 -15
  47. package/dist/provenance/seam.js +7 -5
  48. package/dist/providers/ai-sdk.js +87 -7
  49. package/dist/providers/types.d.ts +6 -0
  50. package/dist/reference-data/catalog.js +141 -2
  51. package/dist/report-model/authoring-grammar.d.ts +26 -26
  52. package/dist/sandbox/image-packages.d.ts +26 -4
  53. package/dist/sandbox/image-packages.js +18 -4
  54. package/dist/schemas/data-profile-schemas.d.ts +12 -12
  55. package/dist/schemas/plan-schemas.d.ts +57 -3
  56. package/dist/schemas/plan-schemas.js +1 -1
  57. package/dist/schemas/workflow-state.d.ts +113 -0
  58. package/dist/schemas/workflow-state.js +54 -0
  59. package/dist/state/artifacts.d.ts +17 -1
  60. package/dist/state/artifacts.js +21 -3
  61. package/dist/state/index.d.ts +2 -2
  62. package/dist/state/index.js +1 -1
  63. package/dist/state/runs.d.ts +43 -9
  64. package/dist/state/runs.js +85 -14
  65. package/dist/state/step-executions.d.ts +9 -0
  66. package/dist/state/step-executions.js +22 -0
  67. package/dist/tools/ad-hoc-router.d.ts +2 -0
  68. package/dist/tools/ad-hoc-router.js +18 -2
  69. package/dist/tools/capability-data.d.ts +36 -0
  70. package/dist/tools/capability-data.js +73 -0
  71. package/dist/tools/execute-analysis.d.ts +37 -9
  72. package/dist/tools/execute-analysis.js +131 -21
  73. package/dist/tools/knowledge/check.d.ts +60 -0
  74. package/dist/tools/knowledge/check.js +92 -0
  75. package/dist/tools/knowledge/client.d.ts +382 -0
  76. package/dist/tools/knowledge/client.js +302 -0
  77. package/dist/tools/knowledge/environment.d.ts +78 -0
  78. package/dist/tools/knowledge/environment.js +105 -0
  79. package/dist/tools/knowledge/index.d.ts +49 -0
  80. package/dist/tools/knowledge/index.js +70 -0
  81. package/dist/tools/knowledge/local-slots.d.ts +62 -0
  82. package/dist/tools/knowledge/local-slots.js +177 -0
  83. package/dist/tools/knowledge/pin.d.ts +14 -0
  84. package/dist/tools/knowledge/pin.js +17 -0
  85. package/dist/tools/knowledge/recommend.d.ts +92 -0
  86. package/dist/tools/knowledge/recommend.js +98 -0
  87. package/dist/tools/knowledge/situation.d.ts +143 -0
  88. package/dist/tools/knowledge/situation.js +164 -0
  89. package/dist/tools/knowledge/skeleton.d.ts +69 -0
  90. package/dist/tools/knowledge/skeleton.js +202 -0
  91. package/dist/tools/knowledge/template.d.ts +137 -0
  92. package/dist/tools/knowledge/template.js +267 -0
  93. package/dist/tools/research/generate-plan.d.ts +23 -0
  94. package/dist/tools/research/generate-plan.js +203 -12
  95. package/dist/tools/research/guarded-address.d.ts +20 -0
  96. package/dist/tools/research/guarded-address.js +148 -0
  97. package/dist/tools/research/searxng-engine.d.ts +40 -0
  98. package/dist/tools/research/searxng-engine.js +120 -0
  99. package/dist/tools/research/web-fetch.d.ts +124 -0
  100. package/dist/tools/research/web-fetch.js +627 -0
  101. package/dist/tools/research/web-search.d.ts +75 -0
  102. package/dist/tools/research/web-search.js +112 -0
  103. package/dist/tools/sandbox/list-available-packages.d.ts +7 -4
  104. package/dist/tools/sandbox/list-available-packages.js +12 -4
  105. package/dist/tools/sandbox/list-available-refs.d.ts +21 -0
  106. package/dist/tools/sandbox/list-available-refs.js +60 -3
  107. package/dist/tools/sandbox/report-blocker.js +5 -1
  108. package/dist/tools/terminal-text.d.ts +11 -0
  109. package/dist/tools/terminal-text.js +19 -0
  110. package/dist/tools/workspace/decision-record.d.ts +81 -0
  111. package/dist/tools/workspace/decision-record.js +117 -0
  112. package/dist/tools/workspace/edit-file.d.ts +3 -1
  113. package/dist/tools/workspace/edit-file.js +20 -2
  114. package/dist/tools/workspace/execute-command.d.ts +17 -0
  115. package/dist/tools/workspace/execute-command.js +28 -1
  116. package/dist/tools/workspace/index.d.ts +1 -0
  117. package/dist/tools/workspace/index.js +1 -0
  118. package/dist/tools/workspace/mutator.d.ts +1 -1
  119. package/dist/workflows/execute-analysis.d.ts +58 -18
  120. package/dist/workflows/execute-analysis.js +273 -58
  121. package/dist/workflows/sandbox-step.d.ts +12 -0
  122. package/package.json +5 -1
@@ -7,8 +7,8 @@ import type { AnalysisPlan } from "./workflow-state.js";
7
7
  /** Step schema for planner output — omits fields populated at execution time
8
8
  * and the hardcoded sandbox turn budget. */
9
9
  export declare const PlanStepSchema: z.ZodObject<{
10
- name: z.ZodString;
11
10
  context: z.ZodOptional<z.ZodString>;
11
+ name: z.ZodString;
12
12
  description: z.ZodOptional<z.ZodString>;
13
13
  id: z.ZodString;
14
14
  caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -21,11 +21,29 @@ export declare const PlanStepSchema: z.ZodObject<{
21
21
  count: z.ZodNumber;
22
22
  }, z.core.$strip>>;
23
23
  }, z.core.$strip>>>;
24
+ grounding: z.ZodOptional<z.ZodObject<{
25
+ status: z.ZodEnum<{
26
+ grounded: "grounded";
27
+ ungrounded: "ungrounded";
28
+ flagged: "flagged";
29
+ }>;
30
+ snapshot: z.ZodString;
31
+ claims: z.ZodArray<z.ZodString>;
32
+ template: z.ZodOptional<z.ZodString>;
33
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
+ step: z.ZodString;
35
+ name: z.ZodString;
36
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
37
+ source: z.ZodOptional<z.ZodString>;
38
+ }, z.core.$strip>>>;
39
+ reason: z.ZodString;
40
+ }, z.core.$strip>>;
24
41
  track: z.ZodString;
25
42
  step_type: z.ZodString;
26
43
  acceptance_criteria: z.ZodArray<z.ZodString>;
27
44
  constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
28
45
  packages: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
46
+ capability: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
29
47
  agent: z.ZodEnum<{
30
48
  [x: string]: string;
31
49
  }>;
@@ -40,8 +58,8 @@ export declare const PlannerPlanSchema: z.ZodObject<{
40
58
  omicsSubtype: z.ZodOptional<z.ZodString>;
41
59
  title: z.ZodString;
42
60
  steps: z.ZodArray<z.ZodObject<{
43
- name: z.ZodString;
44
61
  context: z.ZodOptional<z.ZodString>;
62
+ name: z.ZodString;
45
63
  description: z.ZodOptional<z.ZodString>;
46
64
  id: z.ZodString;
47
65
  caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -54,11 +72,29 @@ export declare const PlannerPlanSchema: z.ZodObject<{
54
72
  count: z.ZodNumber;
55
73
  }, z.core.$strip>>;
56
74
  }, z.core.$strip>>>;
75
+ grounding: z.ZodOptional<z.ZodObject<{
76
+ status: z.ZodEnum<{
77
+ grounded: "grounded";
78
+ ungrounded: "ungrounded";
79
+ flagged: "flagged";
80
+ }>;
81
+ snapshot: z.ZodString;
82
+ claims: z.ZodArray<z.ZodString>;
83
+ template: z.ZodOptional<z.ZodString>;
84
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
85
+ step: z.ZodString;
86
+ name: z.ZodString;
87
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
88
+ source: z.ZodOptional<z.ZodString>;
89
+ }, z.core.$strip>>>;
90
+ reason: z.ZodString;
91
+ }, z.core.$strip>>;
57
92
  track: z.ZodString;
58
93
  step_type: z.ZodString;
59
94
  acceptance_criteria: z.ZodArray<z.ZodString>;
60
95
  constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
61
96
  packages: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
97
+ capability: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
62
98
  agent: z.ZodEnum<{
63
99
  [x: string]: string;
64
100
  }>;
@@ -82,8 +118,8 @@ export declare const PlanningAgentOutputSchema: z.ZodObject<{
82
118
  omicsSubtype: z.ZodOptional<z.ZodString>;
83
119
  title: z.ZodString;
84
120
  steps: z.ZodArray<z.ZodObject<{
85
- name: z.ZodString;
86
121
  context: z.ZodOptional<z.ZodString>;
122
+ name: z.ZodString;
87
123
  description: z.ZodOptional<z.ZodString>;
88
124
  id: z.ZodString;
89
125
  caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -96,11 +132,29 @@ export declare const PlanningAgentOutputSchema: z.ZodObject<{
96
132
  count: z.ZodNumber;
97
133
  }, z.core.$strip>>;
98
134
  }, z.core.$strip>>>;
135
+ grounding: z.ZodOptional<z.ZodObject<{
136
+ status: z.ZodEnum<{
137
+ grounded: "grounded";
138
+ ungrounded: "ungrounded";
139
+ flagged: "flagged";
140
+ }>;
141
+ snapshot: z.ZodString;
142
+ claims: z.ZodArray<z.ZodString>;
143
+ template: z.ZodOptional<z.ZodString>;
144
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
145
+ step: z.ZodString;
146
+ name: z.ZodString;
147
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
148
+ source: z.ZodOptional<z.ZodString>;
149
+ }, z.core.$strip>>>;
150
+ reason: z.ZodString;
151
+ }, z.core.$strip>>;
99
152
  track: z.ZodString;
100
153
  step_type: z.ZodString;
101
154
  acceptance_criteria: z.ZodArray<z.ZodString>;
102
155
  constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
103
156
  packages: z.ZodNonOptional<z.ZodOptional<z.ZodArray<z.ZodString>>>;
157
+ capability: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
104
158
  agent: z.ZodEnum<{
105
159
  [x: string]: string;
106
160
  }>;
@@ -17,7 +17,7 @@ export const PlanStepSchema = AnalysisStepSchema.omit({
17
17
  error: true,
18
18
  maxSteps: true,
19
19
  })
20
- .required({ agent: true, resources: true, packages: true })
20
+ .required({ agent: true, resources: true, packages: true, capability: true })
21
21
  .extend({
22
22
  agent: z.enum(plannableAgentIds).describe("Sandbox agent ID, routed by the step's primary data object. Must be one of the available agents."),
23
23
  });
@@ -5,6 +5,47 @@
5
5
  * and the completion schemas that validate LLM structured output.
6
6
  */
7
7
  import { z } from "zod";
8
+ /**
9
+ * One scientific setting of a grounded step: a parameter of the procedure
10
+ * that `knowledge_recommend` returned, with the procedure step it belongs to
11
+ * and the source of its value. The host binds the settings to the template
12
+ * of the step at dispatch, thus a template default never replaces a plan
13
+ * decision silently.
14
+ */
15
+ export declare const GroundingSettingSchema: z.ZodObject<{
16
+ step: z.ZodString;
17
+ name: z.ZodString;
18
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
19
+ source: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>;
21
+ export type GroundingSetting = z.infer<typeof GroundingSettingSchema>;
22
+ /**
23
+ * The grounding of one method step: the claim identifiers and the snapshot
24
+ * digest that `knowledge_recommend` returned in this run, the template the
25
+ * step renders, the settings of the procedure, and a one-line reason.
26
+ * Optional on both step schemas, thus a stored plan and a plan made without
27
+ * the knowledge service load and validate as before. Phase 0 validates the
28
+ * shape only. An empty field is visible: the evaluation counts a method step
29
+ * without a value as ungrounded.
30
+ */
31
+ export declare const GroundingSchema: z.ZodObject<{
32
+ status: z.ZodEnum<{
33
+ grounded: "grounded";
34
+ ungrounded: "ungrounded";
35
+ flagged: "flagged";
36
+ }>;
37
+ snapshot: z.ZodString;
38
+ claims: z.ZodArray<z.ZodString>;
39
+ template: z.ZodOptional<z.ZodString>;
40
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
41
+ step: z.ZodString;
42
+ name: z.ZodString;
43
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
44
+ source: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$strip>>>;
46
+ reason: z.ZodString;
47
+ }, z.core.$strip>;
48
+ export type Grounding = z.infer<typeof GroundingSchema>;
8
49
  /**
9
50
  * A step of an analysis plan. `PlanStepSchema` (schemas/plan-schemas.ts) narrows
10
51
  * this into the planner's output contract and emits it as the `submit_plan`
@@ -37,7 +78,25 @@ export declare const AnalysisStepSchema: z.ZodObject<{
37
78
  count: z.ZodNumber;
38
79
  }, z.core.$strip>>;
39
80
  }, z.core.$strip>>;
81
+ grounding: z.ZodOptional<z.ZodObject<{
82
+ status: z.ZodEnum<{
83
+ grounded: "grounded";
84
+ ungrounded: "ungrounded";
85
+ flagged: "flagged";
86
+ }>;
87
+ snapshot: z.ZodString;
88
+ claims: z.ZodArray<z.ZodString>;
89
+ template: z.ZodOptional<z.ZodString>;
90
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
91
+ step: z.ZodString;
92
+ name: z.ZodString;
93
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
94
+ source: z.ZodOptional<z.ZodString>;
95
+ }, z.core.$strip>>>;
96
+ reason: z.ZodString;
97
+ }, z.core.$strip>>;
40
98
  agent: z.ZodOptional<z.ZodString>;
99
+ capability: z.ZodOptional<z.ZodString>;
41
100
  timeout: z.ZodOptional<z.ZodNumber>;
42
101
  maxSteps: z.ZodNumber;
43
102
  description: z.ZodOptional<z.ZodString>;
@@ -74,7 +133,25 @@ export declare const AnalysisPlanSchema: z.ZodObject<{
74
133
  count: z.ZodNumber;
75
134
  }, z.core.$strip>>;
76
135
  }, z.core.$strip>>;
136
+ grounding: z.ZodOptional<z.ZodObject<{
137
+ status: z.ZodEnum<{
138
+ grounded: "grounded";
139
+ ungrounded: "ungrounded";
140
+ flagged: "flagged";
141
+ }>;
142
+ snapshot: z.ZodString;
143
+ claims: z.ZodArray<z.ZodString>;
144
+ template: z.ZodOptional<z.ZodString>;
145
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
146
+ step: z.ZodString;
147
+ name: z.ZodString;
148
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
149
+ source: z.ZodOptional<z.ZodString>;
150
+ }, z.core.$strip>>>;
151
+ reason: z.ZodString;
152
+ }, z.core.$strip>>;
77
153
  agent: z.ZodOptional<z.ZodString>;
154
+ capability: z.ZodOptional<z.ZodString>;
78
155
  timeout: z.ZodOptional<z.ZodNumber>;
79
156
  maxSteps: z.ZodNumber;
80
157
  description: z.ZodOptional<z.ZodString>;
@@ -146,7 +223,25 @@ export declare const ContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
146
223
  count: z.ZodNumber;
147
224
  }, z.core.$strip>>;
148
225
  }, z.core.$strip>>;
226
+ grounding: z.ZodOptional<z.ZodObject<{
227
+ status: z.ZodEnum<{
228
+ grounded: "grounded";
229
+ ungrounded: "ungrounded";
230
+ flagged: "flagged";
231
+ }>;
232
+ snapshot: z.ZodString;
233
+ claims: z.ZodArray<z.ZodString>;
234
+ template: z.ZodOptional<z.ZodString>;
235
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
236
+ step: z.ZodString;
237
+ name: z.ZodString;
238
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
239
+ source: z.ZodOptional<z.ZodString>;
240
+ }, z.core.$strip>>>;
241
+ reason: z.ZodString;
242
+ }, z.core.$strip>>;
149
243
  agent: z.ZodOptional<z.ZodString>;
244
+ capability: z.ZodOptional<z.ZodString>;
150
245
  timeout: z.ZodOptional<z.ZodNumber>;
151
246
  maxSteps: z.ZodNumber;
152
247
  description: z.ZodOptional<z.ZodString>;
@@ -266,7 +361,25 @@ export declare const SuspensionPayloadSchema: z.ZodObject<{
266
361
  count: z.ZodNumber;
267
362
  }, z.core.$strip>>;
268
363
  }, z.core.$strip>>;
364
+ grounding: z.ZodOptional<z.ZodObject<{
365
+ status: z.ZodEnum<{
366
+ grounded: "grounded";
367
+ ungrounded: "ungrounded";
368
+ flagged: "flagged";
369
+ }>;
370
+ snapshot: z.ZodString;
371
+ claims: z.ZodArray<z.ZodString>;
372
+ template: z.ZodOptional<z.ZodString>;
373
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
374
+ step: z.ZodString;
375
+ name: z.ZodString;
376
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
377
+ source: z.ZodOptional<z.ZodString>;
378
+ }, z.core.$strip>>>;
379
+ reason: z.ZodString;
380
+ }, z.core.$strip>>;
269
381
  agent: z.ZodOptional<z.ZodString>;
382
+ capability: z.ZodOptional<z.ZodString>;
270
383
  timeout: z.ZodOptional<z.ZodNumber>;
271
384
  maxSteps: z.ZodNumber;
272
385
  description: z.ZodOptional<z.ZodString>;
@@ -6,6 +6,50 @@
6
6
  */
7
7
  import { z } from "zod";
8
8
  // ── Plan structures ─────────────────────────────────────────────────
9
+ /**
10
+ * One scientific setting of a grounded step: a parameter of the procedure
11
+ * that `knowledge_recommend` returned, with the procedure step it belongs to
12
+ * and the source of its value. The host binds the settings to the template
13
+ * of the step at dispatch, thus a template default never replaces a plan
14
+ * decision silently.
15
+ */
16
+ export const GroundingSettingSchema = z.object({
17
+ step: z.string().describe("The procedure step the setting belongs to (for example `differential_expression` or `normalize`)."),
18
+ name: z.string().describe("The parameter name as the procedure names it (for example `alpha` or `lfc_shrink`)."),
19
+ value: z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]).describe("The value the procedure sets."),
20
+ source: z.string().optional().describe("The source of the value (a doi or a document) when the procedure names one. Absent otherwise."),
21
+ });
22
+ /**
23
+ * The grounding of one method step: the claim identifiers and the snapshot
24
+ * digest that `knowledge_recommend` returned in this run, the template the
25
+ * step renders, the settings of the procedure, and a one-line reason.
26
+ * Optional on both step schemas, thus a stored plan and a plan made without
27
+ * the knowledge service load and validate as before. Phase 0 validates the
28
+ * shape only. An empty field is visible: the evaluation counts a method step
29
+ * without a value as ungrounded.
30
+ */
31
+ export const GroundingSchema = z.object({
32
+ status: z
33
+ .enum(["grounded", "ungrounded", "flagged"])
34
+ .describe("`grounded` when the step follows a returned procedure; `ungrounded` when no rule covered it or the service did not answer; `flagged` when a rule changed the outcome of the step."),
35
+ snapshot: z.string().describe("The `snapshot.digest` that `knowledge_recommend` returned in this run, or `none`."),
36
+ claims: z
37
+ .array(z.string())
38
+ .describe("The claim identifiers of the step as `knowledge_recommend` returned them (for example `R-0031@e7d0`). Empty when ungrounded."),
39
+ template: z
40
+ .string()
41
+ .optional()
42
+ .describe("The template id with its version (for example `tpl-deseq2-two-group@1.0.0`) when the step renders a template. Absent otherwise."),
43
+ settings: z
44
+ .array(GroundingSettingSchema)
45
+ .optional()
46
+ .describe("The scientific settings of the step: the parameters of the procedure steps the plan step holds, as `knowledge_recommend` returned them. " +
47
+ "Copy the `grounding.settings` of the skeleton step as it is, one entry per parameter, with its step, name, value, and source. " +
48
+ "Do not restate a setting as prose only, and do not change a value here: state a different value in the step and its reason. Absent when the step is ungrounded."),
49
+ reason: z
50
+ .string()
51
+ .describe("One line: the situation and the method with the rule that selects it, the side chosen for a disputed rule, or why the step is ungrounded or flagged."),
52
+ });
9
53
  /**
10
54
  * A step of an analysis plan. `PlanStepSchema` (schemas/plan-schemas.ts) narrows
11
55
  * this into the planner's output contract and emits it as the `submit_plan`
@@ -52,8 +96,18 @@ export const AnalysisStepSchema = z.object({
52
96
  })
53
97
  .optional()
54
98
  .describe("Resources the step needs. Ground the estimate in the actual data size — see the resource-estimation rules."),
99
+ grounding: GroundingSchema.optional().describe("The knowledge grounding of a method step: fill it from the answer of `knowledge_recommend` when that tool is attached. Omit it when no knowledge tool is attached."),
55
100
  // Execution fields
56
101
  agent: z.string().optional().describe("Assigned sandbox agent name from registry"),
102
+ // Optional on the persistence schema so a plan stored before this field still parses.
103
+ // `PlanStepSchema` re-requires it for planner output. The launch reads it with the agent id to
104
+ // resolve what reference data the capability declares — refer to `capabilityDataRequirement`.
105
+ capability: z
106
+ .string()
107
+ .optional()
108
+ .describe("The one capability phrase of the assigned agent that this step uses, copied EXACTLY from the agent catalog. " +
109
+ "One phrase, verbatim — never a paraphrase, never a list, never your own wording. " +
110
+ "The launch resolves the reference data that the capability declares before the run starts, so a reworded phrase loses that check and the step discovers an absent source itself."),
57
111
  timeout: z.number().optional().describe("Execution timeout in seconds (falls back to image default)"),
58
112
  maxSteps: z.number().describe("Max LLM agentic steps for sandbox agent"),
59
113
  description: z.string().optional().describe("Human-readable description of what the step produces."),
@@ -84,6 +84,13 @@ export interface ArtifactPageQuery {
84
84
  fileType?: string;
85
85
  /** A part of the path, with no regard to case. Each character matches only itself. */
86
86
  q?: string;
87
+ /** The whole path, with case. It selects the one row of that path. */
88
+ path?: string;
89
+ /**
90
+ * Extensions in lower case, with no dot. A row is selected when the extension of its path is a member. A row with
91
+ * no extension never matches, and an empty list selects each row. The read compares the members as they are.
92
+ */
93
+ extensions?: readonly string[];
87
94
  sort: ArtifactPageSort;
88
95
  limit: number;
89
96
  offset: number;
@@ -100,14 +107,23 @@ export interface ArtifactPageEntry {
100
107
  stepId: string | null;
101
108
  createdAt: string;
102
109
  }
110
+ /** The count of the selected rows that have one extension. */
111
+ export interface ArtifactExtensionCount {
112
+ /** The extension in lower case with no dot, or `null` for the rows that have no extension. */
113
+ extension: string | null;
114
+ count: number;
115
+ }
103
116
  /** One page of the ledger, and the count of the rows that the filters select. */
104
117
  export interface ArtifactPage {
105
118
  entries: ArtifactPageEntry[];
106
119
  total: number;
120
+ /** The selected rows by extension, in the order of the extension with `null` last. The counts sum to `total`. */
121
+ extensionCounts: ArtifactExtensionCount[];
107
122
  }
108
123
  /**
109
124
  * One page of the artifact ledger of an analysis, in two statements: the count of the rows that the filters
110
- * select, and the page. The count is a separate statement because a page past the end has no row to carry it.
125
+ * select, grouped by extension, and the page. The count is a separate statement because a page past the end has no
126
+ * row to carry it. `total` is the sum of the groups.
111
127
  *
112
128
  * Every row of the analysis is a member, an `input` row and a row with `unrecoverable_at` included. The cost
113
129
  * grows with the ledger of the one analysis, because the count reads each filtered row.
@@ -179,9 +179,16 @@ export function queryAnalysisArtifacts(pool, analysisId) {
179
179
  return result.rows.map((r) => ({ path: r.path, hash: r.hash, fileType: r.file_type ?? null }));
180
180
  });
181
181
  }
182
+ /**
183
+ * The extension of `path` in lower case: the text after the last dot of the file name, which is the part after the
184
+ * last `/`. The pattern needs one character or more before that dot and one or more after it, thus a name with no dot,
185
+ * a name whose only dot is its first character, and a name that ends with a dot give `NULL`.
186
+ */
187
+ const EXTENSION_SQL = `lower(substring(regexp_replace(path, '^.*/', '') from '^.+\\.([^.]+)$'))`;
182
188
  /**
183
189
  * One page of the artifact ledger of an analysis, in two statements: the count of the rows that the filters
184
- * select, and the page. The count is a separate statement because a page past the end has no row to carry it.
190
+ * select, grouped by extension, and the page. The count is a separate statement because a page past the end has no
191
+ * row to carry it. `total` is the sum of the groups.
185
192
  *
186
193
  * Every row of the analysis is a member, an `input` row and a row with `unrecoverable_at` included. The cost
187
194
  * grows with the ledger of the one analysis, because the count reads each filtered row.
@@ -203,11 +210,21 @@ export function queryArtifactPage(pool, analysisId, query) {
203
210
  // `LIKE` would turn `%` and `_` of the input into wildcards.
204
211
  if (query.q !== undefined)
205
212
  conditions.push(`strpos(lower(path), lower(${bind(query.q)}::text)) > 0`);
213
+ if (query.path !== undefined)
214
+ conditions.push(`path = ${bind(query.path)}`);
215
+ if (query.extensions !== undefined && query.extensions.length > 0) {
216
+ conditions.push(`${EXTENSION_SQL} = ANY(${bind([...query.extensions])}::text[])`);
217
+ }
206
218
  const where = conditions.join(" AND ");
207
219
  const countResult = await pool.query({
208
- text: `SELECT COUNT(*)::int AS total FROM cortex_artifacts WHERE ${where}`,
220
+ text: `SELECT ${EXTENSION_SQL} AS extension, COUNT(*)::int AS n
221
+ FROM cortex_artifacts
222
+ WHERE ${where}
223
+ GROUP BY 1
224
+ ORDER BY 1 ASC NULLS LAST`,
209
225
  values,
210
226
  });
227
+ const extensionCounts = countResult.rows.map((r) => ({ extension: r.extension ?? null, count: Number(r.n) }));
211
228
  // `path` is unique in one analysis, thus it breaks each tie and two pages never overlap.
212
229
  const order = query.sort === "recent" ? "created_at DESC, path ASC" : "path ASC";
213
230
  const rowsResult = await pool.query({
@@ -228,7 +245,8 @@ export function queryArtifactPage(pool, analysisId, query) {
228
245
  stepId: r.source_step ?? null,
229
246
  createdAt: r.created_at,
230
247
  })),
231
- total: Number(countResult.rows[0]?.total ?? 0),
248
+ total: extensionCounts.reduce((sum, e) => sum + e.count, 0),
249
+ extensionCounts,
232
250
  };
233
251
  });
234
252
  }
@@ -10,9 +10,9 @@ export { initCortexState } from "./init.js";
10
10
  export type { Querier } from "./db.js";
11
11
  export { upsertAnalysis, suspendAnalysis, resumeAnalysis, loadAnalysisStatus } from "./analyses.js";
12
12
  export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryStepArtifactPaths, queryUnsyncedStepArtifacts, updateArtifactId, updateFileIds, queryArtifactPage, countArtifactsByRuns, } from "./artifacts.js";
13
- export type { RegisterArtifactInput, InputArtifactMeta, StepArtifactRef, ArtifactPage, ArtifactPageEntry, ArtifactPageQuery, ArtifactPageSort, RunArtifactCount, } from "./artifacts.js";
13
+ export type { RegisterArtifactInput, InputArtifactMeta, StepArtifactRef, ArtifactExtensionCount, ArtifactPage, ArtifactPageEntry, ArtifactPageQuery, ArtifactPageSort, RunArtifactCount, } from "./artifacts.js";
14
14
  export { insertRun, reserveRunById, RunDedupCollisionError, RunIdentityCollisionError, updateRunStatus, reconcileOrphanedRuns, ORPHANED_RUN_GRACE_MS, markRunCanceledIfActive, promoteFailedToPartial, setRunMandate, // oss-core-managed-ok: run-mandate ledger (nullable; OSS leaves null)
15
- setRunSynthesisOutcome, queryRun, queryActiveRun, queryNonTerminalRunsByAnalysis, queryRunsForInspection, queryRunsByAnalysis, queryRunsByThread, queryRunIdsByPlan, } from "./runs.js";
15
+ setRunSynthesisOutcome, queryRun, queryActiveRun, queryNonTerminalRunsByAnalysis, queryRunsForInspection, queryRunsByAnalysis, countRunsByAnalysis, queryRunsByThread, queryRunIdsByPlan, queryNewestPlanRun, } from "./runs.js";
16
16
  export type { InsertRunInput, RunPage, RunReservation } from "./runs.js";
17
17
  export { insertStepExecution, seedStepExecutions, sweepPendingStepExecutions, updateStepExecution, queryStepsByRun } from "./step-executions.js";
18
18
  export type { InsertStepExecutionInput, SeedStepExecutionRow, UpdateStepExecutionInput } from "./step-executions.js";
@@ -10,7 +10,7 @@ export { initCortexState } from "./init.js";
10
10
  export { upsertAnalysis, suspendAnalysis, resumeAnalysis, loadAnalysisStatus } from "./analyses.js";
11
11
  export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryStepArtifactPaths, queryUnsyncedStepArtifacts, updateArtifactId, updateFileIds, queryArtifactPage, countArtifactsByRuns, } from "./artifacts.js";
12
12
  export { insertRun, reserveRunById, RunDedupCollisionError, RunIdentityCollisionError, updateRunStatus, reconcileOrphanedRuns, ORPHANED_RUN_GRACE_MS, markRunCanceledIfActive, promoteFailedToPartial, setRunMandate, // oss-core-managed-ok: run-mandate ledger (nullable; OSS leaves null)
13
- setRunSynthesisOutcome, queryRun, queryActiveRun, queryNonTerminalRunsByAnalysis, queryRunsForInspection, queryRunsByAnalysis, queryRunsByThread, queryRunIdsByPlan, } from "./runs.js";
13
+ setRunSynthesisOutcome, queryRun, queryActiveRun, queryNonTerminalRunsByAnalysis, queryRunsForInspection, queryRunsByAnalysis, countRunsByAnalysis, queryRunsByThread, queryRunIdsByPlan, queryNewestPlanRun, } from "./runs.js";
14
14
  export { insertStepExecution, seedStepExecutions, sweepPendingStepExecutions, updateStepExecution, queryStepsByRun } from "./step-executions.js";
15
15
  export { setSandboxRef, clearSandboxRef, reconcileReapedSandbox } from "./active-sandboxes.js";
16
16
  export { insertPlan, upsertPlan, loadPlan, loadPlanRecord } from "./plans.js";
@@ -21,6 +21,8 @@ export interface InsertRunInput {
21
21
  planId?: string | null;
22
22
  mandateJti?: string | null;
23
23
  mandateExpiresAt?: string | null;
24
+ /** The start time as an ISO string. Without it, the row gets the clock of the host. */
25
+ startedAt?: string;
24
26
  }
25
27
  export interface RunReservation {
26
28
  readonly row: CortexRunRow;
@@ -64,6 +66,11 @@ export declare function reserveRunById(pool: Querier, input: InsertRunInput): Re
64
66
  * most one match.
65
67
  */
66
68
  export declare function queryActiveRun(pool: Querier, analysisId: string, planId: string | null): ResultAsync<CortexRunRow | null, DbError>;
69
+ /** The optional text filter of the run reads. */
70
+ export interface RunTextFilter {
71
+ /** A part of the run id or of the plan title, with no regard to case. Each character matches only itself. */
72
+ q?: string;
73
+ }
67
74
  /**
68
75
  * Every NON-TERMINAL run of an analysis, newest-first and deliberately unbounded.
69
76
  *
@@ -80,8 +87,10 @@ export declare function queryActiveRun(pool: Querier, analysisId: string, planId
80
87
  * The status set is the one {@link queryActiveRun} uses — non-terminal means `running`. Keep the two
81
88
  * in step: a new non-terminal status added to one and not the other makes a live run invisible to
82
89
  * exactly one of its readers.
90
+ *
91
+ * With `q`, only the runs that the text filter selects are members.
83
92
  */
84
- export declare function queryActiveRunsByAnalysis(pool: Querier, analysisId: string): ResultAsync<CortexRunRow[], DbError>;
93
+ export declare function queryActiveRunsByAnalysis(pool: Querier, analysisId: string, { q }?: RunTextFilter): ResultAsync<CortexRunRow[], DbError>;
85
94
  /**
86
95
  * How long a reserved run may wait for its workflow before {@link reconcileOrphanedRuns} fails it. A launch writes
87
96
  * the workflow row seconds after the reservation, and the margin covers a slow authorization gate of a managed host.
@@ -104,23 +113,36 @@ export declare function reconcileOrphanedRuns(pool: Querier, opts?: {
104
113
  now?: number;
105
114
  graceMs?: number;
106
115
  }): ResultAsync<string[], DbError>;
107
- export declare function updateRunStatus(pool: Querier, runId: string, status: "running" | "completed" | "partial" | "failed" | "canceled" | "suspended_insufficient_funds", error?: string | null): ResultAsync<void, DbError>;
116
+ /**
117
+ * Write a status to a run row that is still `running`, and report whether the row changed. The first terminal write
118
+ * of a run wins: a row that already holds a terminal status keeps its status, its `completed_at`, and its error.
119
+ * The error text loses each NUL character, because Postgres rejects a NUL in text and the write must not fail for its own value.
120
+ */
121
+ export declare function updateRunStatus(pool: Querier, runId: string, status: "running" | "completed" | "partial" | "failed" | "canceled" | "suspended_insufficient_funds", error?: string | null): ResultAsync<boolean, DbError>;
108
122
  /**
109
123
  * Conditionally transition an ACTIVE run to `canceled`, stamping `completed_at`
110
124
  * and recording `reason` in `error` (the same column `collectAndComplete`
111
125
  * stamps `external_cancel` into). Reports whether a row transitioned — false
112
126
  * means the run was already terminal (e.g. it completed concurrently with an
113
- * external cancel), and the caller MUST NOT fall back to `updateRunStatus`,
114
- * which would clobber that terminal status. The guarded set is the active set
115
- * `queryActiveRun` deduplicates on.
127
+ * external cancel). The guarded set is the active set `queryActiveRun`
128
+ * deduplicates on.
116
129
  */
117
130
  export declare function markRunCanceledIfActive(pool: Querier, runId: string, reason: string): ResultAsync<boolean, DbError>;
118
131
  export declare function promoteFailedToPartial(pool: Querier, runId: string): ResultAsync<boolean, DbError>;
119
132
  export declare function queryRun(pool: Querier, runId: string): ResultAsync<CortexRunRow | null, DbError>;
120
- export declare function queryRunsByAnalysis(pool: Querier, analysisId: string, { limit, offset }?: {
133
+ /**
134
+ * One window of the runs of an analysis, newest start first. With `q`, the window holds only the runs that the text
135
+ * filter selects: the filter applies before `limit` and `offset`, and it does not change the order.
136
+ */
137
+ export declare function queryRunsByAnalysis(pool: Querier, analysisId: string, { limit, offset, q }?: {
121
138
  limit?: number;
122
139
  offset?: number;
123
- }): ResultAsync<CortexRunRow[], DbError>;
140
+ } & RunTextFilter): ResultAsync<CortexRunRow[], DbError>;
141
+ /**
142
+ * The count of the runs of an analysis, in one statement. With `q`, the count holds only the runs that the text filter
143
+ * selects, thus it agrees with the windows of {@link queryRunsByAnalysis} for the same `q`.
144
+ */
145
+ export declare function countRunsByAnalysis(pool: Querier, analysisId: string, { q }?: RunTextFilter): ResultAsync<number, DbError>;
124
146
  /**
125
147
  * The run ids of one plan of one analysis, newest start first, at most `limit`.
126
148
  * The run id breaks a tie of start times, highest first. A plan with no run gives
@@ -131,6 +153,17 @@ export declare function queryRunIdsByPlan(pool: Querier, opts: {
131
153
  planId: string;
132
154
  limit: number;
133
155
  }): ResultAsync<string[], DbError>;
156
+ /**
157
+ * The newest run of one plan of one analysis, or `null` for a plan with no run. The order is the one of
158
+ * {@link queryRunIdsByPlan}: the latest start first, and the highest run id on a tie of start times.
159
+ */
160
+ export declare function queryNewestPlanRun(pool: Querier, opts: {
161
+ analysisId: string;
162
+ planId: string;
163
+ }): ResultAsync<{
164
+ runId: string;
165
+ startedAt: string;
166
+ } | null, DbError>;
134
167
  /**
135
168
  * Read the analysis's non-terminal run activity without coupling it to a
136
169
  * conversation thread. The total is counted before the detail limit so a
@@ -146,10 +179,11 @@ export declare function queryRunsForInspection(pool: Querier, analysisId: string
146
179
  limit?: number;
147
180
  offset?: number;
148
181
  }): ResultAsync<RunPage, DbError>;
149
- export declare function queryRunsByThread(pool: Querier, analysisId: string, threadId: string, { limit, offset }?: {
182
+ /** The runs of one thread of an analysis, newest start first. With `q`, the text filter applies before the window. */
183
+ export declare function queryRunsByThread(pool: Querier, analysisId: string, threadId: string, { limit, offset, q }?: {
150
184
  limit?: number;
151
185
  offset?: number;
152
- }): ResultAsync<CortexRunRow[], DbError>;
186
+ } & RunTextFilter): ResultAsync<CortexRunRow[], DbError>;
153
187
  /**
154
188
  * Persist the run mandate jti + expiry for a run. oss-core-managed-ok: run-mandate ledger (nullable; OSS leaves null)
155
189
  * Called by `authorizeForRun` after a successful mint so the cancel