@inflexa-ai/harness 0.41.2 → 0.42.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 (73) hide show
  1. package/dist/agents/conversation-agent.js +3 -0
  2. package/dist/agents/report-session-agent.d.ts +2 -2
  3. package/dist/agents/report-session-agent.js +4 -0
  4. package/dist/app/chat-turn.d.ts +0 -4
  5. package/dist/app/chat-turn.js +39 -25
  6. package/dist/app/message-assembly.d.ts +2 -2
  7. package/dist/app/message-assembly.js +1 -1
  8. package/dist/contracts/chat-events.d.ts +12 -5
  9. package/dist/contracts/chat-events.js +3 -3
  10. package/dist/contracts/chat-frame.d.ts +41 -0
  11. package/dist/contracts/chat-frame.js +173 -0
  12. package/dist/contracts/chat-parts.d.ts +15 -3
  13. package/dist/contracts/chat-parts.js +2 -2
  14. package/dist/contracts/index.d.ts +6 -4
  15. package/dist/contracts/index.js +1 -0
  16. package/dist/contracts/message.d.ts +7 -5
  17. package/dist/contracts/message.js +1 -1
  18. package/dist/contracts/part-registry.d.ts +6 -6
  19. package/dist/contracts/schemas/chat-events.d.ts +2 -2
  20. package/dist/contracts/schemas/chat-events.js +2 -2
  21. package/dist/contracts/schemas/chat-parts.d.ts +34 -2
  22. package/dist/contracts/schemas/chat-parts.js +9 -3
  23. package/dist/contracts/schemas/index.d.ts +2 -2
  24. package/dist/contracts/schemas/index.js +2 -2
  25. package/dist/execution/run-event-parts.d.ts +19 -11
  26. package/dist/execution/run-event-parts.js +0 -0
  27. package/dist/execution/run-event-stream.d.ts +2 -2
  28. package/dist/index.d.ts +10 -6
  29. package/dist/index.js +4 -2
  30. package/dist/lib/page-capture.d.ts +27 -9
  31. package/dist/lib/page-capture.js +81 -33
  32. package/dist/loop/compaction.d.ts +8 -3
  33. package/dist/loop/run-agent.d.ts +11 -0
  34. package/dist/loop/run-agent.js +62 -35
  35. package/dist/loop/types.d.ts +3 -0
  36. package/dist/memory/ai-sdk-message-storage.d.ts +18 -3
  37. package/dist/memory/ai-sdk-message-storage.js +23 -1
  38. package/dist/memory/conversation-display-recorder.d.ts +7 -1
  39. package/dist/memory/conversation-display-recorder.js +59 -119
  40. package/dist/memory/conversation-display-replay.d.ts +3 -3
  41. package/dist/memory/conversation-display-replay.js +7 -21
  42. package/dist/memory/conversation-display-storage.d.ts +10 -10
  43. package/dist/memory/conversation-display-storage.js +9 -8
  44. package/dist/memory/conversation-view.d.ts +5 -4
  45. package/dist/memory/conversation-view.js +14 -18
  46. package/dist/memory/count-tokens.js +1 -0
  47. package/dist/memory/thread-store.d.ts +9 -2
  48. package/dist/memory/thread-store.js +8 -2
  49. package/dist/prompts/compaction.d.ts +2 -2
  50. package/dist/prompts/compaction.js +2 -2
  51. package/dist/prompts/report-session.d.ts +1 -1
  52. package/dist/prompts/report-session.js +40 -28
  53. package/dist/report-render/views/block-mark.d.ts +8 -0
  54. package/dist/report-render/views/block-mark.js +10 -0
  55. package/dist/report-render/views/chart-view.js +2 -1
  56. package/dist/report-render/views/prose.js +10 -6
  57. package/dist/report-render/views/values.js +5 -4
  58. package/dist/state/migrations/20260927180000_thread_title_set_by_user.d.ts +6 -0
  59. package/dist/state/migrations/20260927180000_thread_title_set_by_user.js +10 -0
  60. package/dist/state/migrations/index.js +2 -0
  61. package/dist/tools/report-authoring/authoring-tools.d.ts +16 -5
  62. package/dist/tools/report-authoring/authoring-tools.js +52 -24
  63. package/dist/tools/report-session/examine-page.d.ts +29 -14
  64. package/dist/tools/report-session/examine-page.js +40 -16
  65. package/dist/tools/report-session/list-artifacts.d.ts +23 -10
  66. package/dist/tools/report-session/list-artifacts.js +51 -31
  67. package/dist/tools/report-session/page-faults.d.ts +29 -0
  68. package/dist/tools/report-session/page-faults.js +48 -0
  69. package/dist/tools/report-session/preview-report.d.ts +9 -2
  70. package/dist/tools/report-session/preview-report.js +13 -3
  71. package/dist/tools/report-session/record-version.d.ts +5 -1
  72. package/dist/tools/report-session/record-version.js +4 -3
  73. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import type { CortexChatPart } from "./chat-parts.js";
2
- export type CortexChatPartType = CortexChatPart["type"];
1
+ import type { ChatPart } from "./chat-parts.js";
2
+ export type ChatPartType = ChatPart["type"];
3
3
  export type PartEmitter = "workflow" | "conversation";
4
4
  export type PartConsumer = "sidebar" | "conversation";
5
5
  export interface PartDescriptor {
@@ -12,7 +12,7 @@ export interface PartDescriptor {
12
12
  /** If true, multiple emissions share the same id — latest wins. */
13
13
  reconciling: boolean;
14
14
  }
15
- export declare const PART_REGISTRY: Record<CortexChatPartType, PartDescriptor>;
16
- export declare function isTransient(type: CortexChatPartType): boolean;
17
- export declare function isReconciling(type: CortexChatPartType): boolean;
18
- export declare function isSidebarPart(type: CortexChatPartType): boolean;
15
+ export declare const PART_REGISTRY: Record<ChatPartType, PartDescriptor>;
16
+ export declare function isTransient(type: ChatPartType): boolean;
17
+ export declare function isReconciling(type: ChatPartType): boolean;
18
+ export declare function isSidebarPart(type: ChatPartType): boolean;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Zod schemas for Cortex-native chat-stream events — validation at boundaries.
2
+ * Zod schemas for chat-stream events — validation at boundaries.
3
3
  */
4
4
  import { z } from "zod";
5
5
  export declare const EventSourceSchema: z.ZodObject<{
@@ -83,7 +83,7 @@ export declare const ChatErrorEventSchema: z.ZodObject<{
83
83
  callPath: z.ZodArray<z.ZodString>;
84
84
  }, z.core.$strip>;
85
85
  }, z.core.$strip>;
86
- export declare const CortexChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
86
+ export declare const ChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
87
87
  type: z.ZodLiteral<"text-delta">;
88
88
  text: z.ZodString;
89
89
  source: z.ZodObject<{
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Zod schemas for Cortex-native chat-stream events — validation at boundaries.
2
+ * Zod schemas for chat-stream events — validation at boundaries.
3
3
  */
4
4
  import { z } from "zod";
5
5
  import { TokenUsageRollupSchema } from "./usage.js";
@@ -45,7 +45,7 @@ export const ChatErrorEventSchema = z.object({
45
45
  reason: z.string().optional(),
46
46
  source: EventSourceSchema,
47
47
  });
48
- export const CortexChatEventSchema = z.discriminatedUnion("type", [
48
+ export const ChatEventSchema = z.discriminatedUnion("type", [
49
49
  TextDeltaEventSchema,
50
50
  ToolStartedEventSchema,
51
51
  ToolFinishedEventSchema,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Zod schemas for Cortex chat data parts — validation at boundaries.
2
+ * Zod schemas for chat data parts — validation at boundaries.
3
3
  */
4
4
  import { z } from "zod";
5
5
  export declare const PlanStepSchema: z.ZodObject<{
@@ -11,8 +11,16 @@ export declare const PlanStepSchema: z.ZodObject<{
11
11
  resources: z.ZodOptional<z.ZodObject<{
12
12
  cpu: z.ZodNumber;
13
13
  memoryGb: z.ZodNumber;
14
+ gpu: z.ZodOptional<z.ZodObject<{
15
+ count: z.ZodNumber;
16
+ }, z.core.$strip>>;
14
17
  }, z.core.$strip>>;
15
18
  maxSteps: z.ZodNumber;
19
+ track: z.ZodOptional<z.ZodString>;
20
+ step_type: z.ZodOptional<z.ZodString>;
21
+ acceptance_criteria: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
+ constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
+ caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
16
24
  }, z.core.$strip>;
17
25
  export declare const PresentationContentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
18
26
  kind: z.ZodLiteral<"echart">;
@@ -93,8 +101,16 @@ export declare const PlanPartSchema: z.ZodObject<{
93
101
  resources: z.ZodOptional<z.ZodObject<{
94
102
  cpu: z.ZodNumber;
95
103
  memoryGb: z.ZodNumber;
104
+ gpu: z.ZodOptional<z.ZodObject<{
105
+ count: z.ZodNumber;
106
+ }, z.core.$strip>>;
96
107
  }, z.core.$strip>>;
97
108
  maxSteps: z.ZodNumber;
109
+ track: z.ZodOptional<z.ZodString>;
110
+ step_type: z.ZodOptional<z.ZodString>;
111
+ acceptance_criteria: z.ZodOptional<z.ZodArray<z.ZodString>>;
112
+ constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
113
+ caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
98
114
  }, z.core.$strip>>>;
99
115
  analytical_narrative: z.ZodOptional<z.ZodString>;
100
116
  omicsType: z.ZodOptional<z.ZodString>;
@@ -484,8 +500,12 @@ export declare const CompactionPartSchema: z.ZodObject<{
484
500
  tokensBefore: z.ZodNumber;
485
501
  tokensAfter: z.ZodOptional<z.ZodNumber>;
486
502
  durationMs: z.ZodOptional<z.ZodNumber>;
503
+ trigger: z.ZodOptional<z.ZodEnum<{
504
+ "turn-start": "turn-start";
505
+ "mid-turn": "mid-turn";
506
+ }>>;
487
507
  }, z.core.$strip>;
488
- export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
508
+ export declare const ChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
489
509
  type: z.ZodLiteral<"data-presentation">;
490
510
  id: z.ZodString;
491
511
  title: z.ZodOptional<z.ZodString>;
@@ -533,8 +553,16 @@ export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
533
553
  resources: z.ZodOptional<z.ZodObject<{
534
554
  cpu: z.ZodNumber;
535
555
  memoryGb: z.ZodNumber;
556
+ gpu: z.ZodOptional<z.ZodObject<{
557
+ count: z.ZodNumber;
558
+ }, z.core.$strip>>;
536
559
  }, z.core.$strip>>;
537
560
  maxSteps: z.ZodNumber;
561
+ track: z.ZodOptional<z.ZodString>;
562
+ step_type: z.ZodOptional<z.ZodString>;
563
+ acceptance_criteria: z.ZodOptional<z.ZodArray<z.ZodString>>;
564
+ constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
565
+ caveats: z.ZodOptional<z.ZodArray<z.ZodString>>;
538
566
  }, z.core.$strip>>>;
539
567
  analytical_narrative: z.ZodOptional<z.ZodString>;
540
568
  omicsType: z.ZodOptional<z.ZodString>;
@@ -788,4 +816,8 @@ export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
788
816
  tokensBefore: z.ZodNumber;
789
817
  tokensAfter: z.ZodOptional<z.ZodNumber>;
790
818
  durationMs: z.ZodOptional<z.ZodNumber>;
819
+ trigger: z.ZodOptional<z.ZodEnum<{
820
+ "turn-start": "turn-start";
821
+ "mid-turn": "mid-turn";
822
+ }>>;
791
823
  }, z.core.$strip>], "type">;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Zod schemas for Cortex chat data parts — validation at boundaries.
2
+ * Zod schemas for chat data parts — validation at boundaries.
3
3
  */
4
4
  import { z } from "zod";
5
5
  import { TokenUsageRollupSchema } from "./usage.js";
@@ -10,8 +10,13 @@ export const PlanStepSchema = z.object({
10
10
  agent: z.string(),
11
11
  question: z.string(),
12
12
  depends_on: z.array(z.string()),
13
- resources: z.object({ cpu: z.number(), memoryGb: z.number() }).optional(),
13
+ resources: z.object({ cpu: z.number(), memoryGb: z.number(), gpu: z.object({ count: z.number() }).optional() }).optional(),
14
14
  maxSteps: z.number(),
15
+ track: z.string().optional(),
16
+ step_type: z.string().optional(),
17
+ acceptance_criteria: z.array(z.string()).optional(),
18
+ constraints: z.array(z.string()).optional(),
19
+ caveats: z.array(z.string()).optional(),
15
20
  });
16
21
  export const PresentationContentSchema = z.discriminatedUnion("kind", [
17
22
  z.object({
@@ -307,9 +312,10 @@ export const CompactionPartSchema = z.object({
307
312
  tokensBefore: z.number().int().nonnegative(),
308
313
  tokensAfter: z.number().int().nonnegative().optional(),
309
314
  durationMs: z.number().int().nonnegative().optional(),
315
+ trigger: z.enum(["turn-start", "mid-turn"]).optional(),
310
316
  });
311
317
  // ── Union ───────────────────────────────────────────────────────────
312
- export const CortexChatPartSchema = z.discriminatedUnion("type", [
318
+ export const ChatPartSchema = z.discriminatedUnion("type", [
313
319
  PresentationPartSchema,
314
320
  PlanPartSchema,
315
321
  RunCardPartSchema,
@@ -1,3 +1,3 @@
1
- export { PlanStepSchema, PresentationContentSchema, PresentationPartSchema, PlanPartSchema, RunCardPartSchema, FileReferenceEntrySchema, FileReferencePartSchema, RunStartedPartSchema, StepStatusSchema, DagStepStateSchema, DagStatePartSchema, StepPhaseSchema, StepActivityPartSchema, FileTreeEntrySchema, StepFileTreePartSchema, StepOutputFileSchema, StepOutputPartSchema, StepSummaryPartSchema, StepUsagePartSchema, StepBlockedPartSchema, SynthesizedFindingSchema, BiologicalThemeSchema, RunSynthesisPartSchema, SynthesisPhaseSchema, SynthesisProgressPartSchema, RunCompletedFindingSchema, RunCompletedPartSchema, RunFailedPartSchema, CortexChatPartSchema, } from "./chat-parts.js";
2
- export { EventSourceSchema, TextDeltaEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, CortexChatEventSchema, } from "./chat-events.js";
1
+ export { PlanStepSchema, PresentationContentSchema, PresentationPartSchema, PlanPartSchema, RunCardPartSchema, FileReferenceEntrySchema, FileReferencePartSchema, RunStartedPartSchema, StepStatusSchema, DagStepStateSchema, DagStatePartSchema, StepPhaseSchema, StepActivityPartSchema, FileTreeEntrySchema, StepFileTreePartSchema, StepOutputFileSchema, StepOutputPartSchema, StepSummaryPartSchema, StepUsagePartSchema, StepBlockedPartSchema, SynthesizedFindingSchema, BiologicalThemeSchema, RunSynthesisPartSchema, SynthesisPhaseSchema, SynthesisProgressPartSchema, RunCompletedFindingSchema, RunCompletedPartSchema, RunFailedPartSchema, ChatPartSchema, } from "./chat-parts.js";
2
+ export { EventSourceSchema, TextDeltaEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, ChatEventSchema, } from "./chat-events.js";
3
3
  export { TokenUsageRollupSchema } from "./usage.js";
@@ -1,3 +1,3 @@
1
- export { PlanStepSchema, PresentationContentSchema, PresentationPartSchema, PlanPartSchema, RunCardPartSchema, FileReferenceEntrySchema, FileReferencePartSchema, RunStartedPartSchema, StepStatusSchema, DagStepStateSchema, DagStatePartSchema, StepPhaseSchema, StepActivityPartSchema, FileTreeEntrySchema, StepFileTreePartSchema, StepOutputFileSchema, StepOutputPartSchema, StepSummaryPartSchema, StepUsagePartSchema, StepBlockedPartSchema, SynthesizedFindingSchema, BiologicalThemeSchema, RunSynthesisPartSchema, SynthesisPhaseSchema, SynthesisProgressPartSchema, RunCompletedFindingSchema, RunCompletedPartSchema, RunFailedPartSchema, CortexChatPartSchema, } from "./chat-parts.js";
2
- export { EventSourceSchema, TextDeltaEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, CortexChatEventSchema, } from "./chat-events.js";
1
+ export { PlanStepSchema, PresentationContentSchema, PresentationPartSchema, PlanPartSchema, RunCardPartSchema, FileReferenceEntrySchema, FileReferencePartSchema, RunStartedPartSchema, StepStatusSchema, DagStepStateSchema, DagStatePartSchema, StepPhaseSchema, StepActivityPartSchema, FileTreeEntrySchema, StepFileTreePartSchema, StepOutputFileSchema, StepOutputPartSchema, StepSummaryPartSchema, StepUsagePartSchema, StepBlockedPartSchema, SynthesizedFindingSchema, BiologicalThemeSchema, RunSynthesisPartSchema, SynthesisPhaseSchema, SynthesisProgressPartSchema, RunCompletedFindingSchema, RunCompletedPartSchema, RunFailedPartSchema, ChatPartSchema, } from "./chat-parts.js";
2
+ export { EventSourceSchema, TextDeltaEventSchema, ToolStartedEventSchema, ToolFinishedEventSchema, FinishEventSchema, ChatErrorEventSchema, ChatEventSchema, } from "./chat-events.js";
3
3
  export { TokenUsageRollupSchema } from "./usage.js";
@@ -1,21 +1,20 @@
1
1
  /**
2
- * The two input-only rules of the run-event read seam: narrowing a raw durable
3
- * stream value to the chat data-part contract, and the latest-wins reconciling
4
- * fold applied before delivery.
2
+ * The rules of the run-event read side that need no database and no durability
3
+ * engine: narrowing a raw durable stream value to the chat data-part contract,
4
+ * and the latest-wins reconciling fold, as a batch for `createRunEventStream`
5
+ * and live for an embedder that reads the run streams itself.
5
6
  *
6
- * They live apart from the reader because they are the only part of the seam
7
- * whose correctness is a function of its argument alone — no database, no
8
- * durability engine, no clock — and keeping them here is what lets that be
9
- * proven directly instead of inferred from a driven subscription.
7
+ * They live apart from the reader, thus a test drives them directly instead of
8
+ * through a subscription.
10
9
  */
11
- import type { CortexChatPart } from "../contracts/chat-parts.js";
10
+ import type { ChatPart } from "../contracts/chat-parts.js";
12
11
  /**
13
12
  * Narrow one raw stream value to a chat data part, or `null` when it is not one.
14
13
  *
15
14
  * A run's streams carry more than the contract: a sandbox step also writes its
16
15
  * loop orchestration under envelopes (`data-loop-event`, `data-sandbox-event`)
17
16
  * that belong to the workflow layer and have no registry entry. The seam's
18
- * contract is the `CortexChatPart` union, so anything the registry does not
17
+ * contract is the `ChatPart` union, so anything the registry does not
19
18
  * classify is not deliverable — which also covers a part written by a producer
20
19
  * newer than the reader.
21
20
  *
@@ -26,7 +25,7 @@ import type { CortexChatPart } from "../contracts/chat-parts.js";
26
25
  * the discriminant is the boundary that can actually drift (a producer emitting
27
26
  * something else entirely) and the one worth checking.
28
27
  */
29
- export declare function parseRunEventPart(value: unknown): CortexChatPart | null;
28
+ export declare function parseRunEventPart(value: unknown): ChatPart | null;
30
29
  /**
31
30
  * Collapse a batch of parts so each reconciling id appears once, carrying its
32
31
  * latest value, and every other part survives untouched in write order.
@@ -41,4 +40,13 @@ export declare function parseRunEventPart(value: unknown): CortexChatPart | null
41
40
  * A survivor keeps the position of its LAST occurrence, so relative order among
42
41
  * the parts that are delivered is the order they were written.
43
42
  */
44
- export declare function foldRunEventParts(parts: readonly CortexChatPart[]): CortexChatPart[];
43
+ export declare function foldRunEventParts(parts: readonly ChatPart[]): ChatPart[];
44
+ /**
45
+ * The live form of {@link foldRunEventParts}, for a stream that stays open. An
46
+ * entry with a reconcile key waits `flushMs`, and a later entry with the same
47
+ * key replaces it. Thus a catch-up burst delivers each key once, and a live
48
+ * update lands one window later. Every other entry, also one of a type that the
49
+ * registry does not know, goes to `emit` at once, thus it can overtake a held
50
+ * entry. The held entries go to `emit` when the stream ends.
51
+ */
52
+ export declare function pipeFoldedRunEvents<T>(entries: AsyncIterable<T>, emit: (entry: T) => Promise<void>, flushMs: number): Promise<void>;
Binary file
@@ -31,7 +31,7 @@
31
31
  * writer it observes.
32
32
  */
33
33
  import type { Pool } from "pg";
34
- import type { CortexChatPart } from "../contracts/chat-parts.js";
34
+ import type { ChatPart } from "../contracts/chat-parts.js";
35
35
  import type { Logger } from "../lib/logger.js";
36
36
  /**
37
37
  * Construction-time dependencies. The pool is the application pool the run
@@ -48,7 +48,7 @@ export interface RunEventStreamDeps {
48
48
  * never invoked concurrently with itself and back-pressure is the caller's to
49
49
  * exert by taking its time. A throw is logged and swallowed.
50
50
  */
51
- export type RunEventPartHandler = (part: CortexChatPart) => void | Promise<void>;
51
+ export type RunEventPartHandler = (part: ChatPart) => void | Promise<void>;
52
52
  /** Call-time parameters of one subscription. */
53
53
  export interface RunEventSubscribeOptions {
54
54
  /** The run to observe. Also the parent workflow's id. */
package/dist/index.d.ts CHANGED
@@ -60,7 +60,7 @@ export { UnavailableAsk, AskRejectedError } from "./tools/approval/contract.js";
60
60
  export type { Ask, AskRequest, AskReply, AskApproval } from "./tools/approval/contract.js";
61
61
  export { runAgent, finalText } from "./loop/run-agent.js";
62
62
  export type { RunAgentOptions, RunAgentResult, AgentFinish, AgentRound } from "./loop/run-agent.js";
63
- export type { CompactionPolicy } from "./loop/compaction.js";
63
+ export type { CompactionPolicy, CompactionRules } from "./loop/compaction.js";
64
64
  export type { ToolMask } from "./loop/tool-mask.js";
65
65
  export type { AgentDefinition, RunStep, EmitFn, EmitEvent, EventSource } from "./loop/types.js";
66
66
  export type { KeptToolOutput, ToolOutputStore } from "./loop/tool-output.js";
@@ -82,7 +82,7 @@ export type { SuspendOn } from "./providers/errors.js";
82
82
  export { suspensionOfFailure } from "./workflows/suspension.js";
83
83
  export type { Suspension } from "./workflows/suspension.js";
84
84
  export { createStreamingChat } from "./providers/streaming-chat.js";
85
- export { DEFAULT_CONVERSATION_BUDGET, openChatTurn, prepareChatTurn, runChatTurn } from "./app/chat-turn.js";
85
+ export { openChatTurn, prepareChatTurn, runChatTurn } from "./app/chat-turn.js";
86
86
  export type { ChatTurnOutcome, ChatTurnRan, ChatTurnRefusal, ChatTurnResult, ChatTurnSession, OpenChatTurn, OpenChatTurnParams, PrepareChatTurnDeps, PrepareChatTurnParams, PrepareChatTurnResult, RunChatTurnDeps, RunChatTurnParams, RunOpenChatTurnParams, } from "./app/chat-turn.js";
87
87
  export { createThreadStore } from "./memory/thread-store.js";
88
88
  export type { ThreadStore, Thread, ThreadType, ThreadInputError, CreateThreadInput, ListThreadsInput, ThreadPage } from "./memory/thread-store.js";
@@ -93,12 +93,15 @@ export { createConversationDisplayRecorder } from "./memory/conversation-display
93
93
  export type { ConversationDisplayRecorder, ConversationDisplayRecorderOptions } from "./memory/conversation-display-recorder.js";
94
94
  export { envelopeDisplayMessages, parseStoredDisplayEnvelope } from "./memory/conversation-display-storage.js";
95
95
  export type { ConversationDisplayMetadata, ConversationUIData, ConversationUIMessage, StoredDisplayEnvelope } from "./memory/conversation-display-storage.js";
96
- export { storedMessagesToCortex } from "./memory/conversation-display-replay.js";
97
- export type { CortexChatEvent, TextDeltaEvent, ToolStartedEvent, ToolFinishedEvent, ToolOutcome, ToolCallOutcome, ToolCallDetail, FinishEvent, ChatErrorEvent, } from "./contracts/chat-events.js";
96
+ export { storedMessagesToChat } from "./memory/conversation-display-replay.js";
97
+ export type { ChatEvent, ChatFrame, ChatPartFrame, TextDeltaEvent, ToolStartedEvent, ToolFinishedEvent, ToolOutcome, ToolCallOutcome, ToolCallDetail, FinishEvent, ChatErrorEvent, } from "./contracts/chat-events.js";
98
+ export { toChatFrame, applyChatFrame, checkChatPart } from "./contracts/chat-frame.js";
99
+ export type { TextPart, ToolCallPart, MessagePart, ChatMessage } from "./contracts/message.js";
100
+ export type { TurnTerminal, ApplyFrameResult, ChatPartCheck } from "./contracts/chat-frame.js";
98
101
  export type { TokenUsageRollup } from "./contracts/usage.js";
99
- export type { CortexChatPart, PresentationPart, PresentationContent, PlanPart, RunCardPart, FileReferencePart, FileReferenceEntry, RunStartedPart, DagStatePart, DagStepState, StepStatus, StepActivityPart, StepPhase, StepFileTreePart, FileTreeEntry, StepOutputPart, StepOutputFile, StepSummaryPart, StepUsagePart, StepBlockedPart, RunSynthesisPart, SynthesizedFinding, BiologicalTheme, SynthesisProgressPart, SynthesisPhase, RunCompletedPart, RunCompletedFinding, RunFailedPart, CompactionPart, } from "./contracts/chat-parts.js";
102
+ export type { ChatPart, PresentationPart, PresentationContent, PlanPart, RunCardPart, FileReferencePart, FileReferenceEntry, RunStartedPart, DagStatePart, DagStepState, StepStatus, StepActivityPart, StepPhase, StepFileTreePart, FileTreeEntry, StepOutputPart, StepOutputFile, StepSummaryPart, StepUsagePart, StepBlockedPart, RunSynthesisPart, SynthesizedFinding, BiologicalTheme, SynthesisProgressPart, SynthesisPhase, RunCompletedPart, RunCompletedFinding, RunFailedPart, CompactionPart, AskPart, ChildSessionStartedPart, ReportRenderedPart, } from "./contracts/chat-parts.js";
100
103
  export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./contracts/part-registry.js";
101
- export type { CortexChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./contracts/part-registry.js";
104
+ export type { ChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./contracts/part-registry.js";
102
105
  export { parseStructureUrl, alphafoldEntryUrl, alphafoldPredictionUrl } from "./contracts/structure-source.js";
103
106
  export type { StructureSource, StructureFormat } from "./contracts/structure-source.js";
104
107
  export { launchDbos, shutdownDbos, sweepEphemeralWorkflows } from "./runtime/dbos.js";
@@ -167,6 +170,7 @@ export { registerSandboxStep } from "./workflows/sandbox-step.js";
167
170
  export type { SandboxStepDeps, SandboxStepInput, SandboxStepResult, SandboxAgentBuildContext } from "./workflows/sandbox-step.js";
168
171
  export { createRunEventStream } from "./execution/run-event-stream.js";
169
172
  export type { RunEventStream, RunEventStreamDeps, RunEventSubscribeOptions, RunEventPartHandler } from "./execution/run-event-stream.js";
173
+ export { pipeFoldedRunEvents } from "./execution/run-event-parts.js";
170
174
  export { createSandboxAgents, SANDBOX_AGENT_META } from "./agents/sandbox/index.js";
171
175
  export type { SandboxAgentDeps, SandboxStepCoords, AgentMeta } from "./agents/sandbox/index.js";
172
176
  export { AnalysisPlanSchema } from "./schemas/workflow-state.js";
package/dist/index.js CHANGED
@@ -130,7 +130,7 @@ export { createStreamingChat } from "./providers/streaming-chat.js";
130
130
  // and gives only its transport values: the harness stores the opening, each round,
131
131
  // and the outcome. `appendTurn` stays for a record of a host. `createThreadStore`
132
132
  // owns thread metadata (create/list/title).
133
- export { DEFAULT_CONVERSATION_BUDGET, openChatTurn, prepareChatTurn, runChatTurn } from "./app/chat-turn.js";
133
+ export { openChatTurn, prepareChatTurn, runChatTurn } from "./app/chat-turn.js";
134
134
  export { createThreadStore } from "./memory/thread-store.js";
135
135
  export { createThreadHistory, conversationRecordTurn } from "./memory/thread-history.js";
136
136
  // The synthetic-message primitives. A host appends a record of out-of-band work (an analysis run's
@@ -154,7 +154,8 @@ export { envelopeDisplayMessages, parseStoredDisplayEnvelope } from "./memory/co
154
154
  // along with the startup backfill that was its only caller. `parseStoredDisplayEnvelope` absorbs the
155
155
  // one thing a read can now meet and not understand — a part whose key this vocabulary has retired —
156
156
  // by dropping that part, so one stale row cannot fail a whole thread.
157
- export { storedMessagesToCortex } from "./memory/conversation-display-replay.js";
157
+ export { storedMessagesToChat } from "./memory/conversation-display-replay.js";
158
+ export { toChatFrame, applyChatFrame, checkChatPart } from "./contracts/chat-frame.js";
158
159
  export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./contracts/part-registry.js";
159
160
  // The source grammar of a `structure` presentation card — a host re-runs the same parse over a
160
161
  // persisted `url` before it fetches, so the rule lives in one place for both sides.
@@ -270,6 +271,7 @@ export { registerSandboxStep } from "./workflows/sandbox-step.js";
270
271
  // Nothing in the signature belongs to the durability engine, so an embedder
271
272
  // consumes run events without depending on it.
272
273
  export { createRunEventStream } from "./execution/run-event-stream.js";
274
+ export { pipeFoldedRunEvents } from "./execution/run-event-parts.js";
273
275
  // Sandbox-agent catalog. `buildAgent` maps a `SandboxAgentBuildContext` onto
274
276
  // `SandboxAgentDeps`, then selects the per-step agent by id from this record;
275
277
  // `SANDBOX_AGENT_META` is the planner-facing meta the same ids key.
@@ -5,12 +5,16 @@
5
5
  * readiness signal of the page, and gives back base64 screenshots. The eyes tool of a report session reads
6
6
  * this module.
7
7
  *
8
+ * The layout resolves at the CSS width of a reader, and the picture renders at half the device scale. A
9
+ * picture costs tokens in proportion to its area, thus the half scale lets one look hold a whole report.
10
+ *
8
11
  * A short page captures as one full-page shot. A tall page captures as consecutive vertical slices, because
9
- * one tall picture dies twice on the provider path: a picture past the hard dimension cap rejects the whole
10
- * request, and a legal tall picture downscales to about 1568 pixels on the long side, which compresses the
11
- * text past legibility. A slice of about two window heights survives both. The slice budget bounds what one
12
- * look costs, and a page past the budget truncates with the captured and the total pixels on the coverage,
13
- * thus the truncation is never silent.
12
+ * the model reads a picture whole only up to a limit on the long edge, and a taller picture downscales or
13
+ * refuses the request. The slice budget bounds what one look costs, and a page past the budget truncates
14
+ * with the captured and the total pixels on the coverage, thus the truncation is never silent.
15
+ *
16
+ * A capture can also take one block alone. The renderer marks each block with its id, and the capture clips
17
+ * the union box of the marked elements with a margin. A page that holds no such mark gives no picture.
14
18
  *
15
19
  * The readiness contract is the reason for one shared body. The renderer emits the event name and the
16
20
  * sentinel name, and `report-render/page.ts` owns both constants together with the two budgets. This module
@@ -45,6 +49,9 @@ export interface CapturedShot {
45
49
  * thus `capturedPx < totalPx` says that the slice budget ran out and the tail of the page is absent. `viewport`
46
50
  * appears when a screenshot threw and the retry at the window passed, thus the one picture shows the top
47
51
  * window alone and a section below the fold is absent from it.
52
+ *
53
+ * `block` is the box of one block and its margin; `capturedPx < totalPx` says that the slice budget cut it.
54
+ * `no-block` means that no element of the page carries the mark of the block, thus no picture exists.
48
55
  */
49
56
  export type CaptureCoverage = {
50
57
  readonly kind: "full";
@@ -54,10 +61,19 @@ export type CaptureCoverage = {
54
61
  readonly totalPx: number;
55
62
  } | {
56
63
  readonly kind: "viewport";
64
+ } | {
65
+ readonly kind: "block";
66
+ readonly capturedPx: number;
67
+ readonly totalPx: number;
68
+ } | {
69
+ readonly kind: "no-block";
57
70
  };
58
71
  /** The pictures and the faults of one page capture. */
59
72
  export interface PageCapture {
60
- /** The pictures in document order: one shot under `full` and `viewport`, the slices under `tiled`. */
73
+ /**
74
+ * The pictures in document order: one shot under `full` and `viewport`, the slices under `tiled` and
75
+ * `block`, and none under `no-block`.
76
+ */
61
77
  screenshots: CapturedShot[];
62
78
  coverage: CaptureCoverage;
63
79
  consoleErrors: string[];
@@ -68,13 +84,15 @@ export interface PageCapture {
68
84
  * speaks the throw protocol, because the chrome connection does. A test injects a seam that reads no
69
85
  * browser, thus a tool orchestration runs with no chrome sidecar.
70
86
  */
71
- export type CapturePage = (url: string) => Promise<PageCapture>;
72
- /** The extra settle steps that one call site needs. A call site that needs neither passes nothing. */
87
+ export type CapturePage = (url: string, options?: CaptureOptions) => Promise<PageCapture>;
88
+ /** The extra settle steps and the target of one capture. A call site that needs none passes nothing. */
73
89
  export interface CaptureOptions {
74
90
  /** A CSS selector to wait for after the readiness signal. The wait is best-effort. */
75
91
  readonly waitForSelector?: string;
76
92
  /** An extra settle time in milliseconds after the readiness signal, for a late paint. */
77
93
  readonly waitMs?: number;
94
+ /** The id of the one block to capture. Absent, the capture takes the whole document. */
95
+ readonly blockId?: string;
78
96
  }
79
97
  /**
80
98
  * Capture one page: the screenshots, the console errors, and the failed requests.
@@ -82,7 +100,7 @@ export interface CaptureOptions {
82
100
  * The pictures hold the document, and not the window alone. Thus a caller can judge a section that a reader
83
101
  * reaches by a scroll. A short page arrives as one full-page shot, and a tall page arrives as consecutive
84
102
  * slices in document order. A refused bitmap degrades to the window, and the coverage of the result names
85
- * what the pictures hold.
103
+ * what the pictures hold. A capture that names a block holds that block alone.
86
104
  *
87
105
  * The readiness wait is best-effort. A page that never signals still captures at the readiness budget, thus
88
106
  * a broken page gives a picture that shows what broke.
@@ -5,12 +5,16 @@
5
5
  * readiness signal of the page, and gives back base64 screenshots. The eyes tool of a report session reads
6
6
  * this module.
7
7
  *
8
+ * The layout resolves at the CSS width of a reader, and the picture renders at half the device scale. A
9
+ * picture costs tokens in proportion to its area, thus the half scale lets one look hold a whole report.
10
+ *
8
11
  * A short page captures as one full-page shot. A tall page captures as consecutive vertical slices, because
9
- * one tall picture dies twice on the provider path: a picture past the hard dimension cap rejects the whole
10
- * request, and a legal tall picture downscales to about 1568 pixels on the long side, which compresses the
11
- * text past legibility. A slice of about two window heights survives both. The slice budget bounds what one
12
- * look costs, and a page past the budget truncates with the captured and the total pixels on the coverage,
13
- * thus the truncation is never silent.
12
+ * the model reads a picture whole only up to a limit on the long edge, and a taller picture downscales or
13
+ * refuses the request. The slice budget bounds what one look costs, and a page past the budget truncates
14
+ * with the captured and the total pixels on the coverage, thus the truncation is never silent.
15
+ *
16
+ * A capture can also take one block alone. The renderer marks each block with its id, and the capture clips
17
+ * the union box of the marked elements with a margin. A page that holds no such mark gives no picture.
14
18
  *
15
19
  * The readiness contract is the reason for one shared body. The renderer emits the event name and the
16
20
  * sentinel name, and `report-render/page.ts` owns both constants together with the two budgets. This module
@@ -26,6 +30,7 @@
26
30
  */
27
31
  import { withPage } from "./chrome.js";
28
32
  import { PAGE_NAV_TIMEOUT_MS, PAGE_READY_TIMEOUT_MS, THEME_READY_EVENT, THEME_READY_SENTINEL } from "../report-render/page.js";
33
+ import { BLOCK_ID_ATTRIBUTE } from "../report-render/views/block-mark.js";
29
34
  /** The budget of the optional selector wait. The wait is best-effort, thus a miss captures the page anyway. */
30
35
  const SELECTOR_TIMEOUT_MS = 5_000;
31
36
  /**
@@ -37,22 +42,22 @@ const SELECTOR_TIMEOUT_MS = 5_000;
37
42
  const VIEWPORT_WIDTH = 1440;
38
43
  const VIEWPORT_HEIGHT = 900;
39
44
  /**
40
- * The height of one capture slice, in CSS pixels, and the bound of a single-shot page.
41
- *
42
- * The provider downscales every picture to about 1568 pixels on the long side before the model reads it. Two
43
- * window heights survive that downscale with readable text, and a taller picture reaches the model compressed
44
- * past that. Thus a page at this height or under captures as one full-page shot, and a taller page captures
45
- * as slices of this height.
45
+ * The device scale of one capture. The layout keeps the CSS width of a reader, and the picture holds half
46
+ * the pixels on each side. A picture costs about one token for each 750 pixels of its area.
46
47
  */
47
- const TILE_HEIGHT_PX = VIEWPORT_HEIGHT * 2;
48
+ const DEVICE_SCALE_FACTOR = 0.5;
48
49
  /**
49
- * The most slices of one capture.
50
- *
51
- * Each slice is one picture on the tool result, and the budget bounds what one look costs the context. A page
52
- * taller than the budget covers truncates, and the coverage carries the captured and the total pixels, thus
53
- * the truncation is never silent.
50
+ * The height of one slice and the bound of a single-shot page, in CSS pixels. At the half scale a slice is
51
+ * 720 by 2000 pixels, under the long edge of 2576 pixels that the model reads with no downscale.
54
52
  */
55
- const MAX_TILES = 6;
53
+ const TILE_HEIGHT_PX = 4_000;
54
+ /**
55
+ * The most slices of one capture: 20,000 CSS pixels, about 9,600 tokens, thus a report of 16,000 pixels
56
+ * fits whole. A taller page truncates, and the coverage carries the captured and the total pixels.
57
+ */
58
+ const MAX_TILES = 5;
59
+ /** The margin around the box of one block, in CSS pixels. Content that overflows its box stays in the picture. */
60
+ const BLOCK_MARGIN_PX = 16;
56
61
  /**
57
62
  * The body of the readiness wait, in the browser context. The sentinel arm resolves a page that dispatched
58
63
  * the event before this wait registered, thus a plain listener never blocks forever. The timer arm bounds a
@@ -94,26 +99,67 @@ async function measureTotalHeight(page) {
94
99
  return typeof measured === "number" && Number.isFinite(measured) ? measured : 0;
95
100
  }
96
101
  /**
97
- * Capture the slices of one tall page, in document order. Each slice clips {@link TILE_HEIGHT_PX} rows at the
98
- * reader width, and the last slice ends at the document height or at the budget, whichever comes first.
102
+ * Capture the rows of one area as slices, in document order. Each slice clips {@link TILE_HEIGHT_PX} rows,
103
+ * and the last slice ends at the area or at the budget, whichever comes first.
99
104
  */
100
- async function captureTiles(page, totalPx) {
101
- const tileCount = Math.min(Math.ceil(totalPx / TILE_HEIGHT_PX), MAX_TILES);
105
+ async function captureSlices(page, area) {
106
+ const heightPx = area.toY - area.fromY;
107
+ const tileCount = Math.min(Math.ceil(heightPx / TILE_HEIGHT_PX), MAX_TILES);
102
108
  const screenshots = [];
103
109
  for (let index = 0; index < tileCount; index++) {
104
- const fromY = index * TILE_HEIGHT_PX;
105
- const toY = Math.min(fromY + TILE_HEIGHT_PX, totalPx);
106
- const clip = { x: 0, y: fromY, width: VIEWPORT_WIDTH, height: toY - fromY };
110
+ const fromY = area.fromY + index * TILE_HEIGHT_PX;
111
+ const toY = Math.min(fromY + TILE_HEIGHT_PX, area.toY);
112
+ const clip = { x: area.x, y: fromY, width: area.width, height: toY - fromY };
107
113
  screenshots.push({ base64: toBase64(await page.screenshot({ encoding: "base64", clip })), range: { fromY, toY } });
108
114
  }
109
- const capturedPx = Math.min(tileCount * TILE_HEIGHT_PX, totalPx);
110
- return { screenshots, coverage: { kind: "tiled", capturedPx, totalPx } };
115
+ return { screenshots, capturedPx: Math.min(tileCount * TILE_HEIGHT_PX, heightPx) };
116
+ }
117
+ /**
118
+ * The body of the block measure, in the browser context: the union box of the marked elements, with the
119
+ * margin, or `null`. The body compares each attribute value, thus an id never becomes part of a selector.
120
+ */
121
+ function measureBlock(attribute, blockId, margin) {
122
+ let left = Number.POSITIVE_INFINITY;
123
+ let top = Number.POSITIVE_INFINITY;
124
+ let right = Number.NEGATIVE_INFINITY;
125
+ let bottom = Number.NEGATIVE_INFINITY;
126
+ for (const node of Array.from(document.querySelectorAll(`[${attribute}]`))) {
127
+ if (node.getAttribute(attribute) !== blockId)
128
+ continue;
129
+ const rect = node.getBoundingClientRect();
130
+ left = Math.min(left, rect.left + window.scrollX);
131
+ top = Math.min(top, rect.top + window.scrollY);
132
+ right = Math.max(right, rect.right + window.scrollX);
133
+ bottom = Math.max(bottom, rect.bottom + window.scrollY);
134
+ }
135
+ if (left === Number.POSITIVE_INFINITY) {
136
+ return null;
137
+ }
138
+ const root = document.documentElement;
139
+ const x = Math.max(0, Math.floor(left - margin));
140
+ const fromY = Math.max(0, Math.floor(top - margin));
141
+ const toX = Math.min(root.scrollWidth, Math.ceil(right + margin));
142
+ const toY = Math.min(root.scrollHeight, Math.ceil(bottom + margin));
143
+ // A block of no height still gives a strip, thus the picture shows the empty place of the block.
144
+ return { x, width: Math.max(1, toX - x), fromY, toY: Math.max(fromY + 1, toY) };
145
+ }
146
+ /**
147
+ * Take the pictures of one block. A refused bitmap propagates, because the window shows the top of the page
148
+ * and not the block.
149
+ */
150
+ async function captureBlock(page, blockId) {
151
+ const area = await page.evaluate(measureBlock, BLOCK_ID_ATTRIBUTE, blockId, BLOCK_MARGIN_PX);
152
+ if (area === null) {
153
+ return { screenshots: [], coverage: { kind: "no-block" } };
154
+ }
155
+ const sliced = await captureSlices(page, area);
156
+ return { screenshots: sliced.screenshots, coverage: { kind: "block", capturedPx: sliced.capturedPx, totalPx: area.toY - area.fromY } };
111
157
  }
112
158
  /**
113
159
  * Take the pictures of one settled page.
114
160
  *
115
161
  * A page at the single-shot bound or under gives one full-page shot. A taller page gives consecutive slices,
116
- * because the provider path compresses or rejects one tall picture; the module comment carries the account.
162
+ * because the model downscales or refuses one tall picture; the module comment carries the account.
117
163
  *
118
164
  * The compositor can refuse a bitmap of either shape while the bitmap of the window is fine. A degraded
119
165
  * picture beats a dead look, thus a refusal retries one time at the window. A second throw names a broken
@@ -122,8 +168,10 @@ async function captureTiles(page, totalPx) {
122
168
  async function captureShots(page) {
123
169
  const totalPx = await measureTotalHeight(page);
124
170
  try {
125
- if (totalPx > TILE_HEIGHT_PX)
126
- return await captureTiles(page, totalPx);
171
+ if (totalPx > TILE_HEIGHT_PX) {
172
+ const sliced = await captureSlices(page, { x: 0, width: VIEWPORT_WIDTH, fromY: 0, toY: totalPx });
173
+ return { screenshots: sliced.screenshots, coverage: { kind: "tiled", capturedPx: sliced.capturedPx, totalPx } };
174
+ }
127
175
  return { screenshots: [{ base64: toBase64(await page.screenshot({ encoding: "base64", fullPage: true })) }], coverage: { kind: "full" } };
128
176
  }
129
177
  catch (refused) {
@@ -146,7 +194,7 @@ async function captureShots(page) {
146
194
  * The pictures hold the document, and not the window alone. Thus a caller can judge a section that a reader
147
195
  * reaches by a scroll. A short page arrives as one full-page shot, and a tall page arrives as consecutive
148
196
  * slices in document order. A refused bitmap degrades to the window, and the coverage of the result names
149
- * what the pictures hold.
197
+ * what the pictures hold. A capture that names a block holds that block alone.
150
198
  *
151
199
  * The readiness wait is best-effort. A page that never signals still captures at the readiness budget, thus
152
200
  * a broken page gives a picture that shows what broke.
@@ -165,7 +213,7 @@ export function capturePage(chrome, url, options = {}) {
165
213
  });
166
214
  // The size is set before the navigation, because a layout resolves at load time. The connection gives
167
215
  // a small default window, and that window collapses each multi-column band of the design.
168
- await page.setViewport({ width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT });
216
+ await page.setViewport({ width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT, deviceScaleFactor: DEVICE_SCALE_FACTOR });
169
217
  // The preference is active before the navigation, because the page reveals its sections as it loads.
170
218
  // A preference that arrives after the load reaches a page that already runs its transitions.
171
219
  await page.emulateMediaFeatures([{ name: "prefers-reduced-motion", value: "reduce" }]);
@@ -185,7 +233,7 @@ export function capturePage(chrome, url, options = {}) {
185
233
  }
186
234
  // The pictures must show the whole document at the layout that a reader gets. Thus a defect below the
187
235
  // fold is visible, and a question about content that never appeared has an answer.
188
- const shots = await captureShots(page);
236
+ const shots = options.blockId === undefined ? await captureShots(page) : await captureBlock(page, options.blockId);
189
237
  return {
190
238
  screenshots: shots.screenshots,
191
239
  coverage: shots.coverage,
@@ -3,10 +3,15 @@ import type { ToolMask } from "./tool-mask.js";
3
3
  import type { LoopMessage } from "./types.js";
4
4
  /** The cap of requests of one compaction exchange: up to 3 rounds of memory edits, and then the summary. */
5
5
  export declare const COMPACTION_MAX_REQUESTS = 4;
6
- /** How the loop compacts its conversation when the view passes the budget. */
7
- export interface CompactionPolicy {
8
- /** The budget of the view, in estimated tokens. */
6
+ /** When an agent compacts its conversation, in the input tokens that the provider reported for the last request. */
7
+ export interface CompactionRules {
8
+ /** The budget before each request of a turn. */
9
9
  readonly budget: number;
10
+ /** The budget before the user message of a turn joins the conversation. Absent: no compaction before the user message. */
11
+ readonly turnStartBudget?: number;
12
+ }
13
+ /** How the loop compacts its conversation when the last request passed a budget. */
14
+ export interface CompactionPolicy extends CompactionRules {
10
15
  /** The provider of the conversation, with no text stream to the surface: the summary is no reply. */
11
16
  readonly provider: AgentChat;
12
17
  /** The text of the compaction request. */