@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
@@ -15,6 +15,19 @@ export declare const PlanStepSchema: z.ZodObject<{
15
15
  count: z.ZodNumber;
16
16
  }, z.core.$strip>>;
17
17
  }, z.core.$strip>>;
18
+ grounding: z.ZodOptional<z.ZodObject<{
19
+ status: z.ZodString;
20
+ snapshot: z.ZodString;
21
+ claims: z.ZodArray<z.ZodString>;
22
+ template: z.ZodOptional<z.ZodString>;
23
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
24
+ step: z.ZodString;
25
+ name: z.ZodString;
26
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
27
+ source: z.ZodOptional<z.ZodString>;
28
+ }, z.core.$strip>>>;
29
+ reason: z.ZodString;
30
+ }, z.core.$strip>>;
18
31
  maxSteps: z.ZodNumber;
19
32
  track: z.ZodOptional<z.ZodString>;
20
33
  step_type: z.ZodOptional<z.ZodString>;
@@ -106,6 +119,19 @@ export declare const PlanPartSchema: z.ZodObject<{
106
119
  count: z.ZodNumber;
107
120
  }, z.core.$strip>>;
108
121
  }, z.core.$strip>>;
122
+ grounding: z.ZodOptional<z.ZodObject<{
123
+ status: z.ZodString;
124
+ snapshot: z.ZodString;
125
+ claims: z.ZodArray<z.ZodString>;
126
+ template: z.ZodOptional<z.ZodString>;
127
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
128
+ step: z.ZodString;
129
+ name: z.ZodString;
130
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
131
+ source: z.ZodOptional<z.ZodString>;
132
+ }, z.core.$strip>>>;
133
+ reason: z.ZodString;
134
+ }, z.core.$strip>>;
109
135
  maxSteps: z.ZodNumber;
110
136
  track: z.ZodOptional<z.ZodString>;
111
137
  step_type: z.ZodOptional<z.ZodString>;
@@ -670,6 +696,19 @@ export declare const ChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
670
696
  count: z.ZodNumber;
671
697
  }, z.core.$strip>>;
672
698
  }, z.core.$strip>>;
699
+ grounding: z.ZodOptional<z.ZodObject<{
700
+ status: z.ZodString;
701
+ snapshot: z.ZodString;
702
+ claims: z.ZodArray<z.ZodString>;
703
+ template: z.ZodOptional<z.ZodString>;
704
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
705
+ step: z.ZodString;
706
+ name: z.ZodString;
707
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>;
708
+ source: z.ZodOptional<z.ZodString>;
709
+ }, z.core.$strip>>>;
710
+ reason: z.ZodString;
711
+ }, z.core.$strip>>;
673
712
  maxSteps: z.ZodNumber;
674
713
  track: z.ZodOptional<z.ZodString>;
675
714
  step_type: z.ZodOptional<z.ZodString>;
@@ -12,6 +12,23 @@ export const PlanStepSchema = z.object({
12
12
  question: z.string(),
13
13
  depends_on: z.array(z.string()),
14
14
  resources: z.object({ cpu: z.number(), memoryGb: z.number(), gpu: z.object({ count: z.number() }).optional() }).optional(),
15
+ grounding: z
16
+ .object({
17
+ status: z.string(),
18
+ snapshot: z.string(),
19
+ claims: z.array(z.string()),
20
+ template: z.string().optional(),
21
+ settings: z
22
+ .array(z.object({
23
+ step: z.string(),
24
+ name: z.string(),
25
+ value: z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
26
+ source: z.string().optional(),
27
+ }))
28
+ .optional(),
29
+ reason: z.string(),
30
+ })
31
+ .optional(),
15
32
  maxSteps: z.number(),
16
33
  track: z.string().optional(),
17
34
  step_type: z.string().optional(),
@@ -1,3 +1,3 @@
1
1
  export { PlanStepSchema, PresentationContentSchema, PresentationPartSchema, PlanPartSchema, RunCardPartSchema, PlanApprovalPartSchema, FileReferenceEntrySchema, FileReferencePartSchema, RunStartedPartSchema, StepStatusSchema, DagStepStateSchema, DagStatePartSchema, StepPhaseSchema, StepActivityPartSchema, ActivityEntryPartSchema, SubAgentActivityEntrySchema, SubAgentActivityPartSchema, FileTreeEntrySchema, StepFileTreePartSchema, StepOutputFileSchema, StepOutputPartSchema, StepSummaryPartSchema, StepUsagePartSchema, StepBlockedPartSchema, FindingReferenceSchema, SynthesizedFindingSchema, BiologicalThemeSchema, RunSynthesisPartSchema, SynthesisPhaseSchema, SynthesisProgressPartSchema, RunCompletedFindingSchema, RunCompletedPartSchema, RunFailedPartSchema, ChatPartSchema, } from "./chat-parts.js";
2
- export { EventSourceSchema, TextDeltaEventSchema, IterationEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, ChatEventSchema, } from "./chat-events.js";
2
+ export { EventSourceSchema, TextDeltaEventSchema, IterationEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, MessageStartEventSchema, ChatEventSchema, } from "./chat-events.js";
3
3
  export { TokenUsageRollupSchema } from "./usage.js";
@@ -1,3 +1,3 @@
1
1
  export { PlanStepSchema, PresentationContentSchema, PresentationPartSchema, PlanPartSchema, RunCardPartSchema, PlanApprovalPartSchema, FileReferenceEntrySchema, FileReferencePartSchema, RunStartedPartSchema, StepStatusSchema, DagStepStateSchema, DagStatePartSchema, StepPhaseSchema, StepActivityPartSchema, ActivityEntryPartSchema, SubAgentActivityEntrySchema, SubAgentActivityPartSchema, FileTreeEntrySchema, StepFileTreePartSchema, StepOutputFileSchema, StepOutputPartSchema, StepSummaryPartSchema, StepUsagePartSchema, StepBlockedPartSchema, FindingReferenceSchema, SynthesizedFindingSchema, BiologicalThemeSchema, RunSynthesisPartSchema, SynthesisPhaseSchema, SynthesisProgressPartSchema, RunCompletedFindingSchema, RunCompletedPartSchema, RunFailedPartSchema, ChatPartSchema, } from "./chat-parts.js";
2
- export { EventSourceSchema, TextDeltaEventSchema, IterationEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, ChatEventSchema, } from "./chat-events.js";
2
+ export { EventSourceSchema, TextDeltaEventSchema, IterationEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, MessageStartEventSchema, ChatEventSchema, } from "./chat-events.js";
3
3
  export { TokenUsageRollupSchema } from "./usage.js";
@@ -19,6 +19,7 @@
19
19
  * and queue rows each hold an `ON DELETE CASCADE` foreign key to
20
20
  * `workflow_status`, so they go with the status row.
21
21
  */
22
+ import { DBOSClient } from "@dbos-inc/dbos-sdk";
22
23
  import type { Pool } from "pg";
23
24
  import type { Logger } from "../lib/logger.js";
24
25
  import type { WorkflowPurger } from "./workflow-purger.js";
@@ -27,4 +28,5 @@ export interface DbosWorkflowPurgerDeps {
27
28
  readonly pool: Pool;
28
29
  readonly logger?: Logger;
29
30
  }
31
+ export declare function dbosClientFor(pool: Pool, logger: Logger): Promise<DBOSClient>;
30
32
  export declare function createDbosWorkflowPurger({ pool, logger: injected }: DbosWorkflowPurgerDeps): WorkflowPurger;
@@ -64,23 +64,30 @@ function asEngineLogger(logger) {
64
64
  error: (entry, metadata) => logger.error(render(entry), metadata?.stack === undefined ? undefined : { stack: metadata.stack }),
65
65
  };
66
66
  }
67
- export function createDbosWorkflowPurger({ pool, logger: injected }) {
68
- const logger = (injected ?? createNoopLogger()).named("workflow-purger");
69
- // One client per factory, not per call. Creating a client does no I/O, but the
70
- // client registers `error` and `connect` handlers on the pool it is handed, so a
71
- // client per purge would accumulate handler pairs on a long-lived pool. Its
72
- // `destroy()` ends that pool, so a client over an injected pool must never be
73
- // destroyed either — which leaves a per-call client nothing to release. Creation
74
- // is lazy so building a purger stays free for a host that never purges.
75
- let pending;
76
- const engine = () => {
67
+ /**
68
+ * One client for each pool, shared by every purger and by the run canceler. A client registers
69
+ * `error` and `connect` handlers on the pool it is handed, so a client for each caller would
70
+ * accumulate handler pairs on a long-lived pool. Its `destroy()` ends that pool, so a client over
71
+ * an injected pool must never be destroyed either — which leaves a per-call client nothing to
72
+ * release. Creation is lazy so a host that never reaches the engine builds no client. The logger of
73
+ * the first caller for a pool becomes the engine logger of that pool.
74
+ */
75
+ const clients = new WeakMap();
76
+ export function dbosClientFor(pool, logger) {
77
+ let client = clients.get(pool);
78
+ if (client === undefined) {
77
79
  // `create` never initializes the system database, and initialization is the
78
80
  // only path that reads the connection string once a pool is supplied — so the
79
81
  // url is unreachable from this client rather than merely untaken, and there is
80
- // none to thread through the seam.
81
- pending ??= DBOSClient.create({ systemDatabaseUrl: "", systemDatabasePool: pool, logger: asEngineLogger(logger) });
82
- return pending;
83
- };
82
+ // no url to pass.
83
+ client = DBOSClient.create({ systemDatabaseUrl: "", systemDatabasePool: pool, logger: asEngineLogger(logger) });
84
+ clients.set(pool, client);
85
+ }
86
+ return client;
87
+ }
88
+ export function createDbosWorkflowPurger({ pool, logger: injected }) {
89
+ const logger = (injected ?? createNoopLogger()).named("workflow-purger");
90
+ const engine = () => dbosClientFor(pool, logger);
84
91
  /**
85
92
  * Whether the engine's schema exists at all — the only thing that separates a
86
93
  * ledger the engine never created from one that is broken. It costs a round trip
@@ -1,18 +1,32 @@
1
1
  /**
2
2
  * RunCanceler — the encapsulated external-cancel path for an `executeAnalysis` run.
3
3
  *
4
- * A cancelled DBOS workflow can never execute another step, so the body's own
5
- * terminal block (`collectAndComplete`) is unreachable on external cancel and
6
- * nothing converges: the run row stays `running` (blocking same-plan relaunch
7
- * through `queryActiveRun`'s active-status dedup), pending step rows never
8
- * sweep, the running charge never closes, and the run mandate is never
9
- * revoked. This module is the host-side counterpart: cancel the engine's
10
- * parent + children, then converge each ledger the workflow would have.
4
+ * A cancelled DBOS workflow can never start another step, so the body's own
5
+ * terminal block (`collectAndComplete`) can be unreachable once the cancel lands
6
+ * and nothing converges: the run row stays `running` (blocking same-plan relaunch
7
+ * through `queryActiveRun`'s active-status dedup) and pending step rows never
8
+ * sweep. A step that started before the cancel still runs to its end, and its
9
+ * run status write is conditional on a `running` row. This module is the
10
+ * host-side counterpart: cancel the engine's parent + children, then converge
11
+ * the ledgers the workflow would have.
12
+ *
13
+ * The writer that wins the conditional terminal write of the run row owns the
14
+ * run end: the run emit, the charge close, and the mandate revoke. This module
15
+ * does those acts only when its write changed the row. A refused write means
16
+ * the body won the row and owns them; a failed write leaves the row `running`,
17
+ * so a second cancel converges the run. The step rows settle on every path.
18
+ *
19
+ * One exception: after a failed status write the body does the run end and
20
+ * records it as a workflow event (`run-end-record.ts`), while the row stays
21
+ * `running`. This module reads that record before its terminal write. A present
22
+ * record makes the terminal write carry the recorded status and error, and no
23
+ * act of the run end follows. A failed read writes nothing, so a second cancel
24
+ * converges the run.
11
25
  *
12
26
  * The engine capability stays internal — the production default is the
13
27
  * purger's `DBOSClient`-backed child-cascading cancel, which needs no launched
14
28
  * engine (see `dbos-workflow-purger.ts` for why the static `DBOS` facade is
15
- * the wrong tool here). `cancelWorkflows` is an optional test seam over it.
29
+ * the wrong tool here). `cancelWorkflows` is an optional injected function over it.
16
30
  *
17
31
  * No stream writes: `DBOS.writeStream` writes only from inside the workflow
18
32
  * that owns the stream, so the run-event reader (`run-event-stream.ts`)
@@ -22,6 +36,7 @@ import type { Pool } from "pg";
22
36
  import type { AgentSession } from "../auth/types.js";
23
37
  import type { RunCharge } from "../billing/run-charge.js";
24
38
  import type { Logger } from "../lib/logger.js";
39
+ import type { ProvenanceSeam } from "../provenance/seam.js";
25
40
  import type { RunStatus } from "../state/schema.js";
26
41
  import type { RunAuthorizer } from "./run-authorizer.js";
27
42
  export declare class UnknownRunError extends Error {
@@ -40,8 +55,10 @@ export interface CancelRunResult {
40
55
  * (the conditional write refuses to clobber it).
41
56
  */
42
57
  readonly finalStatus: RunStatus;
43
- /** What actually converged. `mandate` is vacuously true for a row with no
44
- * persisted jti — nothing to revoke, so hosts alert on any false flag. */
58
+ /** What actually converged. `charge` and `mandate` are vacuously true when
59
+ * there is nothing for this cancel to converge — a refused terminal write
60
+ * (the body owns them) and, for `mandate`, a row with no persisted jti — so
61
+ * hosts alert on any false flag. */
45
62
  readonly converged: {
46
63
  readonly steps: boolean;
47
64
  readonly charge: boolean;
@@ -53,9 +70,14 @@ export interface RunCancelerDeps {
53
70
  readonly runCharge: RunCharge;
54
71
  readonly runAuthorizer: RunAuthorizer;
55
72
  readonly logger?: Logger;
56
- /** Test seam over the engine cancel. Production default: the workflow
73
+ /** Receives the end of a run that this canceler cancels. An absent binding, or a binding with no run emit, emits nothing. */
74
+ readonly provenance?: ProvenanceSeam;
75
+ /** The engine cancel. Production default: the workflow
57
76
  * purger's `DBOSClient`-backed cancel, child-cascading and launch-free. */
58
77
  readonly cancelWorkflows?: (workflowIds: readonly string[]) => Promise<void>;
78
+ /** The run end that the body recorded: `null` when it recorded none, a rejection when the read fails.
79
+ * The value is unchecked engine data. Production default: `DBOSClient.getEvent` with a zero timeout. */
80
+ readonly readRecordedRunEnd?: (runId: string) => Promise<unknown>;
59
81
  }
60
82
  export interface RunCanceler {
61
83
  /**
@@ -1,18 +1,32 @@
1
1
  /**
2
2
  * RunCanceler — the encapsulated external-cancel path for an `executeAnalysis` run.
3
3
  *
4
- * A cancelled DBOS workflow can never execute another step, so the body's own
5
- * terminal block (`collectAndComplete`) is unreachable on external cancel and
6
- * nothing converges: the run row stays `running` (blocking same-plan relaunch
7
- * through `queryActiveRun`'s active-status dedup), pending step rows never
8
- * sweep, the running charge never closes, and the run mandate is never
9
- * revoked. This module is the host-side counterpart: cancel the engine's
10
- * parent + children, then converge each ledger the workflow would have.
4
+ * A cancelled DBOS workflow can never start another step, so the body's own
5
+ * terminal block (`collectAndComplete`) can be unreachable once the cancel lands
6
+ * and nothing converges: the run row stays `running` (blocking same-plan relaunch
7
+ * through `queryActiveRun`'s active-status dedup) and pending step rows never
8
+ * sweep. A step that started before the cancel still runs to its end, and its
9
+ * run status write is conditional on a `running` row. This module is the
10
+ * host-side counterpart: cancel the engine's parent + children, then converge
11
+ * the ledgers the workflow would have.
12
+ *
13
+ * The writer that wins the conditional terminal write of the run row owns the
14
+ * run end: the run emit, the charge close, and the mandate revoke. This module
15
+ * does those acts only when its write changed the row. A refused write means
16
+ * the body won the row and owns them; a failed write leaves the row `running`,
17
+ * so a second cancel converges the run. The step rows settle on every path.
18
+ *
19
+ * One exception: after a failed status write the body does the run end and
20
+ * records it as a workflow event (`run-end-record.ts`), while the row stays
21
+ * `running`. This module reads that record before its terminal write. A present
22
+ * record makes the terminal write carry the recorded status and error, and no
23
+ * act of the run end follows. A failed read writes nothing, so a second cancel
24
+ * converges the run.
11
25
  *
12
26
  * The engine capability stays internal — the production default is the
13
27
  * purger's `DBOSClient`-backed child-cascading cancel, which needs no launched
14
28
  * engine (see `dbos-workflow-purger.ts` for why the static `DBOS` facade is
15
- * the wrong tool here). `cancelWorkflows` is an optional test seam over it.
29
+ * the wrong tool here). `cancelWorkflows` is an optional injected function over it.
16
30
  *
17
31
  * No stream writes: `DBOS.writeStream` writes only from inside the workflow
18
32
  * that owns the stream, so the run-event reader (`run-event-stream.ts`)
@@ -22,9 +36,10 @@ import { createNoopLogger } from "../lib/console-logger.js";
22
36
  import { deliverNotice } from "../lib/hooks.js";
23
37
  import { elapsedSinceIso, recordRunCompleted, recordStepCompleted } from "../lib/metrics.js";
24
38
  import { unwrapOrThrow } from "../lib/result.js";
25
- import { markRunCanceledIfActive, queryRun } from "../state/runs.js";
26
- import { queryStepsByRun, sweepPendingStepExecutions } from "../state/step-executions.js";
27
- import { createDbosWorkflowPurger } from "./dbos-workflow-purger.js";
39
+ import { markRunCanceledIfActive, queryRun, updateRunStatus } from "../state/runs.js";
40
+ import { cancelRunningStepExecutions, queryStepsByRun, sweepPendingStepExecutions } from "../state/step-executions.js";
41
+ import { createDbosWorkflowPurger, dbosClientFor } from "./dbos-workflow-purger.js";
42
+ import { parseRecordedRunEnd, RUN_END_EVENT_KEY } from "./run-end-record.js";
28
43
  /** The reason stamped on the run row and the revoke — the same literal
29
44
  * `collectAndComplete` records for a cancel it observes from inside. */
30
45
  const EXTERNAL_CANCEL_REASON = "external_cancel";
@@ -52,9 +67,22 @@ export function createRunCanceler(deps) {
52
67
  })();
53
68
  await engineCancel(workflowIds);
54
69
  };
70
+ const readRecordedRunEnd = deps.readRecordedRunEnd ??
71
+ (async (runId) => (await dbosClientFor(pool, logger)).getEvent(runId, RUN_END_EVENT_KEY, 0));
55
72
  /** Steps whose child started (a persisted child workflow id) and has not written its terminal row. */
56
73
  const incompleteSteps = async (runId) => unwrapOrThrow(await queryStepsByRun(pool, runId)).filter((step) => step.childWorkflowId !== null && step.completedAt === null);
57
74
  const childIds = (steps) => steps.flatMap((step) => (step.childWorkflowId !== null ? [step.childWorkflowId] : []));
75
+ const emitRunEvent = deps.provenance?.emitRunEvent;
76
+ const emitGuarded = (event, session) => {
77
+ if (emitRunEvent === undefined)
78
+ return;
79
+ try {
80
+ emitRunEvent(event, session);
81
+ }
82
+ catch (err) {
83
+ logger.error("the run emit of the provenance binding threw", { runId: event.runId, event: event.type, ...logger.errorFields(err) });
84
+ }
85
+ };
58
86
  return {
59
87
  async cancel(runId, session) {
60
88
  const row = unwrapOrThrow(await queryRun(pool, runId));
@@ -89,38 +117,112 @@ export function createRunCanceler(deps) {
89
117
  catch (err) {
90
118
  logger.error("late-child cancel sweep failed", { runId, ...logger.errorFields(err) });
91
119
  }
92
- // Convergence — each phase isolated so one failure skips nothing after it.
93
- let transitioned = false;
120
+ // The run end that the body recorded after a failed status write. A value
121
+ // that is not a recorded run end counts as a failed read.
122
+ let recorded = null;
123
+ let readFailed = false;
94
124
  try {
95
- transitioned = unwrapOrThrow(await markRunCanceledIfActive(pool, runId, EXTERNAL_CANCEL_REASON));
125
+ const value = await readRecordedRunEnd(runId);
126
+ if (value !== null && value !== undefined) {
127
+ recorded = parseRecordedRunEnd(value);
128
+ if (recorded === null) {
129
+ readFailed = true;
130
+ logger.error("the recorded run end has the wrong shape", { runId });
131
+ }
132
+ }
96
133
  }
97
134
  catch (err) {
98
- logger.error("markRunCanceledIfActive failed", { runId, ...logger.errorFields(err) });
135
+ readFailed = true;
136
+ logger.error("the read of the recorded run end failed", { runId, ...logger.errorFields(err) });
137
+ }
138
+ // Convergence — each phase isolated so one failure skips nothing after it.
139
+ // The terminal write has three outcomes: changed (this cancel won the row),
140
+ // refused (the body won it), failed (the row is unchanged). A failed read of
141
+ // the recorded run end is a failed write that never ran.
142
+ let writeOutcome = "failed";
143
+ if (!readFailed) {
144
+ try {
145
+ const changed = recorded === null
146
+ ? unwrapOrThrow(await markRunCanceledIfActive(pool, runId, EXTERNAL_CANCEL_REASON))
147
+ : unwrapOrThrow(await updateRunStatus(pool, runId, recorded.status, recorded.error));
148
+ writeOutcome = changed ? "changed" : "refused";
149
+ }
150
+ catch (err) {
151
+ logger.error("the terminal write of the run failed", { runId, ...logger.errorFields(err) });
152
+ }
153
+ }
154
+ const transitioned = writeOutcome === "changed";
155
+ // A terminal step of the workflow that started before the cancel can still
156
+ // write, but its write is conditional on a `running` row too. The first
157
+ // write wins, and the run-end acts ride behind the write that won: a
158
+ // refused write means the run settled on its own and its own terminal step
159
+ // does them. A cut child never reached its terminal row, so its step
160
+ // records here too. A recorded run end means the body did the acts, so
161
+ // only the run metric rides behind the repair write.
162
+ if (transitioned && recorded !== null) {
163
+ recordRunCompleted({ workflow: "analysis", status: recorded.status, durationMs: elapsedSinceIso(row.startedAt) });
99
164
  }
100
- // The workflow's own terminal step never runs after a cancel, so this
101
- // conditional write is the one terminal write of an external cancel, and
102
- // the outcome metrics ride behind it: a refused write means the run
103
- // settled on its own and its own terminal step recorded them. A cut
104
- // child never reached its terminal row, so its step records here too.
105
- if (transitioned) {
165
+ if (transitioned && recorded === null) {
106
166
  recordRunCompleted({ workflow: "analysis", status: "canceled", durationMs: elapsedSinceIso(row.startedAt) });
107
167
  for (const step of cutSteps ?? [])
108
168
  recordStepCompleted({ agentId: step.agentId, status: "canceled" });
169
+ // The end of the run rides the same condition. One wall-clock read stamps every event:
170
+ // the canceler is not a workflow, so no replay fires these emits again.
171
+ const atMs = Date.now();
172
+ for (const step of cutSteps ?? []) {
173
+ const durationMs = elapsedSinceIso(step.startedAt, atMs);
174
+ emitGuarded({
175
+ type: "step_completed",
176
+ analysisId: row.analysisId,
177
+ runId,
178
+ stepId: step.stepId,
179
+ status: "canceled",
180
+ ...(durationMs !== undefined ? { durationMs } : {}),
181
+ atMs,
182
+ }, session);
183
+ }
184
+ emitGuarded({
185
+ type: "run_completed",
186
+ analysisId: row.analysisId,
187
+ runId,
188
+ status: "canceled",
189
+ atMs,
190
+ durationMs: Math.max(0, atMs - Date.parse(row.startedAt)),
191
+ }, session);
109
192
  }
110
- let steps = false;
193
+ let pendingSwept = false;
111
194
  try {
112
195
  unwrapOrThrow(await sweepPendingStepExecutions(pool, runId));
113
- steps = true;
196
+ pendingSwept = true;
114
197
  }
115
198
  catch (err) {
116
199
  logger.error("pending-step sweep failed", { runId, ...logger.errorFields(err) });
117
200
  }
118
- const charge = await deliverNotice(logger.with({ runId }), "RunCharge.close", runCharge.close({ analysisId: row.analysisId, runId, outcome: { kind: "canceled" }, session }));
119
- const mandate = row.mandateJti === null ||
120
- (await deliverNotice(logger.with({ runId, jti: row.mandateJti }), "RunAuthorizer.revokeByJti", runAuthorizer.revokeByJti({ jti: row.mandateJti, auth: session.auth }, EXTERNAL_CANCEL_REASON)));
201
+ let runningSettled = false;
202
+ try {
203
+ unwrapOrThrow(await cancelRunningStepExecutions(pool, runId, EXTERNAL_CANCEL_REASON));
204
+ runningSettled = true;
205
+ }
206
+ catch (err) {
207
+ logger.error("running-step settle failed", { runId, ...logger.errorFields(err) });
208
+ }
209
+ const steps = pendingSwept && runningSettled;
210
+ // Only the writer that won the row closes the charge and revokes. A refused
211
+ // write left both to the body; a failed write left the row `running`, so a
212
+ // second cancel converges the run. The flags of a refused write are true
213
+ // because there is nothing for this cancel to converge. With a recorded run
214
+ // end the body did both acts, and the flags are its results.
215
+ let charge = recorded !== null ? recorded.closed : writeOutcome === "refused";
216
+ let mandate = recorded !== null ? recorded.revoked : writeOutcome === "refused" || (writeOutcome === "failed" && row.mandateJti === null);
217
+ if (transitioned && recorded === null) {
218
+ charge = await deliverNotice(logger.with({ runId }), "RunCharge.close", runCharge.close({ analysisId: row.analysisId, runId, outcome: { kind: "canceled" }, session }));
219
+ mandate =
220
+ row.mandateJti === null ||
221
+ (await deliverNotice(logger.with({ runId, jti: row.mandateJti }), "RunAuthorizer.revokeByJti", runAuthorizer.revokeByJti({ jti: row.mandateJti, auth: session.auth }, EXTERNAL_CANCEL_REASON)));
222
+ }
121
223
  // No transition means the run reached a terminal state on its own (or the
122
224
  // write failed) — report the row as it stands rather than claiming `canceled`.
123
- let finalStatus = "canceled";
225
+ let finalStatus = recorded?.status ?? "canceled";
124
226
  if (!transitioned) {
125
227
  const reread = unwrapOrThrow(await queryRun(pool, runId));
126
228
  finalStatus = reread?.status ?? "canceled";
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The workflow event under which the body of `executeAnalysis` records its run
4
+ * end after a failed status write. The run canceler reads it with
5
+ * `DBOSClient.getEvent`.
6
+ */
7
+ export declare const RUN_END_EVENT_KEY = "run-end";
8
+ /**
9
+ * The run end that the body did: the status and the error that its failed
10
+ * status write tried to write, and the results of the charge close and of the
11
+ * revoke.
12
+ */
13
+ export declare const RecordedRunEndSchema: z.ZodObject<{
14
+ status: z.ZodEnum<{
15
+ failed: "failed";
16
+ completed: "completed";
17
+ partial: "partial";
18
+ canceled: "canceled";
19
+ suspended_insufficient_funds: "suspended_insufficient_funds";
20
+ }>;
21
+ error: z.ZodNullable<z.ZodString>;
22
+ closed: z.ZodBoolean;
23
+ revoked: z.ZodBoolean;
24
+ }, z.core.$strip>;
25
+ export type RecordedRunEnd = z.infer<typeof RecordedRunEndSchema>;
26
+ /**
27
+ * The engine hands back deserialized data, thus a value of an event is unknown
28
+ * until this check. A value of the wrong shape gives `null`.
29
+ */
30
+ export declare function parseRecordedRunEnd(value: unknown): RecordedRunEnd | null;
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import { RunStatus } from "../state/schema.js";
3
+ /**
4
+ * The workflow event under which the body of `executeAnalysis` records its run
5
+ * end after a failed status write. The run canceler reads it with
6
+ * `DBOSClient.getEvent`.
7
+ */
8
+ export const RUN_END_EVENT_KEY = "run-end";
9
+ /**
10
+ * The run end that the body did: the status and the error that its failed
11
+ * status write tried to write, and the results of the charge close and of the
12
+ * revoke.
13
+ */
14
+ export const RecordedRunEndSchema = z.object({
15
+ status: RunStatus.exclude(["running"]),
16
+ error: z.string().nullable(),
17
+ closed: z.boolean(),
18
+ revoked: z.boolean(),
19
+ });
20
+ /**
21
+ * The engine hands back deserialized data, thus a value of an event is unknown
22
+ * until this check. A value of the wrong shape gives `null`.
23
+ */
24
+ export function parseRecordedRunEnd(value) {
25
+ const parsed = RecordedRunEndSchema.safeParse(value);
26
+ return parsed.success ? parsed.data : null;
27
+ }
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ export type { ThreadAgentResolver, UnregisteredThreadType } from "./runtime/asse
17
17
  export { createReportSessionSpawn } from "./app/spawn-report-session.js";
18
18
  export type { ReportSessionSpawn, ReportSessionSpawnDeps, ReportSessionPaging, SpawnRefusal, ReportBrief, ReportSessionDelta, NewestReportChild, } from "./app/spawn-report-session.js";
19
19
  export { launchPlanRun } from "./tools/execute-analysis.js";
20
- export type { LaunchPlanRunDeps, LaunchPlanRunRefusal, PlanLaunch } from "./tools/execute-analysis.js";
20
+ export type { LaunchPlanRunDeps, LaunchPlanRunInput, LaunchPlanRunRefusal, PlanLaunch } from "./tools/execute-analysis.js";
21
21
  export { approvePlan } from "./app/approve-plan.js";
22
22
  export type { ApprovePlanDeps, ApprovePlanInput, ApprovePlanRefusal, PlanApproval } from "./app/approve-plan.js";
23
23
  export type { EnsureSessionStateResult } from "./app/report-session-runtime.js";
@@ -52,10 +52,14 @@ export type { WorkflowPurger } from "./execution/workflow-purger.js";
52
52
  export { createRunCanceler, UnknownRunError } from "./execution/run-canceler.js";
53
53
  export type { RunCanceler, RunCancelerDeps, CancelRunResult } from "./execution/run-canceler.js";
54
54
  export { defineTool, isToolError } from "./tools/define-tool.js";
55
+ export { createHttpKnowledgeClient, createKnowledgeRecommendTool, createKnowledgeCheckTool, createKnowledgeTools, knowledgeToolDefinitionHash, } from "./tools/knowledge/index.js";
56
+ export type { KnowledgeClient, KnowledgeSituation, HttpKnowledgeClientConfig } from "./tools/knowledge/index.js";
55
57
  export type { Tool, ToolDefinition, ToolContext, ToolError } from "./tools/define-tool.js";
56
58
  export { normalizeDetail, DETAIL_MAX_LENGTH } from "./loop/tool-detail.js";
57
59
  export { createCitationResolver } from "./citations/resolve.js";
58
60
  export type { CitationResolverConfig, CitationResolverDependencies, CitationResolverSourceConfig } from "./citations/resolve.js";
61
+ export { createSearxngEngine } from "./tools/research/searxng-engine.js";
62
+ export type { WebSearchEngine } from "./tools/research/web-search.js";
59
63
  export { CitationKindSchema, CitationInputSchema, CitationSourceSchema, CitationSourceStatusSchema, CitationResolutionResultSchema, CitationVerdictSchema, CitationCoverageSchema, ComparisonStatusSchema, CitationFieldSchema, UnsupportedWorkKindSchema, CitationIdentifiersSchema, NormalizedCitationMetadataSchema, NormalizedCitationSchema, CitationRecordSchema, IdentifierEvidenceSchema, CitationSourceOutcomeSchema, CitationFieldComparisonSchema, CitationConflictSchema, CitationCandidateClusterSchema, CitationClusterRelationSchema, CitationSourceOperationSchema, CitationSourcePlanItemSchema, } from "./citations/types.js";
60
64
  export type { CitationKind, CitationInput, CitationSource, CitationSourceStatus, CitationResolver, CitationResolveOptions, CitationResolutionResult, CitationVerdict, CitationCoverage, ComparisonStatus, CitationField, UnsupportedWorkKind, CitationIdentifiers, NormalizedCitationMetadata, NormalizedCitation, CitationSourceOutcome, CitationRecord, IdentifierEvidence, CitationFieldComparison, CitationConflict, CitationCandidateCluster, CitationSourceClient, CitationSourceRequest, CitationSourceOperation, CitationSourcePlanItem, RegistrationAgencyEvidence, } from "./citations/types.js";
61
65
  export { createAskGateway } from "./tools/approval/gateway.js";
@@ -91,14 +95,14 @@ export type { ChatTurnOutcome, ChatTurnRan, ChatTurnRefusal, ChatTurnResult, Cha
91
95
  export { createThreadStore } from "./memory/thread-store.js";
92
96
  export type { ThreadStore, Thread, ThreadType, ThreadInputError, CreateThreadInput, ListThreadsInput, ListRecentThreadsInput, ThreadPage, } from "./memory/thread-store.js";
93
97
  export { createThreadHistory, conversationRecordTurn } from "./memory/thread-history.js";
94
- export type { ThreadHistory, StoredMessage, RetractOutcome, ConversationTurn, TurnWrite, TurnWriteResult, TurnClose, TurnStatus, StoredTurnRecord, } from "./memory/thread-history.js";
98
+ export type { ThreadHistory, StoredMessage, LoadPageOptions, TurnPage, RetractOutcome, ConversationTurn, TurnWrite, TurnWriteResult, TurnClose, TurnStatus, StoredTurnRecord, } from "./memory/thread-history.js";
95
99
  export { syntheticUserMessage, syntheticRecordMessage, isSyntheticUserMessage, isSyntheticRecordMessage } from "./memory/ai-sdk-message-storage.js";
96
100
  export { createConversationDisplayRecorder } from "./memory/conversation-display-recorder.js";
97
101
  export type { ConversationDisplayRecorder, ConversationDisplayRecorderOptions } from "./memory/conversation-display-recorder.js";
98
102
  export { envelopeDisplayMessages, parseStoredDisplayEnvelope } from "./memory/conversation-display-storage.js";
99
103
  export type { ConversationDisplayMetadata, ConversationUIData, ConversationUIMessage, StoredDisplayEnvelope } from "./memory/conversation-display-storage.js";
100
104
  export { storedMessagesToChat } from "./memory/conversation-display-replay.js";
101
- export type { ChatEvent, ChatFrame, ChatPartFrame, TextDeltaEvent, IterationEvent, ToolStartedEvent, ToolFinishedEvent, ToolOutcome, ToolCallOutcome, ToolCallDetail, FinishEvent, ChatErrorEvent, } from "./contracts/chat-events.js";
105
+ export type { ChatEvent, ChatFrame, ChatPartFrame, TextDeltaEvent, IterationEvent, ToolStartedEvent, ToolFinishedEvent, ToolOutcome, ToolCallOutcome, ToolCallDetail, FinishEvent, ChatErrorEvent, MessageStartEvent, } from "./contracts/chat-events.js";
102
106
  export { toChatFrame, applyChatFrame, checkChatPart } from "./contracts/chat-frame.js";
103
107
  export { createSubAgentActivityTracker, SUBAGENT_ACTIVITY_MAX_ENTRIES } from "./contracts/subagent-activity.js";
104
108
  export type { SubAgentActivityTracker } from "./contracts/subagent-activity.js";
@@ -141,7 +145,7 @@ export type { DataProfileStatus } from "./state/data-profile.js";
141
145
  export { queryLatestRunsByAnalyses, queryDataProfileStatusByAnalyses, queryRunProgressByRuns, queryRunsEndedSince } from "./state/analyses-metrics.js";
142
146
  export type { DataProfileSummary, EndedRunSummary, LatestRunSummary, RunProgressSummary } from "./state/analyses-metrics.js";
143
147
  export { queryArtifactPage, countArtifactsByRuns } from "./state/artifacts.js";
144
- export type { ArtifactPage, ArtifactPageEntry, ArtifactPageQuery, ArtifactPageSort, RunArtifactCount } from "./state/artifacts.js";
148
+ export type { ArtifactExtensionCount, ArtifactPage, ArtifactPageEntry, ArtifactPageQuery, ArtifactPageSort, RunArtifactCount } from "./state/artifacts.js";
145
149
  export { readRunSynthesis } from "./execution/run-synthesis.js";
146
150
  export type { ReadSynthesisInput } from "./execution/run-synthesis.js";
147
151
  export { DIMENSION_CATEGORIES, DIMENSION_CATEGORY_IDS, DIMENSION_PROBES, DIMENSION_PROBE_IDS, GROUP_CATEGORIES, GROUP_CATEGORY_IDS, GROUP_ROLES, GROUP_ROLE_IDS, PROBE_OUTCOME_IDS, dimensionCategoryEntry, dimensionScope, groupCategoryEntry, } from "./contracts/profile-vocabulary.js";
@@ -191,7 +195,7 @@ export type { ValidatePlanOptions } from "./schemas/validate-plan.js";
191
195
  export type { ValidationResult } from "./schemas/validate-plan.js";
192
196
  export { upsertPlan, loadPlan, loadPlanRecord } from "./state/plans.js";
193
197
  export type { UpsertPlanInput, PlanRecord } from "./state/plans.js";
194
- export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, queryRunIdsByPlan, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
198
+ export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, countRunsByAnalysis, queryRunIdsByPlan, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
195
199
  export type { InsertRunInput, RunReservation } from "./state/runs.js";
196
200
  export { queryStepsByRun } from "./state/step-executions.js";
197
201
  export type { CortexRunRow, StepExecutionRow, RunStatus, TerminalRunStatus } from "./state/schema.js";
package/dist/index.js CHANGED
@@ -70,6 +70,10 @@ export { createDbosWorkflowPurger } from "./execution/dbos-workflow-purger.js";
70
70
  export { createRunCanceler, UnknownRunError } from "./execution/run-canceler.js";
71
71
  // Tool primitive.
72
72
  export { defineTool, isToolError } from "./tools/define-tool.js";
73
+ // The knowledge plane: an embedder binds a client at its composition root
74
+ // (or none), and it can hand `knowledge_recommend` to the conversation agent
75
+ // through `hostTools`.
76
+ export { createHttpKnowledgeClient, createKnowledgeRecommendTool, createKnowledgeCheckTool, createKnowledgeTools, knowledgeToolDefinitionHash, } from "./tools/knowledge/index.js";
73
77
  // Tool-call-detail authoring aids for an embedder that contributes a host tool.
74
78
  // A `describeCall` hook that pre-empts truncation — a count in place of a
75
79
  // mid-value cut that would name a file that does not exist — must gate on the
@@ -81,6 +85,12 @@ export { defineTool, isToolError } from "./tools/define-tool.js";
81
85
  export { normalizeDetail, DETAIL_MAX_LENGTH } from "./loop/tool-detail.js";
82
86
  // Host-agnostic citation verification service and its public contracts.
83
87
  export { createCitationResolver } from "./citations/resolve.js";
88
+ // The web-search engine type and the SearXNG realization. An embedder cannot
89
+ // build its composition root without these two names: it constructs the engine
90
+ // and types the `webSearch` field of `ConversationAgentDeps` (the front-door
91
+ // rule of the harness-embedder-exports spec). The tools stay off the barrel —
92
+ // the conversation agent constructs them itself.
93
+ export { createSearxngEngine } from "./tools/research/searxng-engine.js";
84
94
  export { CitationKindSchema, CitationInputSchema, CitationSourceSchema, CitationSourceStatusSchema, CitationResolutionResultSchema, CitationVerdictSchema, CitationCoverageSchema, ComparisonStatusSchema, CitationFieldSchema, UnsupportedWorkKindSchema, CitationIdentifiersSchema, NormalizedCitationMetadataSchema, NormalizedCitationSchema, CitationRecordSchema, IdentifierEvidenceSchema, CitationSourceOutcomeSchema, CitationFieldComparisonSchema, CitationConflictSchema, CitationCandidateClusterSchema, CitationClusterRelationSchema, CitationSourceOperationSchema, CitationSourcePlanItemSchema, } from "./citations/types.js";
85
95
  // Seam: tool approval (`ctx.ask`). `createAskGateway` realizes the `Ask` seam
86
96
  // over the injected `Pool` and carries the outward `answer`/`pending` API plus
@@ -296,7 +306,7 @@ export { validatePlan } from "./schemas/validate-plan.js";
296
306
  // caller-derived id and inserts-if-absent (the deterministic-id intake path);
297
307
  // the run-state calls mirror the chat trigger's reserve → dedup → status flow.
298
308
  export { upsertPlan, loadPlan, loadPlanRecord } from "./state/plans.js";
299
- export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, queryRunIdsByPlan, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
309
+ export { insertRun, reserveRunById, queryActiveRun, queryActiveRunsByAnalysis, updateRunStatus, markRunCanceledIfActive, queryRun, queryRunsByAnalysis, countRunsByAnalysis, queryRunIdsByPlan, RunDedupCollisionError, RunIdentityCollisionError, } from "./state/runs.js";
300
310
  export { queryStepsByRun } from "./state/step-executions.js";
301
311
  // Host-neutral reference-data catalog and shared installation receipts. Each
302
312
  // artifact names the third-party upstream it is fetched from; embedders own all