@inflexa-ai/harness 0.39.2 → 0.40.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 (184) hide show
  1. package/README.md +2 -3
  2. package/dist/agents/conversation-agent.d.ts +3 -0
  3. package/dist/agents/conversation-agent.js +13 -2
  4. package/dist/agents/report-session-agent.d.ts +3 -0
  5. package/dist/agents/report-session-agent.js +2 -0
  6. package/dist/agents/sandbox/cheminformatics-agent.js +0 -3
  7. package/dist/agents/sandbox/shared.d.ts +11 -2
  8. package/dist/agents/sandbox/shared.js +4 -0
  9. package/dist/app/chat-turn.d.ts +75 -12
  10. package/dist/app/chat-turn.js +149 -21
  11. package/dist/app/message-assembly.d.ts +16 -52
  12. package/dist/app/message-assembly.js +41 -68
  13. package/dist/app/run-activity.d.ts +4 -6
  14. package/dist/app/run-activity.js +7 -27
  15. package/dist/app/spawn-report-session.d.ts +6 -11
  16. package/dist/app/spawn-report-session.js +5 -6
  17. package/dist/app/synthesize-run.d.ts +3 -0
  18. package/dist/app/synthesize-run.js +1 -0
  19. package/dist/billing/usage-recorder.d.ts +3 -4
  20. package/dist/billing/usage-recorder.js +3 -4
  21. package/dist/contracts/chat-parts.d.ts +11 -1
  22. package/dist/contracts/chat-parts.js +1 -0
  23. package/dist/contracts/index.d.ts +1 -1
  24. package/dist/contracts/part-registry.js +1 -0
  25. package/dist/contracts/report-blocks.d.ts +8 -8
  26. package/dist/contracts/schemas/chat-parts.d.ts +32 -9
  27. package/dist/contracts/schemas/chat-parts.js +10 -0
  28. package/dist/execution/artifact-metadata.d.ts +26 -33
  29. package/dist/execution/artifact-metadata.js +44 -106
  30. package/dist/execution/post-step-pipeline.d.ts +23 -16
  31. package/dist/execution/post-step-pipeline.js +19 -21
  32. package/dist/execution/run-synthesis.d.ts +3 -0
  33. package/dist/execution/run-synthesis.js +11 -1
  34. package/dist/execution/step-summary.d.ts +21 -30
  35. package/dist/execution/step-summary.js +30 -57
  36. package/dist/index.d.ts +9 -8
  37. package/dist/index.js +15 -34
  38. package/dist/lib/zod-issues.js +2 -4
  39. package/dist/loop/compaction.d.ts +20 -0
  40. package/dist/loop/compaction.js +2 -0
  41. package/dist/loop/continue-agent.d.ts +40 -0
  42. package/dist/loop/continue-agent.js +38 -0
  43. package/dist/loop/metrics.d.ts +30 -22
  44. package/dist/loop/metrics.js +51 -22
  45. package/dist/loop/run-agent.d.ts +111 -13
  46. package/dist/loop/run-agent.js +467 -220
  47. package/dist/loop/run-to-terminal.d.ts +16 -17
  48. package/dist/loop/run-to-terminal.js +24 -35
  49. package/dist/loop/tool-mask.d.ts +23 -0
  50. package/dist/loop/tool-mask.js +46 -0
  51. package/dist/loop/tool-output.d.ts +48 -0
  52. package/dist/loop/tool-output.js +79 -0
  53. package/dist/loop/types.d.ts +6 -3
  54. package/dist/memory/ai-sdk-message-storage.d.ts +49 -2
  55. package/dist/memory/ai-sdk-message-storage.js +78 -2
  56. package/dist/memory/conversation-display-recorder.d.ts +6 -0
  57. package/dist/memory/conversation-display-recorder.js +64 -22
  58. package/dist/memory/conversation-display-replay.d.ts +5 -14
  59. package/dist/memory/conversation-display-replay.js +66 -32
  60. package/dist/memory/conversation-display-storage.d.ts +2 -1
  61. package/dist/memory/conversation-display-storage.js +2 -1
  62. package/dist/memory/conversation-view.d.ts +53 -0
  63. package/dist/memory/conversation-view.js +130 -0
  64. package/dist/memory/count-tokens.d.ts +5 -7
  65. package/dist/memory/count-tokens.js +7 -9
  66. package/dist/memory/thread-history.d.ts +74 -102
  67. package/dist/memory/thread-history.js +181 -246
  68. package/dist/memory/thread-store.d.ts +3 -3
  69. package/dist/memory/thread-store.js +7 -2
  70. package/dist/memory/tool-call-integrity.d.ts +15 -21
  71. package/dist/memory/tool-call-integrity.js +31 -38
  72. package/dist/memory/working-memory.d.ts +2 -5
  73. package/dist/memory/working-memory.js +2 -5
  74. package/dist/prompts/SOUL.d.ts +2 -2
  75. package/dist/prompts/SOUL.js +2 -7
  76. package/dist/prompts/analogical-reasoner.d.ts +1 -1
  77. package/dist/prompts/analogical-reasoner.js +16 -32
  78. package/dist/prompts/briefing.js +1 -1
  79. package/dist/prompts/compaction.d.ts +4 -0
  80. package/dist/prompts/compaction.js +24 -0
  81. package/dist/prompts/conversation.d.ts +1 -1
  82. package/dist/prompts/conversation.js +26 -35
  83. package/dist/prompts/execute-analysis/step-summary.js +7 -5
  84. package/dist/prompts/literature-reviewer.d.ts +1 -1
  85. package/dist/prompts/literature-reviewer.js +29 -34
  86. package/dist/prompts/planner.js +15 -29
  87. package/dist/prompts/report-session.d.ts +1 -1
  88. package/dist/prompts/report-session.js +2 -33
  89. package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
  90. package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +1 -2
  91. package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
  92. package/dist/prompts/sandbox/cheminformatics-agent.js +10 -29
  93. package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
  94. package/dist/prompts/sandbox/chromatin-agent.js +1 -2
  95. package/dist/prompts/sandbox/data-profiler.js +6 -3
  96. package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
  97. package/dist/prompts/sandbox/dna-methylation-agent.js +2 -7
  98. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  99. package/dist/prompts/sandbox/drug-repurposing-agent.js +20 -24
  100. package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
  101. package/dist/prompts/sandbox/enrichment-agent.js +3 -2
  102. package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
  103. package/dist/prompts/sandbox/genomic-variant-agent.js +0 -2
  104. package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
  105. package/dist/prompts/sandbox/immune-profiling-agent.js +7 -14
  106. package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
  107. package/dist/prompts/sandbox/metabolomics-agent.js +0 -2
  108. package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
  109. package/dist/prompts/sandbox/microbiome-agent.js +14 -21
  110. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
  111. package/dist/prompts/sandbox/multi-omics-integration-agent.js +9 -19
  112. package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
  113. package/dist/prompts/sandbox/multimodal-sc-agent.js +4 -5
  114. package/dist/prompts/sandbox/network-agent.d.ts +1 -1
  115. package/dist/prompts/sandbox/network-agent.js +7 -8
  116. package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
  117. package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +19 -19
  118. package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
  119. package/dist/prompts/sandbox/proteomics-agent.js +3 -4
  120. package/dist/prompts/sandbox/scientific-executor.d.ts +1 -1
  121. package/dist/prompts/sandbox/scientific-executor.js +7 -10
  122. package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
  123. package/dist/prompts/sandbox/single-cell-agent.js +2 -4
  124. package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
  125. package/dist/prompts/sandbox/spatial-omics-agent.js +3 -5
  126. package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
  127. package/dist/prompts/sandbox/statistical-modeling-agent.js +1 -1
  128. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
  129. package/dist/prompts/sandbox/translational-safety-agent.js +10 -19
  130. package/dist/prompts/sandbox-standards.d.ts +7 -7
  131. package/dist/prompts/sandbox-standards.js +74 -76
  132. package/dist/prompts/synthesis-agent.d.ts +1 -1
  133. package/dist/prompts/synthesis-agent.js +16 -42
  134. package/dist/providers/ai-sdk.d.ts +39 -6
  135. package/dist/providers/ai-sdk.js +117 -18
  136. package/dist/providers/errors.d.ts +2 -0
  137. package/dist/providers/errors.js +5 -0
  138. package/dist/providers/prompt-cache.d.ts +43 -41
  139. package/dist/providers/prompt-cache.js +47 -41
  140. package/dist/providers/reasoning.d.ts +10 -21
  141. package/dist/providers/reasoning.js +10 -21
  142. package/dist/providers/types.d.ts +21 -5
  143. package/dist/report-model/authoring-grammar.d.ts +2 -2
  144. package/dist/runtime/assemble.d.ts +9 -7
  145. package/dist/runtime/assemble.js +7 -3
  146. package/dist/sandbox/create-sandbox.d.ts +2 -2
  147. package/dist/sandbox/submit-exec.d.ts +1 -1
  148. package/dist/schemas/artifact-manifest.d.ts +4 -4
  149. package/dist/state/init.js +39 -4
  150. package/dist/state/purge-analysis.js +4 -0
  151. package/dist/state/tool-outputs.d.ts +4 -0
  152. package/dist/state/tool-outputs.js +30 -0
  153. package/dist/tasks/data-profile.d.ts +3 -0
  154. package/dist/tasks/data-profile.js +2 -0
  155. package/dist/tools/ad-hoc-router.d.ts +8 -0
  156. package/dist/tools/ad-hoc-router.js +21 -2
  157. package/dist/tools/display/show-user.d.ts +1 -1
  158. package/dist/tools/execute-analysis.d.ts +3 -0
  159. package/dist/tools/execute-analysis.js +9 -1
  160. package/dist/tools/read-tool-output.d.ts +7 -0
  161. package/dist/tools/read-tool-output.js +130 -0
  162. package/dist/tools/research/generate-analogy-report.d.ts +10 -26
  163. package/dist/tools/research/generate-analogy-report.js +76 -163
  164. package/dist/tools/research/generate-plan.d.ts +3 -0
  165. package/dist/tools/research/generate-plan.js +4 -1
  166. package/dist/tools/research/literature-reviewer.d.ts +3 -0
  167. package/dist/tools/research/literature-reviewer.js +3 -0
  168. package/dist/tools/sandbox/report-blocker.d.ts +18 -5
  169. package/dist/tools/sandbox/report-blocker.js +54 -6
  170. package/dist/tools/sandbox/submit-file-metadata.d.ts +30 -0
  171. package/dist/tools/sandbox/submit-file-metadata.js +67 -0
  172. package/dist/tools/start-report-session.d.ts +1 -3
  173. package/dist/tools/start-report-session.js +0 -2
  174. package/dist/tools/workspace/execute-command.js +7 -4
  175. package/dist/tools/workspace/result-bounds.d.ts +4 -4
  176. package/dist/tools/workspace/result-bounds.js +6 -5
  177. package/dist/tools/workspace/workspace-search.d.ts +1 -1
  178. package/dist/workflows/execute-analysis.d.ts +3 -0
  179. package/dist/workflows/execute-analysis.js +1 -0
  180. package/dist/workflows/sandbox-step.d.ts +30 -9
  181. package/dist/workflows/sandbox-step.js +37 -8
  182. package/package.json +9 -9
  183. package/dist/providers/anthropic.d.ts +0 -25
  184. package/dist/providers/anthropic.js +0 -28
@@ -6,18 +6,24 @@
6
6
  * `report_blocker` is the alternative to improvising an inline result the
7
7
  * harness would launder into a green run.
8
8
  *
9
- * This module is the canonical home of the tool. Three loops offer it — the
10
- * sandbox step agent, the planner (`tools/research/generate-plan.ts`) and the
11
- * run synthesizer (`execution/run-synthesis.ts`) — and all three share one id,
9
+ * This module is the canonical home of the tool. Four loops offer it — the
10
+ * sandbox step agent, the planner (`tools/research/generate-plan.ts`), the
11
+ * run synthesizer (`execution/run-synthesis.ts`) and the analogical reasoner
12
+ * (`tools/research/generate-analogy-report.ts`) — and all four share one id,
12
13
  * one input schema and one terminal contract via `createReportBlockerToolFor`.
13
14
  * What differs per loop is only what a blocker *means* there, so each call site
14
15
  * injects its own `blockedWhen` prose and its own capture closure. The tool
15
- * records the reason and tells the agent to stop; the driving body reads its
16
- * own outcome cell after the loop and decides the terminal status.
16
+ * records the reason and tells the agent to stop; the driving body reads the
17
+ * outcome after the loop and decides the terminal status. The sandbox step body
18
+ * runs in durable steps, so it reads the blocker back from the transcript
19
+ * (`recordedBlocker`) on replay, not only from its cell.
17
20
  */
18
21
  import { ok } from "neverthrow";
19
22
  import { z } from "zod";
23
+ import { repairToolInput } from "../../lib/zod-issues.js";
24
+ import { toolOutcomeForOutputType } from "../../loop/tool-outcome.js";
20
25
  import { defineTool } from "../define-tool.js";
26
+ export const REPORT_BLOCKER_TOOL_ID = "report_blocker";
21
27
  export function createBlockerHolder() {
22
28
  return { outcome: null };
23
29
  }
@@ -30,7 +36,7 @@ const ReportBlockerInputSchema = z.object({ reason: z.string().min(1) });
30
36
  */
31
37
  export function createReportBlockerToolFor(deps) {
32
38
  return defineTool({
33
- id: "report_blocker",
39
+ id: REPORT_BLOCKER_TOOL_ID,
34
40
  description: `Terminal. ${deps.blockedWhen} Pass a clear reason. Stop immediately after calling — take no further actions.`,
35
41
  inputSchema: ReportBlockerInputSchema,
36
42
  describeCall: "none",
@@ -43,6 +49,48 @@ export function createReportBlockerToolFor(deps) {
43
49
  },
44
50
  });
45
51
  }
52
+ /**
53
+ * The blocker that a run recorded, read from its transcript: the reason of the
54
+ * first `report_blocker` call, in call order, whose result is ok.
55
+ *
56
+ * A replay returns each tool step's cached result without re-running
57
+ * `execute`, so the in-memory cell is empty on replay; the transcript is not.
58
+ */
59
+ export function recordedBlocker(messages) {
60
+ const recorded = new Set();
61
+ for (const message of messages) {
62
+ if (message.role !== "tool")
63
+ continue;
64
+ for (const part of message.content) {
65
+ if (part.type === "tool-result" && part.toolName === REPORT_BLOCKER_TOOL_ID && toolOutcomeForOutputType(part.output.type) === "ok") {
66
+ recorded.add(part.toolCallId);
67
+ }
68
+ }
69
+ }
70
+ for (const message of messages) {
71
+ if (message.role !== "assistant" || typeof message.content === "string")
72
+ continue;
73
+ for (const part of message.content) {
74
+ if (part.type !== "tool-call" || part.toolName !== REPORT_BLOCKER_TOOL_ID || !recorded.has(part.toolCallId))
75
+ continue;
76
+ const reason = blockerReason(part.input);
77
+ if (reason !== undefined)
78
+ return { kind: "blocker", reason };
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ /** The reason of a `report_blocker` input, validated as the dispatch validates it. */
84
+ function blockerReason(input) {
85
+ const parsed = ReportBlockerInputSchema.safeParse(input);
86
+ if (parsed.success)
87
+ return parsed.data.reason;
88
+ const repaired = repairToolInput(input, parsed.error);
89
+ if (repaired === undefined)
90
+ return undefined;
91
+ const reparsed = ReportBlockerInputSchema.safeParse(repaired);
92
+ return reparsed.success ? reparsed.data.reason : undefined;
93
+ }
46
94
  /**
47
95
  * The sandbox step agent's `report_blocker`, bound to the step body's holder.
48
96
  * A blocker here ends the step with no deliverables and a blocked reason.
@@ -0,0 +1,30 @@
1
+ /**
2
+ * `submit_file_metadata` — the output tool of the file-metadata continuation of
3
+ * a sandbox step (see the harness-sandbox-agents spec).
4
+ *
5
+ * Each step agent declares this tool from its first request; a mask refuses it
6
+ * until the file-metadata continuation, because the tool set sits in the
7
+ * prefix that the prompt cache and a signed thinking block bind to.
8
+ *
9
+ * The tool matches each description to its file BY PATH, never by array
10
+ * index, so a dropped, reordered, or extra entry can never attach a
11
+ * description to the wrong file.
12
+ */
13
+ import { type SubmittedFileDescription } from "../../schemas/file-metadata.js";
14
+ import { type Tool } from "../define-tool.js";
15
+ export declare const SUBMIT_FILE_METADATA_TOOL_ID = "submit_file_metadata";
16
+ /**
17
+ * The per-step cell of the file-metadata continuation. The step body makes it
18
+ * beside the blocker cell, and the agent factory binds the output tool to it.
19
+ */
20
+ export interface FileMetadataCell {
21
+ /** The paths that the continuation describes, or `null` before the first `expect`. */
22
+ readonly knownPaths: ReadonlySet<string> | null;
23
+ /** The accepted description of each described path, keyed by the path. The tool writes only a known path. */
24
+ readonly descriptions: Map<string, SubmittedFileDescription>;
25
+ /** Arm the cell for one continuation: set the known paths, and drop each accepted description. */
26
+ expect(paths: readonly string[]): void;
27
+ }
28
+ export declare function createFileMetadataCell(): FileMetadataCell;
29
+ /** Build the `submit_file_metadata` tool bound to the cell of one step. */
30
+ export declare function createSubmitFileMetadataTool(cell: FileMetadataCell): Tool;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `submit_file_metadata` — the output tool of the file-metadata continuation of
3
+ * a sandbox step (see the harness-sandbox-agents spec).
4
+ *
5
+ * Each step agent declares this tool from its first request; a mask refuses it
6
+ * until the file-metadata continuation, because the tool set sits in the
7
+ * prefix that the prompt cache and a signed thinking block bind to.
8
+ *
9
+ * The tool matches each description to its file BY PATH, never by array
10
+ * index, so a dropped, reordered, or extra entry can never attach a
11
+ * description to the wrong file.
12
+ */
13
+ import { err, ok } from "neverthrow";
14
+ import { SubmitFileMetadataInputSchema } from "../../schemas/file-metadata.js";
15
+ import { defineTool } from "../define-tool.js";
16
+ export const SUBMIT_FILE_METADATA_TOOL_ID = "submit_file_metadata";
17
+ export function createFileMetadataCell() {
18
+ let knownPaths = null;
19
+ const descriptions = new Map();
20
+ return {
21
+ get knownPaths() {
22
+ return knownPaths;
23
+ },
24
+ descriptions,
25
+ expect(paths) {
26
+ knownPaths = new Set(paths);
27
+ descriptions.clear();
28
+ },
29
+ };
30
+ }
31
+ /** Build the `submit_file_metadata` tool bound to the cell of one step. */
32
+ export function createSubmitFileMetadataTool(cell) {
33
+ return defineTool({
34
+ id: SUBMIT_FILE_METADATA_TOOL_ID,
35
+ description: "Submit the metadata of the output files of this step. The harness asks " +
36
+ "for this tool after the task, with the list of the files. It does not " +
37
+ "run during the task. Each entry's `path` MUST exactly match one of the " +
38
+ "listed files. Returns {accepted, unknownPaths, remaining}: " +
39
+ "accepted=true means every file now has metadata — STOP. Otherwise drop " +
40
+ "the unknownPaths and describe the remaining files.",
41
+ inputSchema: SubmitFileMetadataInputSchema,
42
+ describeCall: "none",
43
+ execute: async (input) => {
44
+ const knownPaths = cell.knownPaths;
45
+ if (knownPaths === null) {
46
+ return err({
47
+ error: "No list of files is known yet. The harness asks for the file metadata after the task, with the list of the files.",
48
+ retryable: false,
49
+ });
50
+ }
51
+ const unknownPaths = [];
52
+ for (const entry of input.files) {
53
+ if (!knownPaths.has(entry.path)) {
54
+ unknownPaths.push(entry.path);
55
+ continue;
56
+ }
57
+ cell.descriptions.set(entry.path, entry);
58
+ }
59
+ const remaining = [...knownPaths].filter((path) => !cell.descriptions.has(path));
60
+ return ok({
61
+ accepted: unknownPaths.length === 0 && remaining.length === 0,
62
+ unknownPaths,
63
+ remaining,
64
+ });
65
+ },
66
+ });
67
+ }
@@ -45,7 +45,7 @@ export type StartReportSessionInput = z.infer<typeof startReportSessionInput>;
45
45
  * never throws for a degraded condition.
46
46
  *
47
47
  * `started` and `existing-session` name a report thread. `refused` names a call
48
- * whose scope carries no conversation thread. The four refusals of the spawn
48
+ * whose scope carries no conversation thread. The three refusals of the spawn
49
49
  * keep their own names, thus the agent reads one reason from the spawn and from
50
50
  * the tool alike. `failed` is a store fault, and it carries a short line.
51
51
  */
@@ -68,8 +68,6 @@ export type StartReportSessionResult = {
68
68
  } | {
69
69
  outcome: "parent_not_a_conversation";
70
70
  threadType: ThreadType;
71
- } | {
72
- outcome: "empty_parent_transcript";
73
71
  } | {
74
72
  outcome: "failed";
75
73
  detail: string;
@@ -79,8 +79,6 @@ function toOutcome(fault) {
79
79
  return { outcome: "parent_not_found" };
80
80
  case "parent_not_a_conversation":
81
81
  return { outcome: "parent_not_a_conversation", threadType: fault.threadType };
82
- case "empty_parent_transcript":
83
- return { outcome: "empty_parent_transcript" };
84
82
  case "query_failed":
85
83
  case "mutation_failed":
86
84
  case "connection_failed":
@@ -24,7 +24,7 @@ import { ok } from "neverthrow";
24
24
  import { z } from "zod";
25
25
  import { defineTool } from "../define-tool.js";
26
26
  import { feedExecFrame } from "../../provenance/exec-frame.js";
27
- import { boundExecResult } from "./result-bounds.js";
27
+ import { EXEC_STREAM_BYTE_CAP, boundExecResult } from "./result-bounds.js";
28
28
  import { runSandboxExec } from "./run-exec.js";
29
29
  import { createNoopLogger } from "../../lib/console-logger.js";
30
30
  const ExecuteCommandInputSchema = z.object({
@@ -32,7 +32,8 @@ const ExecuteCommandInputSchema = z.object({
32
32
  .array(z.string().min(1))
33
33
  .min(1)
34
34
  .describe("argv array — e.g. ['python', 'scripts/run.py'] or ['head', '-n', '50', 'data/inputs/x.csv']. " +
35
- "Not passed through a shell; quoting and globbing are not expanded."),
35
+ "A one-element array runs through `sh -c`, so pipes, `&&`, quoting, and globbing work; " +
36
+ "an array of two or more elements runs directly, with no shell, and nothing is expanded."),
36
37
  cwd: z
37
38
  .string()
38
39
  .optional()
@@ -57,8 +58,10 @@ export function createExecuteCommandTool(deps) {
57
58
  executionMode: "workflow",
58
59
  description: "Run a command in the sandbox and return its stdout/stderr/exit code. " +
59
60
  "Use for scripts, CLI tools, shell pipes, and anything the workspace " +
60
- "tools don't express. stdout and stderr are each capped at 8 KiB; oversize " +
61
- "streams come back with truncation markers. Failures are returned as data, " +
61
+ `tools don't express. stdout and stderr are each capped at ${EXEC_STREAM_BYTE_CAP / (1024 * 1024)} MiB; the end ` +
62
+ "of a longer stream is dropped, and the result carries its truncation flag. A long result comes back as an " +
63
+ "excerpt of its start and its end, with a reference to read the rest when the harness keeps it. " +
64
+ "Failures are returned as data, " +
62
65
  "not thrown. stdout/stderr are EPHEMERAL and are NOT a deliverable — use " +
63
66
  "this to confirm a command ran, not to produce results. Do NOT compute " +
64
67
  "analysis results via 'python -c' / inline one-liners and read them from " +
@@ -5,9 +5,9 @@
5
5
  * shape is uniform across the surface and the cap can be tuned in one
6
6
  * place.
7
7
  *
8
- * The cap is well below the loop's overall result budget so a chatty
9
- * command cannot blow the context window even when stdout AND stderr both
10
- * cap out at the limit.
8
+ * The cap bounds the memory of the host and the size of a kept tool output. It
9
+ * does not keep the context of the model small: the loop cuts a long result into
10
+ * an excerpt, and it keeps the text for `read_tool_output`.
11
11
  *
12
12
  * The same value is sent to the sandbox as a retention budget, so the bytes are
13
13
  * dropped at the producer and never cross the wire. Capping here as well is not
@@ -15,7 +15,7 @@
15
15
  * and this is the boundary that keeps it out of the process either way.
16
16
  */
17
17
  import type { ExecResult } from "../../sandbox/types.js";
18
- /** Per-stream cap. 32 KiB — roomy for real output, well under the loop result budget. */
18
+ /** Per-stream cap: the maximum of a kept tool output, thus the host gets each stream that the store can keep. */
19
19
  export declare const EXEC_STREAM_BYTE_CAP: number;
20
20
  export interface BoundedStream {
21
21
  readonly content: string;
@@ -5,17 +5,18 @@
5
5
  * shape is uniform across the surface and the cap can be tuned in one
6
6
  * place.
7
7
  *
8
- * The cap is well below the loop's overall result budget so a chatty
9
- * command cannot blow the context window even when stdout AND stderr both
10
- * cap out at the limit.
8
+ * The cap bounds the memory of the host and the size of a kept tool output. It
9
+ * does not keep the context of the model small: the loop cuts a long result into
10
+ * an excerpt, and it keeps the text for `read_tool_output`.
11
11
  *
12
12
  * The same value is sent to the sandbox as a retention budget, so the bytes are
13
13
  * dropped at the producer and never cross the wire. Capping here as well is not
14
14
  * redundant: a sandbox image that pre-dates the budget returns the whole stream,
15
15
  * and this is the boundary that keeps it out of the process either way.
16
16
  */
17
- /** Per-stream cap. 32 KiB — roomy for real output, well under the loop result budget. */
18
- export const EXEC_STREAM_BYTE_CAP = 32 * 1024;
17
+ import { TOOL_OUTPUT_KEEP_MAX } from "../../loop/tool-output.js";
18
+ /** Per-stream cap: the maximum of a kept tool output, thus the host gets each stream that the store can keep. */
19
+ export const EXEC_STREAM_BYTE_CAP = TOOL_OUTPUT_KEEP_MAX;
19
20
  /**
20
21
  * Decode `buf` as UTF-8, dropping a trailing partial sequence rather than
21
22
  * letting it decode to U+FFFD. Only the last few bytes can be partial, so the
@@ -23,7 +23,7 @@ export declare function fileTargetOf(id: string, metadata: unknown): string | un
23
23
  export declare function createWorkspaceSearchTool(pool: Pool, embedding: EmbeddingProvider): import("../define-tool.js").Tool<{
24
24
  query: string;
25
25
  limit: number;
26
- type?: "output" | "input" | "synthesis" | "summary" | "input-group" | "input-dimension" | "input-kind" | undefined;
26
+ type?: "output" | "input" | "summary" | "synthesis" | "input-group" | "input-dimension" | "input-kind" | undefined;
27
27
  }, {
28
28
  results: {
29
29
  metadata: unknown;
@@ -80,6 +80,7 @@ import type { AnalysisStep } from "../schemas/workflow-state.js";
80
80
  import type { ChatProvider, EmbeddingProvider } from "../providers/types.js";
81
81
  import type { BioToolKeys } from "../tools/bio/keys.js";
82
82
  import type { ProvenanceSeam } from "../provenance/seam.js";
83
+ import type { ToolOutputStore } from "../loop/tool-output.js";
83
84
  import type { RunCharge } from "../billing/run-charge.js";
84
85
  import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
85
86
  import { type PlanStep } from "./execute-analysis-scheduler.js";
@@ -245,6 +246,8 @@ export interface ExecuteAnalysisDeps {
245
246
  * recorder.
246
247
  */
247
248
  readonly usageRecorder?: UsageRecorder;
249
+ /** The store of the loops of the run synthesis and of their read tools. */
250
+ readonly toolOutputStore?: ToolOutputStore;
248
251
  /**
249
252
  * The provenance seam of the composition. The body reads its run emit member,
250
253
  * and it reads no other member.
@@ -354,6 +354,7 @@ export function synthesizeFindings(args) {
354
354
  bioKeys: deps.bioKeys,
355
355
  citationResolver: deps.citationResolver,
356
356
  usageRecorder: deps.usageRecorder,
357
+ ...(deps.toolOutputStore ? { toolOutputStore: deps.toolOutputStore } : {}),
357
358
  }, {
358
359
  analysisId,
359
360
  runId,
@@ -9,8 +9,9 @@
9
9
  * 2. `createSandbox` — provision the sandbox; persist its handle.
10
10
  * 3. `runAgent` — the harness agent loop. Every LLM and tool
11
11
  * call inside is its own durableStep.
12
- * 4. `generateFileMetadata`— post-step LLM call (chunked, slice-to-length).
13
- * 5. `generateStepSummary` — post-step LLM call producing `output/summary.md`.
12
+ * 4. `generateFileMetadata`— the file-metadata continuation of the step agent.
13
+ * 5. `generateStepSummary` — the summary continuation of the step agent,
14
+ * producing `output/summary.md`.
14
15
  * 6. `reconcile + register`— write artifact manifest entries to cortex_artifacts.
15
16
  * 7. `syncArtifacts` — register provenance + upload missing file_ids
16
17
  * via the managed root (scoped to this run+step).
@@ -32,6 +33,7 @@ import type { Logger } from "../lib/logger.js";
32
33
  import type { UsageRecorder } from "../billing/usage-recorder.js";
33
34
  import type { CitationResolver } from "../citations/types.js";
34
35
  import type { AgentDefinition, LoopMessage } from "../loop/types.js";
36
+ import { type ToolOutputStore } from "../loop/tool-output.js";
35
37
  import type { AgentChat, EmbeddingProvider } from "../providers/types.js";
36
38
  import { type RunSession, type SpawnSession } from "../auth/types.js";
37
39
  import type { FileMetadataEntry } from "../execution/artifact-metadata.js";
@@ -41,10 +43,12 @@ import type { SandboxClient } from "../sandbox/client.js";
41
43
  import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
42
44
  import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
43
45
  import type { ArtifactRegistry } from "../execution/artifact-registry.js";
46
+ import { type StepFileMetadata } from "../execution/post-step-pipeline.js";
44
47
  import type { ResourceSpec } from "../config/resource-limits.js";
45
48
  import type { SandboxRef } from "../sandbox/types.js";
46
49
  import { ProvenanceCollector } from "../provenance/collector.js";
47
50
  import { type BlockerHolder } from "../tools/sandbox/report-blocker.js";
51
+ import { type FileMetadataCell } from "../tools/sandbox/submit-file-metadata.js";
48
52
  /**
49
53
  * Input the parent hands the child. Must be JSON-serialisable — DBOS
50
54
  * persists this as the workflow's input row.
@@ -200,13 +204,19 @@ export interface SandboxAgentBuildContext {
200
204
  */
201
205
  readonly lineageCollector: ProvenanceCollector;
202
206
  /**
203
- * Per-run blocker cell (see the harness-sandbox-agents spec). The body owns it and reads
204
- * `holder.outcome` after `runAgent`; the agent factory adds `report_blocker`
205
- * bound to this holder.
207
+ * Per-run blocker cell that `report_blocker` writes. The body prefers the
208
+ * blocker read from the transcript and falls back to this cell.
206
209
  */
207
210
  readonly blockerHolder: BlockerHolder;
211
+ /**
212
+ * Cell for the file-metadata continuation. `submit_file_metadata` is
213
+ * declared up front for prefix stability but masked until then.
214
+ */
215
+ readonly fileMetadata: FileMetadataCell;
208
216
  /** Shared host-side citation resolver for allowlisted sandbox agents. */
209
217
  readonly citationResolver: CitationResolver;
218
+ /** Give it to `SandboxAgentDeps.toolOutputStore`: each loop of the step keeps its texts in it. */
219
+ readonly toolOutputStore?: ToolOutputStore;
210
220
  }
211
221
  /**
212
222
  * Inversion of control: the parent supplies the live agent, the parent's
@@ -226,12 +236,14 @@ export interface SandboxStepDeps {
226
236
  readonly logger?: Logger;
227
237
  /**
228
238
  * LLM usage-accounting seam. Covers this step's agent loop and the
229
- * post-step sub-agent loops alike; omitted falls back to the no-op recorder.
239
+ * post-step continuations alike; omitted falls back to the no-op recorder.
230
240
  */
231
241
  readonly usageRecorder?: UsageRecorder;
242
+ /** The store of the task, of the two post-step continuations, and of the read tool of the step agent. */
243
+ readonly toolOutputStore?: ToolOutputStore;
232
244
  /** Shared resolver threaded from `assembleCoreRuntime`. */
233
245
  readonly citationResolver: CitationResolver;
234
- /** Non-streaming chat — drives the agent loop + the post-step sub-agents. */
246
+ /** Non-streaming chat — drives the agent loop + the post-step continuations. */
235
247
  readonly provider: AgentChat;
236
248
  /** Write-side embedder for the post-step vector index. */
237
249
  readonly embedding: EmbeddingProvider;
@@ -242,11 +254,14 @@ export interface SandboxStepDeps {
242
254
  * cloud-free build, external provenance ledger in the managed build).
243
255
  */
244
256
  readonly artifactRegistry: ArtifactRegistry;
245
- /** Workspace read seam — backs `read_file` in the metadata + summary loops. */
257
+ /**
258
+ * No longer read by the step body; kept because `src/index.ts` exports
259
+ * this type and an embedder builds it as an object literal.
260
+ */
246
261
  readonly workspaceFs: WorkspaceFilesystem;
247
262
  /** Workspace-root resolution seam (see workspace/paths.ts). */
248
263
  readonly resolveWorkspaceRoot: ResolveWorkspaceRoot;
249
- /** Sandbox model id — provenance label for metadata + summary generation. */
264
+ /** No longer read by the step body, kept for the same reason as `workspaceFs`. */
250
265
  readonly model: string;
251
266
  /**
252
267
  * Build the agent definition for this step. The parent resolves the
@@ -272,6 +287,10 @@ export interface PostStepContext {
272
287
  readonly input: SandboxStepInput;
273
288
  readonly session: RunSession;
274
289
  readonly transcript: readonly LoopMessage[];
290
+ /** The step agent of the task: the continuations send its system prompt and its declared tools. */
291
+ readonly agent: AgentDefinition;
292
+ /** The cell that the `submit_file_metadata` tool of `agent` records into. */
293
+ readonly fileMetadata: FileMetadataCell;
275
294
  /** Absolute path to the step's writable artifact directory. */
276
295
  readonly writePrefix: string;
277
296
  /** Sandbox handle id — informational only, used in log lines. */
@@ -279,6 +298,8 @@ export interface PostStepContext {
279
298
  /** Same step-scoped collector the agent loop fed each exec frame into. */
280
299
  readonly lineageCollector: ProvenanceCollector;
281
300
  }
301
+ /** Normalizes a pre-`messages` checkpoint (a bare entries array) for replay. */
302
+ export declare function readStepFileMetadata(checkpoint: StepFileMetadata | readonly FileMetadataEntry[]): StepFileMetadata;
282
303
  /**
283
304
  * Build the step's lineage collector from its durable input. The agent loop
284
305
  * feeds each exec's provenance frame into it; post-step registration reads the
@@ -9,8 +9,9 @@
9
9
  * 2. `createSandbox` — provision the sandbox; persist its handle.
10
10
  * 3. `runAgent` — the harness agent loop. Every LLM and tool
11
11
  * call inside is its own durableStep.
12
- * 4. `generateFileMetadata`— post-step LLM call (chunked, slice-to-length).
13
- * 5. `generateStepSummary` — post-step LLM call producing `output/summary.md`.
12
+ * 4. `generateFileMetadata`— the file-metadata continuation of the step agent.
13
+ * 5. `generateStepSummary` — the summary continuation of the step agent,
14
+ * producing `output/summary.md`.
14
15
  * 6. `reconcile + register`— write artifact manifest entries to cortex_artifacts.
15
16
  * 7. `syncArtifacts` — register provenance + upload missing file_ids
16
17
  * via the managed root (scoped to this run+step).
@@ -34,6 +35,8 @@ import { deliverNotice } from "../lib/hooks.js";
34
35
  import { unwrapOrThrow } from "../lib/result.js";
35
36
  import { runAgent } from "../loop/run-agent.js";
36
37
  import { durableStep } from "../loop/run-step.js";
38
+ import { maskExcept } from "../loop/tool-mask.js";
39
+ import { READ_TOOL_OUTPUT_TOOL_ID } from "../loop/tool-output.js";
37
40
  import { lastExecOutcome } from "../sandbox/exec-outcome.js";
38
41
  import { activityForTool, applyTreeDelta, isChatDataPart, sandboxTreeDelta, stepPartId } from "../sandbox/sandbox-step-translate.js";
39
42
  import { createDetailResolver } from "../tools/detail-resolver.js";
@@ -43,7 +46,8 @@ import { collectStepOutputs, describeStepRegistrationFailure, generateStepFileMe
43
46
  import { mintSandboxIdentity } from "../sandbox/identity.js";
44
47
  import { keepSuspendingRefusal } from "../sandbox/sandbox-error.js";
45
48
  import { ProvenanceCollector } from "../provenance/collector.js";
46
- import { createBlockerHolder } from "../tools/sandbox/report-blocker.js";
49
+ import { createBlockerHolder, recordedBlocker } from "../tools/sandbox/report-blocker.js";
50
+ import { createFileMetadataCell, SUBMIT_FILE_METADATA_TOOL_ID } from "../tools/sandbox/submit-file-metadata.js";
47
51
  import { cancelSelf, suspensionOfFailure, suspensionOfRefusal, suspensionOfSpawnRefusal } from "./suspension.js";
48
52
  /**
49
53
  * Fallback when the plan step omits `timeout`. Plans that need 3-hour runs
@@ -69,6 +73,15 @@ function nextFunctionIdFactory() {
69
73
  let n = 0;
70
74
  return () => `fn-${(n++).toString(36)}`;
71
75
  }
76
+ const NO_STEP_FILE_METADATA = { entries: [], messages: [] };
77
+ /** Normalizes a pre-`messages` checkpoint (a bare entries array) for replay. */
78
+ export function readStepFileMetadata(checkpoint) {
79
+ return isBareEntries(checkpoint) ? { entries: checkpoint, messages: [] } : checkpoint;
80
+ }
81
+ /** `Array.isArray` as a guard that also narrows a readonly array. */
82
+ function isBareEntries(checkpoint) {
83
+ return Array.isArray(checkpoint);
84
+ }
72
85
  /**
73
86
  * Map an internal step failure to a user-safe string. Internal detail (file
74
87
  * paths, content hashes, managed-root rejection reasons, stack traces) stays in the pod
@@ -210,6 +223,7 @@ export async function runSandboxStepBody(input, deps) {
210
223
  // for up to N × `timeoutSeconds`.
211
224
  const stepDeadlineMs = (await DBOS.now()) + (input.timeoutSeconds ?? DEFAULT_STEP_TIMEOUT_SECONDS) * 1000;
212
225
  const blockerHolder = createBlockerHolder();
226
+ const fileMetadata = createFileMetadataCell();
213
227
  const agent = deps.buildAgent({
214
228
  input,
215
229
  session,
@@ -220,8 +234,13 @@ export async function runSandboxStepBody(input, deps) {
220
234
  deadlineMs: () => stepDeadlineMs,
221
235
  lineageCollector,
222
236
  blockerHolder,
237
+ fileMetadata,
223
238
  citationResolver: deps.citationResolver,
239
+ ...(deps.toolOutputStore ? { toolOutputStore: deps.toolOutputStore } : {}),
224
240
  });
241
+ if (deps.toolOutputStore !== undefined && !agent.tools.some((tool) => tool.id === READ_TOOL_OUTPUT_TOOL_ID)) {
242
+ logger.warn("the step agent declares no read_tool_output, thus its loops keep no text of a cut tool result");
243
+ }
225
244
  // Built over THIS agent's tools, not a shared table: a sandbox agent's roster
226
245
  // differs per agent type, and each tool describes its own calls.
227
246
  const resolveDetail = createDetailResolver(agent.tools, logger);
@@ -361,10 +380,14 @@ export async function runSandboxStepBody(input, deps) {
361
380
  emit,
362
381
  runStep: durableStep,
363
382
  usageRecorder: deps.usageRecorder,
383
+ toolOutputStore: deps.toolOutputStore,
364
384
  formatStepName: {
365
385
  llm: (iteration) => `llm:${iteration}`,
366
386
  tool: (toolName, toolUseId) => `tool:${toolName}:${toolUseId}`,
367
387
  },
388
+ // The agent declares the output tool of the file-metadata
389
+ // continuation from its first request, and the task must not use it.
390
+ toolMask: maskExcept(agent.tools, [SUBMIT_FILE_METADATA_TOOL_ID]),
368
391
  isFatalLoopError: (err) => err instanceof DBOSErrors.DBOSWorkflowCancelledError,
369
392
  });
370
393
  transcript = agentResult.messages;
@@ -421,7 +444,10 @@ export async function runSandboxStepBody(input, deps) {
421
444
  // status would attest an empty step. A blocker outcome keeps its own
422
445
  // reason. A capped-out step WITH artifacts stays on the completed path,
423
446
  // because partial output is real output.
424
- const blockerOutcome = blockerHolder.outcome;
447
+ //
448
+ // A replay does not rerun `execute`, so the cell is empty then; the
449
+ // transcript is the durable record and takes precedence over the cell.
450
+ const blockerOutcome = recordedBlocker(transcript) ?? blockerHolder.outcome;
425
451
  const cappedOutEmpty = hitMaxSteps && manifest.length === 0;
426
452
  if (blockerOutcome || cappedOutEmpty) {
427
453
  const blockedReason = blockerOutcome?.reason ?? CAPPED_OUT_EMPTY_REASON;
@@ -466,6 +492,8 @@ export async function runSandboxStepBody(input, deps) {
466
492
  input,
467
493
  session,
468
494
  transcript,
495
+ agent,
496
+ fileMetadata,
469
497
  writePrefix,
470
498
  sandboxId: sandbox.sandboxId,
471
499
  lineageCollector,
@@ -475,12 +503,13 @@ export async function runSandboxStepBody(input, deps) {
475
503
  // outputs are checkpointed (see the harness-durable-runtime spec): the conditional terminal emits they
476
504
  // gate (`data-step-summary`, file-tree) stay replay-stable and the billed
477
505
  // LLM calls are not re-issued on recovery. The remaining stages (walk /
478
- // reconcile / sync / index) stay inline — a separate follow-up.
479
- const metadataEntries = await safeRunValue(logger, () => DBOS.runStep(() => generateStepFileMetadata(deps, postCtx, manifest), {
506
+ // reconcile / sync / index) stay inline — a separate follow-up. The
507
+ // checkpoint keeps the exchange's messages so a replay's prefix matches.
508
+ const { entries: metadataEntries, messages: metadataMessages } = readStepFileMetadata(await safeRunValue(logger, () => DBOS.runStep(() => generateStepFileMetadata(deps, postCtx, manifest), {
480
509
  name: "post-step.generate-file-metadata",
481
- }), "post-step.metadata", []);
510
+ }), "post-step.metadata", NO_STEP_FILE_METADATA));
482
511
  await emitActivity("generating-summary", "Summarizing step results");
483
- const summary = await safeRunValue(logger, () => DBOS.runStep(() => generateStepSummaryAndWrite(deps, postCtx, manifest), {
512
+ const summary = await safeRunValue(logger, () => DBOS.runStep(() => generateStepSummaryAndWrite(deps, postCtx, manifest, metadataMessages), {
484
513
  name: "post-step.generate-step-summary",
485
514
  }), "post-step.summary", undefined);
486
515
  // Lineage attestation (registration) is fail-fast (see the artifact-manifest spec): unlike
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inflexa-ai/harness",
3
- "version": "0.39.2",
3
+ "version": "0.40.0",
4
4
  "description": "Host-agnostic bioinformatics agent harness — hand-rolled agent loop, DBOS-durable workflows, sandboxed compute.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -47,12 +47,12 @@
47
47
  "typecheck": "tsc --noEmit"
48
48
  },
49
49
  "dependencies": {
50
- "@ai-sdk/anthropic": "^4.0.53",
51
- "@ai-sdk/openai": "^4.0.66",
52
- "@ai-sdk/openai-compatible": "^3.0.48",
53
- "@ai-sdk/otel": "^1.0.99",
54
- "@ai-sdk/provider": "^4.0.14",
55
- "@ai-sdk/provider-utils": "5.0.40",
50
+ "@ai-sdk/anthropic": "^4.0.62",
51
+ "@ai-sdk/openai": "^4.0.74",
52
+ "@ai-sdk/openai-compatible": "^3.0.55",
53
+ "@ai-sdk/otel": "^1.0.113",
54
+ "@ai-sdk/provider": "^4.0.18",
55
+ "@ai-sdk/provider-utils": "5.0.47",
56
56
  "@anthropic-ai/sdk": "^0.116.0",
57
57
  "@dbos-inc/dbos-sdk": "^4.23.6",
58
58
  "@fontsource-variable/space-grotesk": "5.1.1",
@@ -69,7 +69,7 @@
69
69
  "@opentelemetry/sdk-trace-node": "^2.9.0",
70
70
  "@opentelemetry/semantic-conventions": "^1.43.0",
71
71
  "ag-grid-community": "36.1.0",
72
- "ai": "^7.0.99",
72
+ "ai": "^7.0.113",
73
73
  "cheerio": "^1.2.0",
74
74
  "dockerode": "^4.0.12",
75
75
  "echarts": "6.1.0",
@@ -95,7 +95,7 @@
95
95
  "uuid": "^11.1.1"
96
96
  },
97
97
  "devDependencies": {
98
- "@ai-sdk/amazon-bedrock": "^5.0.82",
98
+ "@ai-sdk/amazon-bedrock": "^5.0.93",
99
99
  "@eslint/js": "^10.0.1",
100
100
  "@types/bun": "latest",
101
101
  "@types/dockerode": "^3.3.47",
@@ -1,25 +0,0 @@
1
- /**
2
- * Compatibility entry point for Anthropic-backed chat.
3
- *
4
- * The production provider path is AI SDK-backed; this wrapper preserves the
5
- * old factory name for embedders while returning the new `ChatProvider` seam.
6
- */
7
- import type { Logger } from "../lib/logger.js";
8
- import { type ProviderHostPolicy } from "./ai-sdk.js";
9
- import type { ChatProvider, FetchLike } from "./types.js";
10
- export interface AnthropicProviderDeps extends ProviderHostPolicy {
11
- readonly baseURL?: string;
12
- readonly token: string;
13
- readonly model: string;
14
- readonly fetch?: FetchLike;
15
- readonly logger?: Logger;
16
- /** Output-token ceiling per request. Defaults to `DEFAULT_MAX_OUTPUT_TOKENS`. */
17
- readonly maxOutputTokens?: number;
18
- }
19
- /**
20
- * Convenience over the `anthropic` arm of the public `AiSdkProviderConfig`
21
- * union: it takes the Anthropic connection fields directly (`token` as the api
22
- * key) and delegates to `createConfiguredAiSdkProvider`. The same construction
23
- * contract holds — the `model` is bound into the returned provider.
24
- */
25
- export declare function createAnthropicProvider(deps: AnthropicProviderDeps): ChatProvider;