@inflexa-ai/harness 0.48.3 → 0.48.5

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 (98) hide show
  1. package/dist/agents/conversation-agent.js +5 -1
  2. package/dist/agents/sandbox/index.js +3 -0
  3. package/dist/agents/sandbox/mdv-preparation-agent.d.ts +9 -0
  4. package/dist/agents/sandbox/mdv-preparation-agent.js +37 -0
  5. package/dist/agents/sandbox/network-agent.js +1 -1
  6. package/dist/agents/sandbox/shared.js +3 -1
  7. package/dist/agents/sandbox/types.d.ts +1 -1
  8. package/dist/app/chat-turn-workflow.js +1 -0
  9. package/dist/app/chat-turn.d.ts +4 -2
  10. package/dist/app/chat-turn.js +46 -46
  11. package/dist/app/work.d.ts +7 -3
  12. package/dist/app/work.js +17 -16
  13. package/dist/contracts/chat-parts.d.ts +46 -5
  14. package/dist/contracts/chat-parts.js +2 -1
  15. package/dist/contracts/index.d.ts +1 -1
  16. package/dist/contracts/part-registry.js +1 -0
  17. package/dist/contracts/schemas/chat-parts.d.ts +168 -4
  18. package/dist/contracts/schemas/chat-parts.js +21 -1
  19. package/dist/execution/run-event-stream.d.ts +2 -2
  20. package/dist/index.d.ts +1 -1
  21. package/dist/lib/regulatory-corpus/fetch-ich.js +1 -16
  22. package/dist/lib/slug.d.ts +18 -0
  23. package/dist/lib/slug.js +29 -0
  24. package/dist/lib/test/pdf-fixture.d.ts +5 -0
  25. package/dist/lib/test/pdf-fixture.js +14 -0
  26. package/dist/loop/chat-stream.d.ts +4 -1
  27. package/dist/loop/chat-stream.js +30 -13
  28. package/dist/loop/run-loop.js +23 -35
  29. package/dist/loop/sub-agent.d.ts +2 -2
  30. package/dist/loop/sub-agent.js +1 -1
  31. package/dist/loop/test/metric-reader.d.ts +9 -0
  32. package/dist/loop/test/metric-reader.js +33 -0
  33. package/dist/loop/test/unnamed-model.d.ts +6 -0
  34. package/dist/loop/test/unnamed-model.js +24 -0
  35. package/dist/memory/conversation-display-recorder.d.ts +2 -0
  36. package/dist/memory/conversation-display-recorder.js +6 -2
  37. package/dist/memory/conversation-display-storage.d.ts +4 -2
  38. package/dist/memory/conversation-display-storage.js +19 -1
  39. package/dist/prompts/conversation.d.ts +1 -1
  40. package/dist/prompts/conversation.js +6 -4
  41. package/dist/prompts/sandbox/mdv-preparation-agent.d.ts +1 -0
  42. package/dist/prompts/sandbox/mdv-preparation-agent.js +56 -0
  43. package/dist/prompts/sandbox/network-agent.d.ts +1 -1
  44. package/dist/prompts/sandbox/network-agent.js +4 -0
  45. package/dist/providers/errors.js +2 -1
  46. package/dist/report-model/fixture-resolver.js +9 -135
  47. package/dist/report-model/production-resolver.d.ts +3 -3
  48. package/dist/report-model/production-resolver.js +12 -127
  49. package/dist/report-model/reference-read.d.ts +38 -0
  50. package/dist/report-model/reference-read.js +149 -0
  51. package/dist/report-model/reference-resolver.d.ts +7 -0
  52. package/dist/report-model/reference-resolver.js +1 -1
  53. package/dist/report-render/chart.js +48 -46
  54. package/dist/report-render/figures/common.d.ts +34 -0
  55. package/dist/report-render/figures/common.js +4 -1
  56. package/dist/report-render/figures/equal-units.js +2 -4
  57. package/dist/report-render/figures/sankey.js +1 -3
  58. package/dist/report-render/figures/upset.js +2 -5
  59. package/dist/runtime/assemble.js +2 -1
  60. package/dist/sandbox/execution-id.js +2 -14
  61. package/dist/sandbox/leases.js +46 -9
  62. package/dist/schemas/validate-plan.js +2 -14
  63. package/dist/state/active-turns.d.ts +6 -2
  64. package/dist/state/active-turns.js +11 -7
  65. package/dist/state/data-profile.d.ts +8 -0
  66. package/dist/state/data-profile.js +18 -0
  67. package/dist/state/index.d.ts +1 -1
  68. package/dist/state/index.js +1 -1
  69. package/dist/state/migrations/20261102120000_record_the_waiter_of_a_pause.d.ts +6 -0
  70. package/dist/state/migrations/20261102120000_record_the_waiter_of_a_pause.js +10 -0
  71. package/dist/state/migrations/index.js +2 -0
  72. package/dist/state/paused-work.d.ts +5 -3
  73. package/dist/state/paused-work.js +11 -7
  74. package/dist/state/runs.d.ts +3 -2
  75. package/dist/state/runs.js +4 -3
  76. package/dist/tasks/data-profile-index.js +3 -17
  77. package/dist/tasks/data-profile-resolve.js +3 -17
  78. package/dist/tasks/data-profile.js +1 -0
  79. package/dist/tools/bio/humanbase.d.ts +32 -0
  80. package/dist/tools/bio/humanbase.js +180 -0
  81. package/dist/tools/bio/index.d.ts +3 -1
  82. package/dist/tools/bio/index.js +3 -1
  83. package/dist/tools/bio/resolve-gene-ids.d.ts +13 -0
  84. package/dist/tools/bio/resolve-gene-ids.js +67 -0
  85. package/dist/tools/lib/humanbase-client.d.ts +215 -0
  86. package/dist/tools/lib/humanbase-client.js +187 -0
  87. package/dist/tools/lib/mygene-client.d.ts +150 -0
  88. package/dist/tools/lib/mygene-client.js +109 -0
  89. package/dist/tools/lib/opentargets-client.js +15 -25
  90. package/dist/tools/report-authoring/authoring-tools.d.ts +3 -3
  91. package/dist/tools/report-authoring/authoring-tools.js +7 -6
  92. package/dist/tools/research/generate-analogy-report.js +10 -2
  93. package/dist/tools/script/run-script.js +48 -51
  94. package/dist/workflows/execute-analysis.js +4 -3
  95. package/dist/workflows/pause.d.ts +3 -3
  96. package/dist/workflows/pause.js +15 -9
  97. package/dist/workflows/sandbox-step.js +1 -0
  98. package/package.json +7 -4
@@ -93,6 +93,59 @@ export declare const PresentationPartSchema: z.ZodObject<{
93
93
  version: z.ZodNumber;
94
94
  }, z.core.$strip>], "kind">;
95
95
  }, z.core.$strip>;
96
+ export declare const AnalogyReportPartSchema: z.ZodObject<{
97
+ type: z.ZodLiteral<"data-analogy-report">;
98
+ id: z.ZodString;
99
+ report: z.ZodUnion<readonly [z.ZodObject<{
100
+ problemSummary: z.ZodString;
101
+ problemObjects: z.ZodArray<z.ZodObject<{
102
+ name: z.ZodString;
103
+ role: z.ZodString;
104
+ }, z.core.$strip>>;
105
+ problemRelations: z.ZodArray<z.ZodString>;
106
+ keyTerms: z.ZodArray<z.ZodString>;
107
+ schemaVersion: z.ZodLiteral<"1">;
108
+ analogies: z.ZodArray<z.ZodObject<{
109
+ targetDomain: z.ZodString;
110
+ analogyTitle: z.ZodString;
111
+ objectMappings: z.ZodArray<z.ZodObject<{
112
+ source: z.ZodString;
113
+ target: z.ZodString;
114
+ rationale: z.ZodString;
115
+ }, z.core.$strip>>;
116
+ sharedRelations: z.ZodString;
117
+ coverage: z.ZodEnum<{
118
+ available: "available";
119
+ not_loaded: "not_loaded";
120
+ queried_no_data: "queried_no_data";
121
+ search_failed: "search_failed";
122
+ }>;
123
+ solutions: z.ZodArray<z.ZodObject<{
124
+ title: z.ZodString;
125
+ sourceDomain: z.ZodString;
126
+ description: z.ZodString;
127
+ keyConcepts: z.ZodArray<z.ZodString>;
128
+ relevance: z.ZodString;
129
+ sources: z.ZodArray<z.ZodObject<{
130
+ url: z.ZodURL;
131
+ title: z.ZodString;
132
+ }, z.core.$strip>>;
133
+ githubRepos: z.ZodArray<z.ZodObject<{
134
+ url: z.ZodURL;
135
+ description: z.ZodOptional<z.ZodString>;
136
+ }, z.core.$strip>>;
137
+ }, z.core.$strip>>;
138
+ }, z.core.$strip>>;
139
+ }, z.core.$strip>, z.ZodObject<{
140
+ schemaVersion: z.ZodLiteral<"1">;
141
+ error: z.ZodObject<{
142
+ kind: z.ZodEnum<{
143
+ "extraction-failed": "extraction-failed";
144
+ }>;
145
+ message: z.ZodString;
146
+ }, z.core.$strip>;
147
+ }, z.core.$strip>]>;
148
+ }, z.core.$strip>;
96
149
  export declare const PLAN_ID_RE: RegExp;
97
150
  export declare const PlanPartSchema: z.ZodObject<{
98
151
  type: z.ZodLiteral<"data-plan">;
@@ -600,6 +653,21 @@ export declare const PauseCauseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
600
653
  kind: z.ZodLiteral<"host">;
601
654
  reason: z.ZodString;
602
655
  }, z.core.$strip>], "kind">;
656
+ export declare const PauseWaiterSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
657
+ kind: z.ZodLiteral<"turn">;
658
+ }, z.core.$strip>, z.ZodObject<{
659
+ kind: z.ZodLiteral<"sub-agent">;
660
+ agentId: z.ZodString;
661
+ }, z.core.$strip>, z.ZodObject<{
662
+ kind: z.ZodLiteral<"step">;
663
+ stepId: z.ZodString;
664
+ }, z.core.$strip>, z.ZodObject<{
665
+ kind: z.ZodLiteral<"synthesis">;
666
+ }, z.core.$strip>, z.ZodObject<{
667
+ kind: z.ZodLiteral<"run">;
668
+ }, z.core.$strip>, z.ZodObject<{
669
+ kind: z.ZodLiteral<"profile">;
670
+ }, z.core.$strip>], "kind">;
603
671
  export declare const PausePartSchema: z.ZodObject<{
604
672
  type: z.ZodLiteral<"data-pause">;
605
673
  id: z.ZodString;
@@ -609,21 +677,43 @@ export declare const PausePartSchema: z.ZodObject<{
609
677
  run: "run";
610
678
  turn: "turn";
611
679
  }>;
680
+ waiter: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
681
+ kind: z.ZodLiteral<"turn">;
682
+ }, z.core.$strip>, z.ZodObject<{
683
+ kind: z.ZodLiteral<"sub-agent">;
684
+ agentId: z.ZodString;
685
+ }, z.core.$strip>, z.ZodObject<{
686
+ kind: z.ZodLiteral<"step">;
687
+ stepId: z.ZodString;
688
+ }, z.core.$strip>, z.ZodObject<{
689
+ kind: z.ZodLiteral<"synthesis">;
690
+ }, z.core.$strip>, z.ZodObject<{
691
+ kind: z.ZodLiteral<"run">;
692
+ }, z.core.$strip>, z.ZodObject<{
693
+ kind: z.ZodLiteral<"profile">;
694
+ }, z.core.$strip>], "kind">>;
612
695
  state: z.ZodEnum<{
613
696
  paused: "paused";
614
697
  retrying: "retrying";
615
698
  running: "running";
616
699
  }>;
617
- cause: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
700
+ cause: z.ZodDiscriminatedUnion<[z.ZodObject<{
618
701
  kind: z.ZodLiteral<"outage">;
619
702
  }, z.core.$strip>, z.ZodObject<{
620
703
  kind: z.ZodLiteral<"credential">;
621
704
  }, z.core.$strip>, z.ZodObject<{
622
705
  kind: z.ZodLiteral<"host">;
623
706
  reason: z.ZodString;
624
- }, z.core.$strip>], "kind">>;
707
+ }, z.core.$strip>], "kind">;
708
+ pausedAt: z.ZodString;
625
709
  attempt: z.ZodOptional<z.ZodNumber>;
626
710
  retryAt: z.ZodOptional<z.ZodString>;
711
+ endedAt: z.ZodOptional<z.ZodString>;
712
+ end: z.ZodOptional<z.ZodEnum<{
713
+ abort: "abort";
714
+ resume: "resume";
715
+ retry: "retry";
716
+ }>>;
627
717
  }, z.core.$strip>;
628
718
  /** Mirrors `ModelRefusalPart` without its `type`: the stored payload of the part. */
629
719
  export declare const ModelRefusalPayloadSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -720,6 +810,58 @@ export declare const ChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
720
810
  accession: z.ZodString;
721
811
  version: z.ZodNumber;
722
812
  }, z.core.$strip>], "kind">;
813
+ }, z.core.$strip>, z.ZodObject<{
814
+ type: z.ZodLiteral<"data-analogy-report">;
815
+ id: z.ZodString;
816
+ report: z.ZodUnion<readonly [z.ZodObject<{
817
+ problemSummary: z.ZodString;
818
+ problemObjects: z.ZodArray<z.ZodObject<{
819
+ name: z.ZodString;
820
+ role: z.ZodString;
821
+ }, z.core.$strip>>;
822
+ problemRelations: z.ZodArray<z.ZodString>;
823
+ keyTerms: z.ZodArray<z.ZodString>;
824
+ schemaVersion: z.ZodLiteral<"1">;
825
+ analogies: z.ZodArray<z.ZodObject<{
826
+ targetDomain: z.ZodString;
827
+ analogyTitle: z.ZodString;
828
+ objectMappings: z.ZodArray<z.ZodObject<{
829
+ source: z.ZodString;
830
+ target: z.ZodString;
831
+ rationale: z.ZodString;
832
+ }, z.core.$strip>>;
833
+ sharedRelations: z.ZodString;
834
+ coverage: z.ZodEnum<{
835
+ available: "available";
836
+ not_loaded: "not_loaded";
837
+ queried_no_data: "queried_no_data";
838
+ search_failed: "search_failed";
839
+ }>;
840
+ solutions: z.ZodArray<z.ZodObject<{
841
+ title: z.ZodString;
842
+ sourceDomain: z.ZodString;
843
+ description: z.ZodString;
844
+ keyConcepts: z.ZodArray<z.ZodString>;
845
+ relevance: z.ZodString;
846
+ sources: z.ZodArray<z.ZodObject<{
847
+ url: z.ZodURL;
848
+ title: z.ZodString;
849
+ }, z.core.$strip>>;
850
+ githubRepos: z.ZodArray<z.ZodObject<{
851
+ url: z.ZodURL;
852
+ description: z.ZodOptional<z.ZodString>;
853
+ }, z.core.$strip>>;
854
+ }, z.core.$strip>>;
855
+ }, z.core.$strip>>;
856
+ }, z.core.$strip>, z.ZodObject<{
857
+ schemaVersion: z.ZodLiteral<"1">;
858
+ error: z.ZodObject<{
859
+ kind: z.ZodEnum<{
860
+ "extraction-failed": "extraction-failed";
861
+ }>;
862
+ message: z.ZodString;
863
+ }, z.core.$strip>;
864
+ }, z.core.$strip>]>;
723
865
  }, z.core.$strip>, z.ZodObject<{
724
866
  type: z.ZodLiteral<"data-plan">;
725
867
  id: z.ZodString;
@@ -1087,21 +1229,43 @@ export declare const ChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1087
1229
  run: "run";
1088
1230
  turn: "turn";
1089
1231
  }>;
1232
+ waiter: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1233
+ kind: z.ZodLiteral<"turn">;
1234
+ }, z.core.$strip>, z.ZodObject<{
1235
+ kind: z.ZodLiteral<"sub-agent">;
1236
+ agentId: z.ZodString;
1237
+ }, z.core.$strip>, z.ZodObject<{
1238
+ kind: z.ZodLiteral<"step">;
1239
+ stepId: z.ZodString;
1240
+ }, z.core.$strip>, z.ZodObject<{
1241
+ kind: z.ZodLiteral<"synthesis">;
1242
+ }, z.core.$strip>, z.ZodObject<{
1243
+ kind: z.ZodLiteral<"run">;
1244
+ }, z.core.$strip>, z.ZodObject<{
1245
+ kind: z.ZodLiteral<"profile">;
1246
+ }, z.core.$strip>], "kind">>;
1090
1247
  state: z.ZodEnum<{
1091
1248
  paused: "paused";
1092
1249
  retrying: "retrying";
1093
1250
  running: "running";
1094
1251
  }>;
1095
- cause: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1252
+ cause: z.ZodDiscriminatedUnion<[z.ZodObject<{
1096
1253
  kind: z.ZodLiteral<"outage">;
1097
1254
  }, z.core.$strip>, z.ZodObject<{
1098
1255
  kind: z.ZodLiteral<"credential">;
1099
1256
  }, z.core.$strip>, z.ZodObject<{
1100
1257
  kind: z.ZodLiteral<"host">;
1101
1258
  reason: z.ZodString;
1102
- }, z.core.$strip>], "kind">>;
1259
+ }, z.core.$strip>], "kind">;
1260
+ pausedAt: z.ZodString;
1103
1261
  attempt: z.ZodOptional<z.ZodNumber>;
1104
1262
  retryAt: z.ZodOptional<z.ZodString>;
1263
+ endedAt: z.ZodOptional<z.ZodString>;
1264
+ end: z.ZodOptional<z.ZodEnum<{
1265
+ abort: "abort";
1266
+ resume: "resume";
1267
+ retry: "retry";
1268
+ }>>;
1105
1269
  }, z.core.$strip>, z.ZodObject<{
1106
1270
  type: z.ZodLiteral<"data-model-retry">;
1107
1271
  id: z.ZodString;
@@ -2,6 +2,7 @@
2
2
  * Zod schemas for chat data parts — validation at boundaries.
3
3
  */
4
4
  import { z } from "zod";
5
+ import { AnalogicalReasonerOutputSchema } from "../analogy-report.js";
5
6
  import { ToolCallOutcomeSchema } from "./chat-events.js";
6
7
  import { TokenUsageRollupSchema } from "./usage.js";
7
8
  // ── Presentation ────────────────────────────────────────────────────
@@ -77,6 +78,12 @@ export const PresentationPartSchema = z.object({
77
78
  title: z.string().optional(),
78
79
  content: PresentationContentSchema,
79
80
  });
81
+ // ── Analogy report ──────────────────────────────────────────────────
82
+ export const AnalogyReportPartSchema = z.object({
83
+ type: z.literal("data-analogy-report"),
84
+ id: z.string(),
85
+ report: AnalogicalReasonerOutputSchema,
86
+ });
80
87
  // ── Plan reference ──────────────────────────────────────────────────
81
88
  // oxlint-disable-next-line eslint-js/no-restricted-syntax -- the issued plan-id shape: the pln- prefix plus 8 hex digits.
82
89
  export const PLAN_ID_RE = /^pln-[a-f0-9]{8}$/;
@@ -365,15 +372,27 @@ export const PauseCauseSchema = z.discriminatedUnion("kind", [
365
372
  z.object({ kind: z.literal("credential") }),
366
373
  z.object({ kind: z.literal("host"), reason: z.string() }),
367
374
  ]);
375
+ export const PauseWaiterSchema = z.discriminatedUnion("kind", [
376
+ z.object({ kind: z.literal("turn") }),
377
+ z.object({ kind: z.literal("sub-agent"), agentId: z.string() }),
378
+ z.object({ kind: z.literal("step"), stepId: z.string() }),
379
+ z.object({ kind: z.literal("synthesis") }),
380
+ z.object({ kind: z.literal("run") }),
381
+ z.object({ kind: z.literal("profile") }),
382
+ ]);
368
383
  export const PausePartSchema = z.object({
369
384
  type: z.literal("data-pause"),
370
385
  id: z.string(),
371
386
  workId: z.string(),
372
387
  workKind: z.enum(["turn", "run", "profile"]),
388
+ waiter: PauseWaiterSchema.optional(),
373
389
  state: z.enum(["retrying", "paused", "running"]),
374
- cause: PauseCauseSchema.optional(),
390
+ cause: PauseCauseSchema,
391
+ pausedAt: z.string(),
375
392
  attempt: z.number().int().nonnegative().optional(),
376
393
  retryAt: z.string().optional(),
394
+ endedAt: z.string().optional(),
395
+ end: z.enum(["retry", "resume", "abort"]).optional(),
377
396
  });
378
397
  // ── Model refusal ───────────────────────────────────────────────────
379
398
  const ModelRefusalFallbackShape = { id: z.string(), outcome: z.literal("fallback"), model: z.string() };
@@ -413,6 +432,7 @@ export const SubAgentActivityPartSchema = z.object({
413
432
  // ── Union ───────────────────────────────────────────────────────────
414
433
  export const ChatPartSchema = z.discriminatedUnion("type", [
415
434
  PresentationPartSchema,
435
+ AnalogyReportPartSchema,
416
436
  PlanPartSchema,
417
437
  RunCardPartSchema,
418
438
  PlanApprovalPartSchema,
@@ -31,10 +31,10 @@
31
31
  * writer it observes.
32
32
  */
33
33
  import type { ResultAsync } from "neverthrow";
34
- import type { Pool } from "pg";
35
34
  import type { ChatPart } from "../contracts/chat-parts.js";
36
35
  import { type DbError } from "../lib/db-result.js";
37
36
  import type { Logger } from "../lib/logger.js";
37
+ import type { Querier } from "../state/db.js";
38
38
  import type { RunStatus } from "../state/schema.js";
39
39
  /** The part of a run row that the terminal part is made from. */
40
40
  export type RunEventRunRead = {
@@ -48,7 +48,7 @@ export type RunEventRunRead = {
48
48
  * having console forced on it.
49
49
  */
50
50
  export type RunEventStreamDeps = {
51
- readonly pool: Pool;
51
+ readonly pool: Querier;
52
52
  readonly logger?: Logger;
53
53
  /** Reads the status and the error of the run row, `null` when no row exists. Defaults to `queryRun` on `pool`. */
54
54
  readonly readRun?: (runId: string) => ResultAsync<RunEventRunRead | null, DbError>;
package/dist/index.d.ts CHANGED
@@ -108,7 +108,7 @@ export type { SubAgentActivityTracker } from "./contracts/subagent-activity.js";
108
108
  export type { TextPart, ToolCallPart, MessagePart, ChatMessage } from "./contracts/message.js";
109
109
  export type { TurnTerminal, ApplyFrameResult, ChatPartCheck } from "./contracts/chat-frame.js";
110
110
  export type { TokenUsageRollup } from "./contracts/usage.js";
111
- export type { ChatPart, PresentationPart, PresentationContent, PlanPart, RunCardPart, PlanApprovalPart, FileReferencePart, FileReferenceEntry, RunStartedPart, DagStatePart, DagStepState, PlanGraphStep, StepStatus, StepActivityPart, ActivityEntryPart, SubAgentActivityEntry, SubAgentActivityPart, StepPhase, StepFileTreePart, FileTreeEntry, StepOutputPart, StepOutputFile, StepSummaryPart, StepUsagePart, StepBlockedPart, RunSynthesisPart, FindingReference, SynthesizedFinding, BiologicalTheme, SynthesisProgressPart, SynthesisPhase, RunCompletedPart, RunCompletedFinding, RunFailedPart, CompactionPart, PauseCause, WorkKind, PausePart, ModelRetryPart, ModelRefusal, ModelRefusalPart, AskPart, ChildSessionStartedPart, ReportRenderedPart, } from "./contracts/chat-parts.js";
111
+ export type { ChatPart, PresentationPart, PresentationContent, PlanPart, RunCardPart, PlanApprovalPart, FileReferencePart, FileReferenceEntry, RunStartedPart, DagStatePart, DagStepState, PlanGraphStep, StepStatus, StepActivityPart, ActivityEntryPart, SubAgentActivityEntry, SubAgentActivityPart, StepPhase, StepFileTreePart, FileTreeEntry, StepOutputPart, StepOutputFile, StepSummaryPart, StepUsagePart, StepBlockedPart, RunSynthesisPart, FindingReference, SynthesizedFinding, BiologicalTheme, SynthesisProgressPart, SynthesisPhase, RunCompletedPart, RunCompletedFinding, RunFailedPart, CompactionPart, PauseCause, PauseWaiter, PauseEnd, WorkKind, PausePart, ModelRetryPart, ModelRefusal, ModelRefusalPart, AskPart, ChildSessionStartedPart, ReportRenderedPart, AnalogyReportPart, } from "./contracts/chat-parts.js";
112
112
  export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./contracts/part-registry.js";
113
113
  export type { ChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./contracts/part-registry.js";
114
114
  export { parseStructureUrl, alphafoldEntryUrl, alphafoldPredictionUrl } from "./contracts/structure-source.js";
@@ -12,6 +12,7 @@
12
12
  * `ich-<code>` with non-word chars sanitized.
13
13
  */
14
14
  import { readPdfText } from "../pdf-text.js";
15
+ import { slugify } from "../slug.js";
15
16
  import { normalizeWhitespace } from "./normalize-whitespace.js";
16
17
  /**
17
18
  * Curated catalog of ICH guidelines to index into the corpus.
@@ -157,19 +158,3 @@ export async function fetchAndExtractIchDoc(stub) {
157
158
  },
158
159
  };
159
160
  }
160
- function slugify(s) {
161
- let out = "";
162
- let inRun = false;
163
- for (const char of s.toLowerCase()) {
164
- const isSlugChar = (char >= "a" && char <= "z") || (char >= "0" && char <= "9");
165
- if (!isSlugChar) {
166
- inRun = true;
167
- continue;
168
- }
169
- if (inRun && out.length > 0)
170
- out += "-";
171
- inRun = false;
172
- out += char;
173
- }
174
- return out;
175
- }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The shared lowercase slug: each run of characters outside `[a-z0-9]` becomes one dash.
3
+ *
4
+ * The helper holds the loop alone; each caller states its own cap and its own empty-result fallback beside
5
+ * the call.
6
+ */
7
+ export type SlugifyOpts = {
8
+ /**
9
+ * The result never passes this length: the loop stops before the append that would cross it, and a
10
+ * final slice cuts a two-character append that straddled the cap. That slice keeps the dash, thus a
11
+ * capped result can end in a dash. A stop before an append cannot change the first characters of the
12
+ * result, because an append only extends the prefix.
13
+ */
14
+ maxLength?: number;
15
+ /** The result for an input with no slug character. Without a fallback the empty result stays empty. */
16
+ fallback?: string;
17
+ };
18
+ export declare function slugify(value: string, opts?: SlugifyOpts): string;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The shared lowercase slug: each run of characters outside `[a-z0-9]` becomes one dash.
3
+ *
4
+ * The helper holds the loop alone; each caller states its own cap and its own empty-result fallback beside
5
+ * the call.
6
+ */
7
+ export function slugify(value, opts = {}) {
8
+ const { maxLength, fallback } = opts;
9
+ let out = "";
10
+ let inRun = false;
11
+ for (const char of value.toLowerCase()) {
12
+ if (maxLength !== undefined && out.length >= maxLength)
13
+ break;
14
+ const isSlugChar = (char >= "a" && char <= "z") || (char >= "0" && char <= "9");
15
+ if (!isSlugChar) {
16
+ inRun = true;
17
+ continue;
18
+ }
19
+ if (inRun && out.length > 0)
20
+ out += "-";
21
+ inRun = false;
22
+ out += char;
23
+ }
24
+ if (maxLength !== undefined && out.length > maxLength)
25
+ out = out.slice(0, maxLength);
26
+ if (out === "" && fallback !== undefined)
27
+ return fallback;
28
+ return out;
29
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * A minimal single-font PDF with one text line per page, `latin1`-encoded. It carries just enough structure
3
+ * for the PDF text extractors of the suites to read one body line per page.
4
+ */
5
+ export declare function buildPdf(pageCount: number): Buffer;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A minimal single-font PDF with one text line per page, `latin1`-encoded. It carries just enough structure
3
+ * for the PDF text extractors of the suites to read one body line per page.
4
+ */
5
+ export function buildPdf(pageCount) {
6
+ const objects = ["1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj"];
7
+ const kids = Array.from({ length: pageCount }, (_, i) => `${4 + i * 2} 0 R`).join(" ");
8
+ objects.push(`2 0 obj<</Type/Pages/Kids[${kids}]/Count ${pageCount}>>endobj`, `3 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj`);
9
+ for (let i = 0; i < pageCount; i++) {
10
+ const content = `BT /F1 12 Tf 72 720 Td (Page ${i + 1} body text) Tj ET`;
11
+ objects.push(`${4 + i * 2} 0 obj<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]/Contents ${5 + i * 2} 0 R/Resources<</Font<</F1 3 0 R>>>>>>endobj`, `${5 + i * 2} 0 obj<</Length ${content.length}>>stream\n${content}\nendstream endobj`);
12
+ }
13
+ return Buffer.from(`%PDF-1.4\n${objects.join("\n")}\ntrailer<</Size ${3 + pageCount * 2}/Root 1 0 R>>`, "latin1");
14
+ }
@@ -16,7 +16,10 @@ import type { EmitFn } from "./types.js";
16
16
  export declare const CHAT_STREAM_KEY = "chat";
17
17
  /** The data part that names the child workflow of a sub-agent call in the stream of its caller. */
18
18
  export declare const SUB_AGENT_STREAM_PART = "data-subagent-stream";
19
- /** The chunk that carries one frame of the harness in the stream of a turn. A transient chunk is live only. */
19
+ /**
20
+ * The chunk that carries one frame of the harness in the stream of a turn. A transient chunk is in the stream, and
21
+ * a reader gets it. A replay of the step does not write it again, and the stored transcript does not hold it.
22
+ */
20
23
  export declare function chunkOfFrame(frame: ChatFrame, transient?: boolean): UIMessageChunk;
21
24
  /** What the body of a turn workflow writes to its stream, and what each of its tool steps writes. */
22
25
  export type TurnStreamWriter = {
@@ -28,13 +28,16 @@ const HarnessFrameChunkSchema = z.object({
28
28
  type: z.literal(HARNESS_FRAME_CHUNK),
29
29
  data: z.looseObject({ type: z.string() }),
30
30
  });
31
- /** The chunk that carries one frame of the harness in the stream of a turn. A transient chunk is live only. */
31
+ /**
32
+ * The chunk that carries one frame of the harness in the stream of a turn. A transient chunk is in the stream, and
33
+ * a reader gets it. A replay of the step does not write it again, and the stored transcript does not hold it.
34
+ */
32
35
  export function chunkOfFrame(frame, transient = false) {
33
36
  return transient ? { type: HARNESS_FRAME_CHUNK, data: frame, transient: true } : { type: HARNESS_FRAME_CHUNK, data: frame };
34
37
  }
35
38
  /**
36
- * Whether a frame from a tool step shows progress only. The library gives such a frame live, and a replay of the
37
- * step does not give it again. Each other frame of a tool step is checkpointed with the step, and the display of a
39
+ * Whether a frame from a step shows progress only. Such a frame goes to the stream at once, and a replay of the step
40
+ * does not write it again. Each other frame of a tool step is checkpointed with the step, and the display of a
38
41
  * round that a recovery stores keeps it: the end of each call, and each part of the root agent.
39
42
  */
40
43
  function isProgressFrame(frame) {
@@ -43,18 +46,27 @@ function isProgressFrame(frame) {
43
46
  return isKnownPartType(frame.type) && PART_REGISTRY[frame.type].transient;
44
47
  }
45
48
  /**
46
- * Run each body write of one workflow after the body write before it ends.
49
+ * Run each body write of one workflow after the body write before it ends, and each step write after the step write
50
+ * before it ends.
47
51
  *
48
52
  * DBOS gives a stream write its offset inside the insert, thus two writes in flight take the same offset, and the
49
53
  * write that loses sleeps 100 ms before it tries again. A body write must still take its function id at the call,
50
54
  * because a replay finds each checkpoint by the order of the calls. Thus the call reserves its id now, and the
51
- * chained write takes the reserved id from the context of the workflow when it starts.
55
+ * chained write takes the reserved id from the context of the workflow when it starts. A step write takes no
56
+ * function id, thus its chain reserves none.
52
57
  */
53
- function chainBodyWrites() {
54
- let tail = Promise.resolve();
58
+ function chainWrites() {
59
+ let bodyTail = Promise.resolve();
60
+ let stepTail = Promise.resolve();
61
+ const ended = (write) => write.then(() => undefined, () => undefined);
55
62
  return (start) => {
63
+ if (DBOS.isInStep()) {
64
+ const write = stepTail.then(start, start);
65
+ stepTail = ended(write);
66
+ return write;
67
+ }
56
68
  const ctx = getCurrentContextStore();
57
- if (ctx === undefined || !DBOS.isInWorkflow() || DBOS.isInStep())
69
+ if (ctx === undefined || !DBOS.isInWorkflow())
58
70
  return start();
59
71
  const reserved = functionIDGetIncrement();
60
72
  const run = () => {
@@ -71,8 +83,8 @@ function chainBodyWrites() {
71
83
  ctx.curWFFunctionId = next;
72
84
  }
73
85
  };
74
- const write = tail.then(run, run);
75
- tail = write.then(() => undefined, () => undefined);
86
+ const write = bodyTail.then(run, run);
87
+ bodyTail = ended(write);
76
88
  return write;
77
89
  };
78
90
  }
@@ -85,7 +97,7 @@ function chainBodyWrites() {
85
97
  */
86
98
  export function createTurnStreamWriter(rootSource, observe) {
87
99
  const pending = [];
88
- const chained = chainBodyWrites();
100
+ const chained = chainWrites();
89
101
  const track = (write) => {
90
102
  // Observed now, thus a failure before the settle is not an unhandled rejection. The settle still sees it.
91
103
  write.catch(() => undefined);
@@ -114,10 +126,15 @@ export function createTurnStreamWriter(rootSource, observe) {
114
126
  const frame = toChatFrame(event, rootSource);
115
127
  if (frame === null)
116
128
  return;
117
- // A tool step gives its frames to the library, which checkpoints each one that is not progress.
118
129
  if (DBOS.isInStep()) {
119
130
  const liveOnly = "transient" in event && event.transient === true;
120
- toolWriter().write(chunkOfFrame(frame, liveOnly || isProgressFrame(frame)));
131
+ const transient = liveOnly || isProgressFrame(frame);
132
+ // A model step has no library writer, and a transient chunk is not checkpointed with its step. Thus the
133
+ // chunk goes straight to the stream. The library checkpoints each other frame with its tool step.
134
+ if (transient)
135
+ writer.write(chunkOfFrame(frame, true));
136
+ else
137
+ toolWriter().write(chunkOfFrame(frame));
121
138
  return;
122
139
  }
123
140
  await write(frame);
@@ -526,6 +526,27 @@ async function runSeries(agent, opts, calls, log, target, spec) {
526
526
  const detail = computeDetail(tool, toolCall.input, log);
527
527
  return { detail: detail === undefined ? {} : { detail }, input: shownRoot ? viewInputValue(tool, toolCall.input, log) : undefined };
528
528
  };
529
+ /** The two events of a rejected tool call: the start names the call, and the finish states the outcome and the error text. */
530
+ const emitRejectedToolEvents = async (toolCall, shown, outcome, error) => {
531
+ await opts.emit({
532
+ type: "tool-started",
533
+ source,
534
+ toolUseId: toolCall.toolCallId,
535
+ name: toolCall.toolName,
536
+ ...shown.detail,
537
+ input: shown.input,
538
+ });
539
+ await opts.emit({
540
+ type: "tool-finished",
541
+ source,
542
+ toolUseId: toolCall.toolCallId,
543
+ name: toolCall.toolName,
544
+ outcome,
545
+ ...shown.detail,
546
+ input: shown.input,
547
+ error,
548
+ });
549
+ };
529
550
  const seriesSteps = [];
530
551
  let open = openStep();
531
552
  let failure;
@@ -561,24 +582,7 @@ async function runSeries(agent, opts, calls, log, target, spec) {
561
582
  if (refusal !== undefined) {
562
583
  // A refused call does not run, thus its two events come from here.
563
584
  const shown = callShownOf(toolCall);
564
- await opts.emit({
565
- type: "tool-started",
566
- source,
567
- toolUseId: toolCall.toolCallId,
568
- name: toolCall.toolName,
569
- ...shown.detail,
570
- input: shown.input,
571
- });
572
- await opts.emit({
573
- type: "tool-finished",
574
- source,
575
- toolUseId: toolCall.toolCallId,
576
- name: toolCall.toolName,
577
- outcome: "error",
578
- ...shown.detail,
579
- input: shown.input,
580
- error: shownRoot ? textToolValue(refusal) : undefined,
581
- });
585
+ await emitRejectedToolEvents(toolCall, shown, "error", shownRoot ? textToolValue(refusal) : undefined);
582
586
  return { type: "denied", reason: refusal };
583
587
  }
584
588
  let denial;
@@ -595,23 +599,7 @@ async function runSeries(agent, opts, calls, log, target, spec) {
595
599
  return undefined;
596
600
  deniedByTheUser.set(toolCall.toolCallId, denial);
597
601
  const shown = callShownOf(toolCall);
598
- await opts.emit({
599
- type: "tool-started",
600
- source,
601
- toolUseId: toolCall.toolCallId,
602
- name: toolCall.toolName,
603
- ...shown.detail,
604
- input: shown.input,
605
- });
606
- await opts.emit({
607
- type: "tool-finished",
608
- source,
609
- toolUseId: toolCall.toolCallId,
610
- name: toolCall.toolName,
611
- outcome: "denied",
612
- ...shown.detail,
613
- input: shown.input,
614
- });
602
+ await emitRejectedToolEvents(toolCall, shown, "denied", undefined);
615
603
  return { type: "denied", reason: denial };
616
604
  },
617
605
  stopWhen: () => stops(),
@@ -18,7 +18,7 @@
18
18
  * runs the body of the sub-agent in its own process.
19
19
  */
20
20
  import type { RunSession } from "../auth/types.js";
21
- import type { WorkKind, PausePart } from "../contracts/chat-parts.js";
21
+ import type { PauseWaiter, WorkKind, PausePart } from "../contracts/chat-parts.js";
22
22
  import type { ToolContext } from "../tools/define-tool.js";
23
23
  import type { LoopOptions } from "./run-loop.js";
24
24
  /** The options of the loop of a sub-agent that the place where it runs decides. */
@@ -48,7 +48,7 @@ export type SubAgentWork = {
48
48
  readonly runSession?: RunSession;
49
49
  };
50
50
  /** Gives the pause of the loops of a child, which writes its part through `emit`. The assembly gives it. */
51
- export type SubAgentPauses = (work: SubAgentWork, emit: (part: PausePart) => Promise<void>) => LoopOptions["pause"];
51
+ export type SubAgentPauses = (work: SubAgentWork, waiter: PauseWaiter, emit: (part: PausePart) => Promise<void>) => LoopOptions["pause"];
52
52
  /**
53
53
  * Run a sub-agent in the process of its caller, with no workflow: its loops fold their usage into the total of the
54
54
  * caller. A tool factory that a test builds many times takes this registrar, because DBOS registers a name one time.
@@ -78,7 +78,7 @@ export function registerSubAgent(name, body, pauses) {
78
78
  const source = { agentId: name, callPath: [...caller.callPath, name] };
79
79
  const pause = pauses === undefined || work === undefined
80
80
  ? undefined
81
- : pauses(work, async (part) => {
81
+ : pauses(work, { kind: "sub-agent", agentId: name }, async (part) => {
82
82
  await writer.emit({ type: "data-pause", source, data: part });
83
83
  });
84
84
  // A recovered child replays its model calls, and the usage middleware adds each one again. Thus the total
@@ -0,0 +1,9 @@
1
+ import { type MetricData } from "@opentelemetry/sdk-metrics";
2
+ export type MetricReader = {
3
+ /** Flush the provider and return the flat list of exported metrics. */
4
+ collect(): Promise<MetricData[]>;
5
+ /** Shut the provider down and unbind the global meter provider. */
6
+ stop(): Promise<void>;
7
+ };
8
+ /** Bind a meter provider over an in-memory exporter for one test; `stop` undoes both bindings after it. */
9
+ export declare function metricReader(): MetricReader;