@inflexa-ai/harness 0.43.1 → 0.45.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 (119) hide show
  1. package/dist/agents/report-session-agent.d.ts +1 -1
  2. package/dist/app/approve-plan.d.ts +48 -0
  3. package/dist/app/approve-plan.js +84 -0
  4. package/dist/app/data-profile-view.d.ts +1 -1
  5. package/dist/app/run-activity.js +4 -6
  6. package/dist/app/synthesize-run.js +1 -1
  7. package/dist/contracts/chat-events.d.ts +2 -0
  8. package/dist/contracts/chat-frame.d.ts +7 -0
  9. package/dist/contracts/chat-frame.js +18 -4
  10. package/dist/contracts/chat-parts.d.ts +73 -2
  11. package/dist/contracts/chat-parts.js +3 -1
  12. package/dist/contracts/index.d.ts +3 -1
  13. package/dist/contracts/index.js +1 -0
  14. package/dist/contracts/part-registry.js +3 -0
  15. package/dist/contracts/schemas/chat-events.d.ts +13 -0
  16. package/dist/contracts/schemas/chat-events.js +1 -0
  17. package/dist/contracts/schemas/chat-parts.d.ts +200 -15
  18. package/dist/contracts/schemas/chat-parts.js +63 -12
  19. package/dist/contracts/schemas/index.d.ts +1 -1
  20. package/dist/contracts/schemas/index.js +1 -1
  21. package/dist/contracts/subagent-activity.d.ts +12 -0
  22. package/dist/contracts/subagent-activity.js +76 -0
  23. package/dist/execution/artifact-metadata.js +1 -3
  24. package/dist/execution/post-step-pipeline.js +1 -1
  25. package/dist/execution/run-canceler.js +1 -1
  26. package/dist/execution/run-event-parts.d.ts +6 -5
  27. package/dist/execution/run-event-parts.js +6 -5
  28. package/dist/execution/run-event-stream.d.ts +18 -6
  29. package/dist/execution/run-event-stream.js +67 -17
  30. package/dist/execution/run-synthesis.d.ts +21 -0
  31. package/dist/execution/run-synthesis.js +77 -3
  32. package/dist/index.d.ts +24 -10
  33. package/dist/index.js +17 -3
  34. package/dist/lib/hooks.d.ts +1 -1
  35. package/dist/lib/metrics.d.ts +2 -2
  36. package/dist/loop/run-agent.js +1 -0
  37. package/dist/loop/types.d.ts +2 -0
  38. package/dist/memory/card-builders.d.ts +11 -0
  39. package/dist/memory/card-builders.js +35 -21
  40. package/dist/memory/conversation-display-recorder.d.ts +2 -0
  41. package/dist/memory/conversation-display-recorder.js +10 -1
  42. package/dist/memory/conversation-display-storage.d.ts +9 -2
  43. package/dist/memory/conversation-display-storage.js +18 -3
  44. package/dist/memory/thread-history.d.ts +8 -1
  45. package/dist/memory/thread-history.js +13 -3
  46. package/dist/memory/thread-store.d.ts +13 -0
  47. package/dist/memory/thread-store.js +15 -1
  48. package/dist/prompts/conversation.d.ts +1 -1
  49. package/dist/prompts/conversation.js +3 -1
  50. package/dist/provenance/seam.d.ts +16 -5
  51. package/dist/providers/ai-sdk.js +6 -4
  52. package/dist/reference-data/receipt.d.ts +16 -4
  53. package/dist/reference-data/receipt.js +20 -3
  54. package/dist/report-model/pin-snapshot.d.ts +1 -1
  55. package/dist/report-model/pin-snapshot.js +4 -52
  56. package/dist/runtime/assemble.d.ts +9 -2
  57. package/dist/runtime/assemble.js +13 -2
  58. package/dist/runtime/boot.d.ts +3 -0
  59. package/dist/runtime/boot.js +10 -1
  60. package/dist/sandbox/client.d.ts +1 -1
  61. package/dist/sandbox/create-sandbox.js +1 -1
  62. package/dist/sandbox/docker-client.js +1 -1
  63. package/dist/sandbox/k8s-client.js +5 -5
  64. package/dist/sandbox/sandbox-step-translate.d.ts +23 -0
  65. package/dist/sandbox/sandbox-step-translate.js +24 -0
  66. package/dist/schemas/artifact-manifest.d.ts +1 -1
  67. package/dist/schemas/artifact-manifest.js +11 -9
  68. package/dist/schemas/plan-schemas.d.ts +18 -18
  69. package/dist/schemas/run-synthesis.d.ts +2 -2
  70. package/dist/state/analyses-metrics.d.ts +79 -7
  71. package/dist/state/analyses-metrics.js +141 -6
  72. package/dist/state/artifacts.d.ts +50 -3
  73. package/dist/state/artifacts.js +67 -7
  74. package/dist/state/data-profile.d.ts +4 -2
  75. package/dist/state/data-profile.js +7 -5
  76. package/dist/state/index.d.ts +9 -8
  77. package/dist/state/index.js +5 -5
  78. package/dist/state/migrations/20261012120000_index_the_runs_by_start.d.ts +8 -0
  79. package/dist/state/migrations/20261012120000_index_the_runs_by_start.js +12 -0
  80. package/dist/state/migrations/20261013120000_index_the_ended_runs_and_the_recent_threads.d.ts +8 -0
  81. package/dist/state/migrations/20261013120000_index_the_ended_runs_and_the_recent_threads.js +13 -0
  82. package/dist/state/migrations/20261013180000_narrow_the_active_run_index.d.ts +8 -0
  83. package/dist/state/migrations/20261013180000_narrow_the_active_run_index.js +13 -0
  84. package/dist/state/migrations/20261014120000_index_the_plans_by_parent_and_the_runs_by_plan.d.ts +8 -0
  85. package/dist/state/migrations/20261014120000_index_the_plans_by_parent_and_the_runs_by_plan.js +13 -0
  86. package/dist/state/migrations/index.js +8 -0
  87. package/dist/state/plans.d.ts +21 -0
  88. package/dist/state/plans.js +25 -0
  89. package/dist/state/runs.d.ts +36 -5
  90. package/dist/state/runs.js +65 -19
  91. package/dist/state/schema.d.ts +2 -0
  92. package/dist/tasks/data-profile-activity.d.ts +7 -1
  93. package/dist/tasks/data-profile-activity.js +18 -9
  94. package/dist/tasks/data-profile.d.ts +15 -1
  95. package/dist/tasks/data-profile.js +18 -13
  96. package/dist/tools/approval/gateway.js +28 -5
  97. package/dist/tools/display/show-user.d.ts +1 -1
  98. package/dist/tools/execute-analysis.d.ts +51 -0
  99. package/dist/tools/execute-analysis.js +241 -109
  100. package/dist/tools/report-session/derive-table.js +1 -1
  101. package/dist/tools/report-session/examine-page.js +1 -1
  102. package/dist/tools/report-session/list-artifacts.js +2 -2
  103. package/dist/tools/report-session/preview-report.d.ts +1 -1
  104. package/dist/tools/report-session/preview-report.js +6 -6
  105. package/dist/tools/report-session/record-version.d.ts +1 -1
  106. package/dist/tools/report-session/record-version.js +4 -4
  107. package/dist/tools/research/inspect-data-profile.d.ts +1 -1
  108. package/dist/tools/research/inspect-run.d.ts +1 -1
  109. package/dist/tools/research/inspect-run.js +7 -7
  110. package/dist/tools/workspace/mutator.js +2 -2
  111. package/dist/workflows/execute-analysis.d.ts +4 -3
  112. package/dist/workflows/execute-analysis.js +38 -25
  113. package/dist/workflows/plan/graph.d.ts +16 -0
  114. package/dist/workflows/plan/graph.js +36 -0
  115. package/dist/workflows/sandbox-step.d.ts +2 -2
  116. package/dist/workflows/sandbox-step.js +16 -14
  117. package/dist/workspace/filesystem.js +18 -22
  118. package/dist/workspace/paths.d.ts +7 -4
  119. package/package.json +4 -4
@@ -94,7 +94,7 @@ export interface ReportSessionAgentDeps {
94
94
  readonly makeResolver?: (scope: {
95
95
  analysisId: string;
96
96
  auth: AuthContext;
97
- }) => ReferenceResolver;
97
+ }) => Promise<ReferenceResolver>;
98
98
  /**
99
99
  * Page-asset lookup -- the preview tool maps the module specifier of a manifest
100
100
  * entry onto a file on disk. Omitted falls back to the module resolution of the
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Approve a stored plan by its id, with no model call.
3
+ *
4
+ * A host calls this when a person approves a plan. The function refuses a thread or a plan that does
5
+ * not belong to the analysis, and a plan that a newer plan replaced. Then it starts the run of the plan,
6
+ * emits the `approve-plan` provenance event, and appends one record to the thread. The record tells the
7
+ * model that the run started, and it shows the person the approval and the run card.
8
+ *
9
+ * The function is an API boundary: it gives a `Result` for each outcome and never rejects for one. The
10
+ * host gives the identity and the auth of the session, because the harness forwards the auth and never
11
+ * mints it. The harness gives the provenance of the session.
12
+ */
13
+ import { ResultAsync } from "neverthrow";
14
+ import type { AuthContext, Identity } from "../auth/types.js";
15
+ import type { ChatMessage } from "../contracts/message.js";
16
+ import { type ProvenanceSeam } from "../provenance/seam.js";
17
+ import { type LaunchPlanRunDeps, type LaunchPlanRunRefusal } from "../tools/execute-analysis.js";
18
+ /** The deps of an approval: the deps of the launch, and the provenance sink of the host. */
19
+ export type ApprovePlanDeps = LaunchPlanRunDeps & {
20
+ readonly provenance?: ProvenanceSeam;
21
+ };
22
+ export type ApprovePlanInput = {
23
+ analysisId: string;
24
+ threadId: string;
25
+ planId: string;
26
+ identity: Identity;
27
+ auth: AuthContext;
28
+ };
29
+ /**
30
+ * The outcome of an approval. `started` is false when a run of the plan was already active: the
31
+ * approval then changed nothing, and `message` is `null`. `message` is also `null` when the record
32
+ * could not be appended, because the run started anyway. It has no `createdAt`: the transcript read
33
+ * adds the time of the row.
34
+ */
35
+ export type PlanApproval = {
36
+ planId: string;
37
+ runId: string;
38
+ started: boolean;
39
+ message: ChatMessage | null;
40
+ };
41
+ export type ApprovePlanRefusal = LaunchPlanRunRefusal | {
42
+ type: "thread_not_found";
43
+ } | {
44
+ type: "superseded";
45
+ supersededBy: string;
46
+ };
47
+ /** Approve the plan `planId` on the thread `threadId` of the analysis, and start its run. */
48
+ export declare function approvePlan(deps: ApprovePlanDeps, input: ApprovePlanInput): ResultAsync<PlanApproval, ApprovePlanRefusal>;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Approve a stored plan by its id, with no model call.
3
+ *
4
+ * A host calls this when a person approves a plan. The function refuses a thread or a plan that does
5
+ * not belong to the analysis, and a plan that a newer plan replaced. Then it starts the run of the plan,
6
+ * emits the `approve-plan` provenance event, and appends one record to the thread. The record tells the
7
+ * model that the run started, and it shows the person the approval and the run card.
8
+ *
9
+ * The function is an API boundary: it gives a `Result` for each outcome and never rejects for one. The
10
+ * host gives the identity and the auth of the session, because the harness forwards the auth and never
11
+ * mints it. The harness gives the provenance of the session.
12
+ */
13
+ import { ResultAsync, err, ok } from "neverthrow";
14
+ import { createNoopLogger } from "../lib/console-logger.js";
15
+ import { buildRunCardData } from "../memory/card-builders.js";
16
+ import { conversationUIToChatMessages } from "../memory/conversation-display-storage.js";
17
+ import { conversationRecordTurn, createThreadHistory } from "../memory/thread-history.js";
18
+ import { createThreadStore } from "../memory/thread-store.js";
19
+ import { bindSessionEmit } from "../provenance/seam.js";
20
+ import { loadPlanRecord } from "../state/index.js";
21
+ import { launchPlanRun } from "../tools/execute-analysis.js";
22
+ const APPROVAL_PROVENANCE = { agentId: "plan-approval", callPath: ["plan-approval"] };
23
+ function storeFailed(cause) {
24
+ return err({ type: "store_failed", cause });
25
+ }
26
+ /** The refusals that need no launch: a thread or a plan that does not belong, and a replaced plan. */
27
+ async function checkApprovable(deps, input) {
28
+ const read = await ResultAsync.combine([
29
+ createThreadStore(deps.pool).getThread(input.threadId),
30
+ loadPlanRecord(deps.pool, input.planId, { analysisId: input.analysisId }),
31
+ ]);
32
+ if (read.isErr())
33
+ return storeFailed(read.error);
34
+ const [thread, record] = read.value;
35
+ if (thread === null || thread.analysisId !== input.analysisId)
36
+ return err({ type: "thread_not_found" });
37
+ if (record === null)
38
+ return err({ type: "plan_not_found", planId: input.planId });
39
+ if (record.supersededBy !== null)
40
+ return err({ type: "superseded", supersededBy: record.supersededBy });
41
+ return ok(undefined);
42
+ }
43
+ async function approve(deps, input) {
44
+ const logger = (deps.logger ?? createNoopLogger()).named("approve-plan");
45
+ const { analysisId, threadId, planId } = input;
46
+ const approvable = await checkApprovable(deps, input);
47
+ if (approvable.isErr())
48
+ return err(approvable.error);
49
+ // Read before the launch: the kernel writes the approval at this time, and the run writes
50
+ // `run_started` from its workflow body after the launch, so the approval precedes the start.
51
+ const approvedAtMs = Date.now();
52
+ const session = {
53
+ identity: input.identity,
54
+ auth: input.auth,
55
+ scope: { kind: "analysis", analysisId, threadId },
56
+ provenance: APPROVAL_PROVENANCE,
57
+ };
58
+ const launched = await launchPlanRun(deps, { session, planId });
59
+ if (launched.isErr())
60
+ return err(launched.error);
61
+ const { runId, started } = launched.value;
62
+ if (!started)
63
+ return ok({ planId, runId, started: false, message: null });
64
+ bindSessionEmit(deps.provenance, logger)({ type: "approve-plan", analysisId, threadId, planId, runId, atMs: approvedAtMs });
65
+ const card = await buildRunCardData(deps.pool, { planId, analysisId, runId }).match((data) => data, (cause) => {
66
+ logger.error("the run card of an approval could not be read", { analysisId, threadId, planId, runId, ...logger.errorFields(cause) });
67
+ return null;
68
+ });
69
+ const approval = { type: "data-plan-approval", planId, runId, approvedAt: new Date(approvedAtMs).toISOString() };
70
+ const turn = conversationRecordTurn(`The person approved plan ${planId}. Run ${runId} started.`, [
71
+ approval,
72
+ ...(card === null ? [] : [{ type: "data-run-card", ...card }]),
73
+ ]);
74
+ const appended = await createThreadHistory(deps.pool, logger).appendTurn(threadId, turn);
75
+ if (appended.isErr()) {
76
+ logger.error("the approval record could not be appended", { analysisId, threadId, planId, runId, ...logger.errorFields(appended.error) });
77
+ return ok({ planId, runId, started: true, message: null });
78
+ }
79
+ return ok({ planId, runId, started: true, message: conversationUIToChatMessages(turn.displayMessages)[0] ?? null });
80
+ }
81
+ /** Approve the plan `planId` on the thread `threadId` of the analysis, and start its run. */
82
+ export function approvePlan(deps, input) {
83
+ return new ResultAsync(approve(deps, input));
84
+ }
@@ -65,6 +65,6 @@ export declare function profileFileRecords(result: DataProfileResult): DataProfi
65
65
  * rows fall back to coverage, then to summed kind counts, then to `null`: reporting the
66
66
  * described-file count would be a dataset size the row cannot support.
67
67
  */
68
- export declare function profileDatasetFileCount(result: DataProfileResult): number | null;
68
+ export declare function profileDatasetFileCount(result: Pick<DataProfileResult, "partition" | "coverage" | "kinds">): number | null;
69
69
  /** Dataset-wide findings the agent wrote, from whichever field the snapshot carries them in. */
70
70
  export declare function profileCaveats(result: DataProfileResult): string[];
@@ -4,21 +4,19 @@
4
4
  */
5
5
  /** Maximum detailed run rows paid into every conversation turn. */
6
6
  export const RUN_ACTIVITY_DETAIL_LIMIT = 20;
7
- function renderRows(label, rows) {
7
+ function renderRows(rows) {
8
8
  if (rows.length === 0)
9
9
  return [];
10
- return [`${label}:`, ...rows.map((run) => `- runId: ${run.runId} | planId: ${run.planId ?? "none"} | startedAt: ${run.startedAt}`)];
10
+ return ["Running:", ...rows.map((run) => `- runId: ${run.runId} | planId: ${run.planId ?? "none"} | startedAt: ${run.startedAt}`)];
11
11
  }
12
12
  /** Render the bounded run-activity snapshot of a conversation turn. */
13
13
  export function renderRunActivity(activity) {
14
14
  const lines = ["[Run Activity]"];
15
15
  if (activity.total === 0) {
16
- lines.push("No runs are currently running or suspended.");
16
+ lines.push("No runs are currently running.");
17
17
  return lines.join("\n");
18
18
  }
19
- const running = activity.runs.filter((run) => run.status === "running");
20
- const suspended = activity.runs.filter((run) => run.status === "suspended_insufficient_funds");
21
- lines.push(...renderRows("Running", running), ...renderRows("Suspended", suspended));
19
+ lines.push(...renderRows(activity.runs.filter((run) => run.status === "running")));
22
20
  const omitted = activity.total - activity.runs.length;
23
21
  if (omitted > 0) {
24
22
  lines.push(`Showing ${activity.runs.length} of ${activity.total} non-terminal runs; ${omitted} omitted. Use inspect_run to page the full list.`);
@@ -26,7 +26,7 @@ export async function synthesizeRun(deps, params) {
26
26
  const { analysisId, runId, completedSteps, session, emit, onProgress } = params;
27
27
  await onProgress("starting", "Beginning literature-grounded synthesis");
28
28
  try {
29
- const workspaceRoot = resolveWorkspaceRoot(analysisId);
29
+ const workspaceRoot = await resolveWorkspaceRoot(analysisId);
30
30
  const summaries = await loadStepSummariesFromDisk({
31
31
  workspaceRoot,
32
32
  runId,
@@ -20,6 +20,8 @@ import type { TokenUsageRollup } from "./usage.js";
20
20
  export interface EventSource {
21
21
  agentId: string;
22
22
  callPath: string[];
23
+ /** The id of the tool call that runs this loop. For a data profile, the workflow id of its attempt. */
24
+ invocationId?: string;
23
25
  }
24
26
  /** A run of assistant text. Deltas accumulate into the turn's reply. */
25
27
  export interface TextDeltaEvent {
@@ -16,6 +16,13 @@ export type ChatPartCheck = {
16
16
  readonly ok: false;
17
17
  readonly error: string;
18
18
  };
19
+ /**
20
+ * The wire shape of a data part, `{ ...data, type }`, which is the flat shape of the part contracts. The chat stream
21
+ * and the run streams use this one rule.
22
+ */
23
+ export declare function flattenDataPart(part: Pick<ChatDataPart, "type" | "data">): {
24
+ type: `data-${string}`;
25
+ } & Record<string, unknown>;
19
26
  /**
20
27
  * The frame of one emitted event, or `null` for `done` and for an `iteration` of the root agent. A frame of a sub-agent
21
28
  * keeps its source, thus a consumer can filter it. A `text-delta` has no source, thus its frame gets `fallbackSource`,
@@ -3,7 +3,22 @@ import { isReconciling, PART_REGISTRY } from "./part-registry.js";
3
3
  import { EventSourceSchema } from "./schemas/chat-events.js";
4
4
  import { ChatPartSchema } from "./schemas/chat-parts.js";
5
5
  function toSource(source) {
6
- return { agentId: source.agentId, callPath: [...source.callPath] };
6
+ return {
7
+ agentId: source.agentId,
8
+ callPath: [...source.callPath],
9
+ ...(source.invocationId === undefined ? {} : { invocationId: source.invocationId }),
10
+ };
11
+ }
12
+ /**
13
+ * The wire shape of a data part, `{ ...data, type }`, which is the flat shape of the part contracts. The chat stream
14
+ * and the run streams use this one rule.
15
+ */
16
+ export function flattenDataPart(part) {
17
+ // The payload is `unknown`, and the spread is not checked here. The chat stream checks each frame with `checkChatPart`.
18
+ // On the run stream the producer builds the payload with the fields of its part contract, and the synthesis-sink test
19
+ // parses the result with `RunSynthesisPartSchema`.
20
+ const data = (part.data ?? {});
21
+ return { ...data, type: part.type };
7
22
  }
8
23
  /**
9
24
  * The frame of one emitted event, or `null` for `done` and for an `iteration` of the root agent. A frame of a sub-agent
@@ -39,10 +54,9 @@ export function toChatFrame(event, fallbackSource) {
39
54
  case "text-delta":
40
55
  return { type: "text-delta", text: event.text, source: toSource(fallbackSource) };
41
56
  default: {
42
- // A `ChatDataPart`, whose payload the emitter types as `unknown`. The wire part is flat: `{ type, ...data }`.
43
57
  // The cast names the frame that the type claims. `checkChatPart` is the check.
44
- const data = (event.data ?? {});
45
- return { ...data, type: event.type, ...(event.source === undefined ? {} : { source: toSource(event.source) }) };
58
+ const part = flattenDataPart(event);
59
+ return { ...part, ...(event.source === undefined ? {} : { source: toSource(event.source) }) };
46
60
  }
47
61
  }
48
62
  }
@@ -5,13 +5,16 @@
5
5
  * Categories:
6
6
  * Presentation: data-presentation (agent-synthesized content),
7
7
  * data-plan (plan by id), data-file-reference (files by path)
8
- * Approval: data-ask (a tool's pending user-approval prompt)
8
+ * Approval: data-ask (a tool's pending user-approval prompt),
9
+ * data-plan-approval (the record of an approved plan)
9
10
  * Compaction: data-compaction (a compaction of the conversation thread)
10
11
  * Run lifecycle: run-started, dag-state, run-completed, run-failed, run-synthesis,
11
12
  * synthesis-progress
12
13
  * Per-step live: step-activity, step-file-tree
14
+ * Activity history: activity-entry (run stream), subagent-activity (conversation)
13
15
  * Per-step final: step-output, step-summary, step-usage
14
16
  */
17
+ import type { ToolCallOutcome } from "./chat-events.js";
15
18
  import type { TokenUsageRollup } from "./usage.js";
16
19
  export interface PlanStep {
17
20
  id: string;
@@ -78,6 +81,8 @@ export interface PlanPart {
78
81
  type: "data-plan";
79
82
  id: string;
80
83
  planId: string;
84
+ /** The plan that this plan revised. Absent for a first plan. */
85
+ parentPlanId?: string;
81
86
  title?: string;
82
87
  steps?: PlanStep[];
83
88
  analytical_narrative?: string;
@@ -92,6 +97,14 @@ export interface RunCardPart {
92
97
  title: string;
93
98
  stepCount: number;
94
99
  }
100
+ export interface PlanApprovalPart {
101
+ type: "data-plan-approval";
102
+ planId: string;
103
+ /** The run that the approval started. */
104
+ runId: string;
105
+ /** ISO 8601. The instant of the approval, equal to the time of the `approve-plan` provenance event. */
106
+ approvedAt: string;
107
+ }
95
108
  export interface FileReferenceEntry {
96
109
  path: string;
97
110
  runId?: string;
@@ -119,6 +132,8 @@ export interface AskPart {
119
132
  /** Optional additional detail a surface may render. */
120
133
  detail?: string;
121
134
  status: "pending" | "resolved" | "rejected" | "aborted" | "expired";
135
+ /** The kind of the ledger reply. Only a `resolved` or `rejected` part carries it, and never the rejection feedback. */
136
+ reply?: "once" | "always" | "reject";
122
137
  }
123
138
  export interface RunStartedPart {
124
139
  type: "data-run-started";
@@ -152,6 +167,8 @@ export interface DagStepState {
152
167
  /** Error message (set on failure). */
153
168
  error?: string;
154
169
  }
170
+ /** One step of the stored plan graph: the fields of {@link DagStepState} that the plan alone fixes. */
171
+ export type PlanGraphStep = Pick<DagStepState, "id" | "name" | "agent" | "dependsOn" | "level">;
155
172
  export interface DagStatePart {
156
173
  type: "data-dag-state";
157
174
  /** Stable ID for reconciliation — same across all updates for a run. */
@@ -176,6 +193,24 @@ export interface StepActivityPart {
176
193
  phase: StepPhase;
177
194
  /** Human-readable activity description (e.g., "Running DESeq2 analysis"). */
178
195
  activity: string;
196
+ /** ISO 8601 time of the emission. Absent on a part that an older harness wrote. */
197
+ at?: string;
198
+ }
199
+ /**
200
+ * One activity emission of a step or a data profile, kept in the run stream with no reconciliation. The fold
201
+ * delivers each entry in write order.
202
+ */
203
+ export interface ActivityEntryPart {
204
+ type: "data-activity-entry";
205
+ /** Unique per emission within a stream. */
206
+ id: string;
207
+ runId: string;
208
+ stepId: string;
209
+ /** A `SynthesisPhase` for the entries of the synthesis step, a `StepPhase` for each other step. */
210
+ phase: StepPhase | SynthesisPhase;
211
+ activity: string;
212
+ /** ISO 8601 time of the emission. */
213
+ at: string;
179
214
  }
180
215
  export interface FileTreeEntry {
181
216
  path: string;
@@ -290,6 +325,12 @@ export interface RunCompletedPart {
290
325
  */
291
326
  usage?: TokenUsageRollup;
292
327
  }
328
+ export interface FindingReference {
329
+ pmid: string;
330
+ citation: string;
331
+ relevance: string;
332
+ concordance: "supports" | "contradicts" | "extends" | "contextualizes";
333
+ }
293
334
  export interface SynthesizedFinding {
294
335
  stepId: string;
295
336
  title: string;
@@ -297,6 +338,7 @@ export interface SynthesizedFinding {
297
338
  confidence: "high" | "medium" | "low";
298
339
  noveltyStatus: "novel" | "confirmed" | "partially_confirmed" | "contradicted" | "expected";
299
340
  literatureInterpretation: string;
341
+ references: FindingReference[];
300
342
  }
301
343
  export interface BiologicalTheme {
302
344
  name: string;
@@ -336,6 +378,8 @@ export interface SynthesisProgressPart {
336
378
  phase: SynthesisPhase;
337
379
  /** Human-readable activity description. */
338
380
  activity: string;
381
+ /** ISO 8601 time of the emission. Absent in a stream that an older harness wrote. */
382
+ at?: string;
339
383
  /** Number of literature-reviewer delegations started so far. */
340
384
  delegationCount?: number;
341
385
  /** Agent-provided reason — set when phase === "skipped". */
@@ -407,4 +451,31 @@ export interface CompactionPart {
407
451
  /** Before the user message of a turn, or before a later request. */
408
452
  trigger?: "turn-start" | "mid-turn";
409
453
  }
410
- export type ChatPart = PresentationPart | PlanPart | RunCardPart | FileReferencePart | AskPart | RunStartedPart | DagStatePart | StepActivityPart | StepFileTreePart | StepOutputPart | StepSummaryPart | StepUsagePart | StepBlockedPart | RunSynthesisPart | SynthesisProgressPart | RunCompletedPart | RunFailedPart | ChildSessionStartedPart | ReportRenderedPart | CompactionPart;
454
+ /** One tool call of a sub-agent. It holds no input, no output, and no text of the sub-agent. */
455
+ export interface SubAgentActivityEntry {
456
+ agentId: string;
457
+ callPath: string[];
458
+ tool: string;
459
+ /** The one-line detail of the call, normalized, redacted, and capped by the loop. */
460
+ label?: string;
461
+ /** ISO 8601. */
462
+ startedAt: string;
463
+ /** ISO 8601. Absent while the call is in flight and for an `incomplete` call. */
464
+ endedAt?: string;
465
+ /** Absent while the call is in flight. A stored entry always has it. */
466
+ outcome?: ToolCallOutcome;
467
+ }
468
+ /**
469
+ * The tool calls of the sub-agents below one root tool call. Re-emitted under the same `id` after each change,
470
+ * so reconciling readers keep the latest list.
471
+ */
472
+ export interface SubAgentActivityPart {
473
+ type: "data-subagent-activity";
474
+ id: string;
475
+ /** The id of the root tool call. */
476
+ toolCallId: string;
477
+ entries: SubAgentActivityEntry[];
478
+ /** The count of calls past the cap of the entries. */
479
+ dropped: number;
480
+ }
481
+ export type ChatPart = PresentationPart | PlanPart | RunCardPart | PlanApprovalPart | FileReferencePart | AskPart | RunStartedPart | DagStatePart | StepActivityPart | ActivityEntryPart | SubAgentActivityPart | StepFileTreePart | StepOutputPart | StepSummaryPart | StepUsagePart | StepBlockedPart | RunSynthesisPart | SynthesisProgressPart | RunCompletedPart | RunFailedPart | ChildSessionStartedPart | ReportRenderedPart | CompactionPart;
@@ -5,11 +5,13 @@
5
5
  * Categories:
6
6
  * Presentation: data-presentation (agent-synthesized content),
7
7
  * data-plan (plan by id), data-file-reference (files by path)
8
- * Approval: data-ask (a tool's pending user-approval prompt)
8
+ * Approval: data-ask (a tool's pending user-approval prompt),
9
+ * data-plan-approval (the record of an approved plan)
9
10
  * Compaction: data-compaction (a compaction of the conversation thread)
10
11
  * Run lifecycle: run-started, dag-state, run-completed, run-failed, run-synthesis,
11
12
  * synthesis-progress
12
13
  * Per-step live: step-activity, step-file-tree
14
+ * Activity history: activity-entry (run stream), subagent-activity (conversation)
13
15
  * Per-step final: step-output, step-summary, step-usage
14
16
  */
15
17
  export {};
@@ -2,7 +2,7 @@ export { ORGAN_SYSTEMS, OrganSystemSchema, ORGAN_SYSTEM_LABELS, organSystemLabel
2
2
  export type { OrganSystem } from "./organ-system.js";
3
3
  export { SEVERITIES, SeveritySchema } from "./severity.js";
4
4
  export type { Severity } from "./severity.js";
5
- export type { PlanStep, PresentationContent, PresentationPart, PlanPart, RunCardPart, FileReferenceEntry, FileReferencePart, AskPart, RunStartedPart, StepStatus, DagStepState, DagStatePart, StepPhase, StepActivityPart, FileTreeEntry, StepFileTreePart, StepOutputFile, StepOutputPart, StepSummaryPart, StepUsagePart, StepBlockedPart, SynthesizedFinding, BiologicalTheme, RunSynthesisPart, SynthesisPhase, SynthesisProgressPart, RunCompletedFinding, RunCompletedPart, RunFailedPart, ChildSessionStartedPart, ReportRenderedPart, CompactionPart, ChatPart, } from "./chat-parts.js";
5
+ export type { PlanStep, PresentationContent, PresentationPart, PlanPart, RunCardPart, PlanApprovalPart, FileReferenceEntry, FileReferencePart, AskPart, RunStartedPart, StepStatus, DagStepState, PlanGraphStep, DagStatePart, StepPhase, StepActivityPart, ActivityEntryPart, SubAgentActivityEntry, SubAgentActivityPart, FileTreeEntry, StepFileTreePart, StepOutputFile, StepOutputPart, StepSummaryPart, StepUsagePart, StepBlockedPart, FindingReference, SynthesizedFinding, BiologicalTheme, RunSynthesisPart, SynthesisPhase, SynthesisProgressPart, RunCompletedFinding, RunCompletedPart, RunFailedPart, ChildSessionStartedPart, ReportRenderedPart, CompactionPart, ChatPart, } from "./chat-parts.js";
6
6
  export type { EventSource, TextDeltaEvent, IterationEvent, ToolStartedEvent, ToolFinishedEvent, FinishEvent, ChatErrorEvent, ChatEvent, ChatFrame, ChatPartFrame, } from "./chat-events.js";
7
7
  export type { TokenUsageRollup } from "./usage.js";
8
8
  export { DATA_PROFILE_RUN_LITERAL } from "./data-profile.js";
@@ -12,6 +12,8 @@ export type { DimensionCategory, DimensionCategoryEntry, DimensionProbe, Dimensi
12
12
  export type { TextPart, ToolCallPart, MessagePart, ChatMessage } from "./message.js";
13
13
  export { toChatFrame, applyChatFrame, checkChatPart } from "./chat-frame.js";
14
14
  export type { TurnTerminal, ApplyFrameResult, ChatPartCheck } from "./chat-frame.js";
15
+ export { createSubAgentActivityTracker, SUBAGENT_ACTIVITY_MAX_ENTRIES } from "./subagent-activity.js";
16
+ export type { SubAgentActivityTracker } from "./subagent-activity.js";
15
17
  export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./part-registry.js";
16
18
  export type { ChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./part-registry.js";
17
19
  export { AnalogyCoverageSchema, AnalogyReportSchema, AnalogyReportErrorSchema, AnalogicalReasonerOutputSchema } from "./analogy-report.js";
@@ -3,6 +3,7 @@ export { SEVERITIES, SeveritySchema } from "./severity.js";
3
3
  export { DATA_PROFILE_RUN_LITERAL } from "./data-profile.js";
4
4
  export { DIMENSION_CATEGORIES, DIMENSION_CATEGORY_IDS, DIMENSION_PROBE_IDS, DIMENSION_PROBES, GROUP_CATEGORIES, GROUP_CATEGORY_IDS, GROUP_ROLE_IDS, GROUP_ROLES, PROBE_OUTCOME_IDS, dimensionCategoryEntry, dimensionScope, groupCategoryEntry, } from "./profile-vocabulary.js";
5
5
  export { toChatFrame, applyChatFrame, checkChatPart } from "./chat-frame.js";
6
+ export { createSubAgentActivityTracker, SUBAGENT_ACTIVITY_MAX_ENTRIES } from "./subagent-activity.js";
6
7
  export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./part-registry.js";
7
8
  export { AnalogyCoverageSchema, AnalogyReportSchema, AnalogyReportErrorSchema, AnalogicalReasonerOutputSchema } from "./analogy-report.js";
8
9
  export { buildReportSessionUrl, reportSessionResourceId } from "./content-url.js";
@@ -2,11 +2,14 @@ export const PART_REGISTRY = {
2
2
  "data-presentation": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: false },
3
3
  "data-plan": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: false },
4
4
  "data-run-card": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: false },
5
+ "data-plan-approval": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: false },
5
6
  "data-file-reference": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: false },
6
7
  "data-ask": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: true },
7
8
  "data-run-started": { emitter: "workflow", consumer: "sidebar", transient: true, reconciling: false },
8
9
  "data-dag-state": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: true },
9
10
  "data-step-activity": { emitter: "workflow", consumer: "sidebar", transient: true, reconciling: true },
11
+ "data-activity-entry": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
12
+ "data-subagent-activity": { emitter: "conversation", consumer: "conversation", transient: false, reconciling: true },
10
13
  "data-step-file-tree": { emitter: "workflow", consumer: "sidebar", transient: true, reconciling: true },
11
14
  "data-step-output": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
12
15
  "data-step-summary": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
@@ -5,6 +5,7 @@ import { z } from "zod";
5
5
  export declare const EventSourceSchema: z.ZodObject<{
6
6
  agentId: z.ZodString;
7
7
  callPath: z.ZodArray<z.ZodString>;
8
+ invocationId: z.ZodOptional<z.ZodString>;
8
9
  }, z.core.$strip>;
9
10
  export declare const TextDeltaEventSchema: z.ZodObject<{
10
11
  type: z.ZodLiteral<"text-delta">;
@@ -12,6 +13,7 @@ export declare const TextDeltaEventSchema: z.ZodObject<{
12
13
  source: z.ZodObject<{
13
14
  agentId: z.ZodString;
14
15
  callPath: z.ZodArray<z.ZodString>;
16
+ invocationId: z.ZodOptional<z.ZodString>;
15
17
  }, z.core.$strip>;
16
18
  }, z.core.$strip>;
17
19
  export declare const IterationEventSchema: z.ZodObject<{
@@ -19,6 +21,7 @@ export declare const IterationEventSchema: z.ZodObject<{
19
21
  source: z.ZodObject<{
20
22
  agentId: z.ZodString;
21
23
  callPath: z.ZodArray<z.ZodString>;
24
+ invocationId: z.ZodOptional<z.ZodString>;
22
25
  }, z.core.$strip>;
23
26
  }, z.core.$strip>;
24
27
  /** Mirrors the `ToolOutcome` union — three states, never a boolean. */
@@ -42,6 +45,7 @@ export declare const ToolStartedEventSchema: z.ZodObject<{
42
45
  source: z.ZodObject<{
43
46
  agentId: z.ZodString;
44
47
  callPath: z.ZodArray<z.ZodString>;
48
+ invocationId: z.ZodOptional<z.ZodString>;
45
49
  }, z.core.$strip>;
46
50
  }, z.core.$strip>;
47
51
  export declare const ToolFinishedEventSchema: z.ZodObject<{
@@ -58,6 +62,7 @@ export declare const ToolFinishedEventSchema: z.ZodObject<{
58
62
  source: z.ZodObject<{
59
63
  agentId: z.ZodString;
60
64
  callPath: z.ZodArray<z.ZodString>;
65
+ invocationId: z.ZodOptional<z.ZodString>;
61
66
  }, z.core.$strip>;
62
67
  }, z.core.$strip>;
63
68
  export declare const FinishEventSchema: z.ZodObject<{
@@ -65,6 +70,7 @@ export declare const FinishEventSchema: z.ZodObject<{
65
70
  source: z.ZodObject<{
66
71
  agentId: z.ZodString;
67
72
  callPath: z.ZodArray<z.ZodString>;
73
+ invocationId: z.ZodOptional<z.ZodString>;
68
74
  }, z.core.$strip>;
69
75
  usage: z.ZodOptional<z.ZodObject<{
70
76
  inputTokens: z.ZodOptional<z.ZodNumber>;
@@ -88,6 +94,7 @@ export declare const ChatErrorEventSchema: z.ZodObject<{
88
94
  source: z.ZodObject<{
89
95
  agentId: z.ZodString;
90
96
  callPath: z.ZodArray<z.ZodString>;
97
+ invocationId: z.ZodOptional<z.ZodString>;
91
98
  }, z.core.$strip>;
92
99
  }, z.core.$strip>;
93
100
  export declare const ChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -96,12 +103,14 @@ export declare const ChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
96
103
  source: z.ZodObject<{
97
104
  agentId: z.ZodString;
98
105
  callPath: z.ZodArray<z.ZodString>;
106
+ invocationId: z.ZodOptional<z.ZodString>;
99
107
  }, z.core.$strip>;
100
108
  }, z.core.$strip>, z.ZodObject<{
101
109
  type: z.ZodLiteral<"iteration">;
102
110
  source: z.ZodObject<{
103
111
  agentId: z.ZodString;
104
112
  callPath: z.ZodArray<z.ZodString>;
113
+ invocationId: z.ZodOptional<z.ZodString>;
105
114
  }, z.core.$strip>;
106
115
  }, z.core.$strip>, z.ZodObject<{
107
116
  type: z.ZodLiteral<"tool-started">;
@@ -111,6 +120,7 @@ export declare const ChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
111
120
  source: z.ZodObject<{
112
121
  agentId: z.ZodString;
113
122
  callPath: z.ZodArray<z.ZodString>;
123
+ invocationId: z.ZodOptional<z.ZodString>;
114
124
  }, z.core.$strip>;
115
125
  }, z.core.$strip>, z.ZodObject<{
116
126
  type: z.ZodLiteral<"tool-finished">;
@@ -126,12 +136,14 @@ export declare const ChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
126
136
  source: z.ZodObject<{
127
137
  agentId: z.ZodString;
128
138
  callPath: z.ZodArray<z.ZodString>;
139
+ invocationId: z.ZodOptional<z.ZodString>;
129
140
  }, z.core.$strip>;
130
141
  }, z.core.$strip>, z.ZodObject<{
131
142
  type: z.ZodLiteral<"finish">;
132
143
  source: z.ZodObject<{
133
144
  agentId: z.ZodString;
134
145
  callPath: z.ZodArray<z.ZodString>;
146
+ invocationId: z.ZodOptional<z.ZodString>;
135
147
  }, z.core.$strip>;
136
148
  usage: z.ZodOptional<z.ZodObject<{
137
149
  inputTokens: z.ZodOptional<z.ZodNumber>;
@@ -154,5 +166,6 @@ export declare const ChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
154
166
  source: z.ZodObject<{
155
167
  agentId: z.ZodString;
156
168
  callPath: z.ZodArray<z.ZodString>;
169
+ invocationId: z.ZodOptional<z.ZodString>;
157
170
  }, z.core.$strip>;
158
171
  }, z.core.$strip>], "type">;
@@ -6,6 +6,7 @@ import { TokenUsageRollupSchema } from "./usage.js";
6
6
  export const EventSourceSchema = z.object({
7
7
  agentId: z.string(),
8
8
  callPath: z.array(z.string()),
9
+ invocationId: z.string().optional(),
9
10
  });
10
11
  export const TextDeltaEventSchema = z.object({
11
12
  type: z.literal("text-delta"),