@diyor28/context 1.0.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.
- package/README.md +270 -0
- package/dist/__tests__/attachment-selector.test.d.ts +11 -0
- package/dist/__tests__/attachment-selector.test.d.ts.map +1 -0
- package/dist/__tests__/attachment-selector.test.js +449 -0
- package/dist/__tests__/attachment-selector.test.js.map +1 -0
- package/dist/__tests__/cache-breakpoints.test.d.ts +11 -0
- package/dist/__tests__/cache-breakpoints.test.d.ts.map +1 -0
- package/dist/__tests__/cache-breakpoints.test.js +398 -0
- package/dist/__tests__/cache-breakpoints.test.js.map +1 -0
- package/dist/__tests__/codecs.test.d.ts +7 -0
- package/dist/__tests__/codecs.test.d.ts.map +1 -0
- package/dist/__tests__/codecs.test.js +331 -0
- package/dist/__tests__/codecs.test.js.map +1 -0
- package/dist/__tests__/compactor.test.d.ts +11 -0
- package/dist/__tests__/compactor.test.d.ts.map +1 -0
- package/dist/__tests__/compactor.test.js +519 -0
- package/dist/__tests__/compactor.test.js.map +1 -0
- package/dist/__tests__/context-graph.test.d.ts +7 -0
- package/dist/__tests__/context-graph.test.d.ts.map +1 -0
- package/dist/__tests__/context-graph.test.js +262 -0
- package/dist/__tests__/context-graph.test.js.map +1 -0
- package/dist/__tests__/hash.test.d.ts +7 -0
- package/dist/__tests__/hash.test.d.ts.map +1 -0
- package/dist/__tests__/hash.test.js +228 -0
- package/dist/__tests__/hash.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +15 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +728 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/__tests__/kind-order.test.d.ts +7 -0
- package/dist/__tests__/kind-order.test.d.ts.map +1 -0
- package/dist/__tests__/kind-order.test.js +243 -0
- package/dist/__tests__/kind-order.test.js.map +1 -0
- package/dist/__tests__/phase2-integration.test.d.ts +5 -0
- package/dist/__tests__/phase2-integration.test.d.ts.map +1 -0
- package/dist/__tests__/phase2-integration.test.js +222 -0
- package/dist/__tests__/phase2-integration.test.js.map +1 -0
- package/dist/__tests__/queries.test.d.ts +7 -0
- package/dist/__tests__/queries.test.d.ts.map +1 -0
- package/dist/__tests__/queries.test.js +254 -0
- package/dist/__tests__/queries.test.js.map +1 -0
- package/dist/__tests__/token-estimator.test.d.ts +7 -0
- package/dist/__tests__/token-estimator.test.d.ts.map +1 -0
- package/dist/__tests__/token-estimator.test.js +267 -0
- package/dist/__tests__/token-estimator.test.js.map +1 -0
- package/dist/adapters/anthropic-estimator.d.ts +38 -0
- package/dist/adapters/anthropic-estimator.d.ts.map +1 -0
- package/dist/adapters/anthropic-estimator.js +108 -0
- package/dist/adapters/anthropic-estimator.js.map +1 -0
- package/dist/adapters/attachment-resolver.d.ts +96 -0
- package/dist/adapters/attachment-resolver.d.ts.map +1 -0
- package/dist/adapters/attachment-resolver.js +176 -0
- package/dist/adapters/attachment-resolver.js.map +1 -0
- package/dist/adapters/attachment-selector.d.ts +59 -0
- package/dist/adapters/attachment-selector.d.ts.map +1 -0
- package/dist/adapters/attachment-selector.js +163 -0
- package/dist/adapters/attachment-selector.js.map +1 -0
- package/dist/adapters/gemini-estimator.d.ts +27 -0
- package/dist/adapters/gemini-estimator.d.ts.map +1 -0
- package/dist/adapters/gemini-estimator.js +80 -0
- package/dist/adapters/gemini-estimator.js.map +1 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +28 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/memory-store.d.ts +139 -0
- package/dist/adapters/memory-store.d.ts.map +1 -0
- package/dist/adapters/memory-store.js +187 -0
- package/dist/adapters/memory-store.js.map +1 -0
- package/dist/adapters/openai-estimator.d.ts +35 -0
- package/dist/adapters/openai-estimator.d.ts.map +1 -0
- package/dist/adapters/openai-estimator.js +89 -0
- package/dist/adapters/openai-estimator.js.map +1 -0
- package/dist/adapters/summarizer.d.ts +121 -0
- package/dist/adapters/summarizer.d.ts.map +1 -0
- package/dist/adapters/summarizer.js +121 -0
- package/dist/adapters/summarizer.js.map +1 -0
- package/dist/adapters/token-estimator.d.ts +63 -0
- package/dist/adapters/token-estimator.d.ts.map +1 -0
- package/dist/adapters/token-estimator.js +37 -0
- package/dist/adapters/token-estimator.js.map +1 -0
- package/dist/builder/context-builder.d.ts +186 -0
- package/dist/builder/context-builder.d.ts.map +1 -0
- package/dist/builder/context-builder.js +305 -0
- package/dist/builder/context-builder.js.map +1 -0
- package/dist/builder/context-fork.d.ts +166 -0
- package/dist/builder/context-fork.d.ts.map +1 -0
- package/dist/builder/context-fork.js +282 -0
- package/dist/builder/context-fork.js.map +1 -0
- package/dist/builder/index.d.ts +6 -0
- package/dist/builder/index.d.ts.map +1 -0
- package/dist/builder/index.js +22 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/codecs/base.d.ts +18 -0
- package/dist/codecs/base.d.ts.map +1 -0
- package/dist/codecs/base.js +39 -0
- package/dist/codecs/base.js.map +1 -0
- package/dist/codecs/conversation-history.codec.d.ts +81 -0
- package/dist/codecs/conversation-history.codec.d.ts.map +1 -0
- package/dist/codecs/conversation-history.codec.js +89 -0
- package/dist/codecs/conversation-history.codec.js.map +1 -0
- package/dist/codecs/index.d.ts +31 -0
- package/dist/codecs/index.d.ts.map +1 -0
- package/dist/codecs/index.js +71 -0
- package/dist/codecs/index.js.map +1 -0
- package/dist/codecs/redacted-stub.codec.d.ts +32 -0
- package/dist/codecs/redacted-stub.codec.d.ts.map +1 -0
- package/dist/codecs/redacted-stub.codec.js +64 -0
- package/dist/codecs/redacted-stub.codec.js.map +1 -0
- package/dist/codecs/structured-reference.codec.d.ts +40 -0
- package/dist/codecs/structured-reference.codec.d.ts.map +1 -0
- package/dist/codecs/structured-reference.codec.js +81 -0
- package/dist/codecs/structured-reference.codec.js.map +1 -0
- package/dist/codecs/system-rules.codec.d.ts +32 -0
- package/dist/codecs/system-rules.codec.d.ts.map +1 -0
- package/dist/codecs/system-rules.codec.js +62 -0
- package/dist/codecs/system-rules.codec.js.map +1 -0
- package/dist/codecs/tool-output.codec.d.ts +66 -0
- package/dist/codecs/tool-output.codec.d.ts.map +1 -0
- package/dist/codecs/tool-output.codec.js +95 -0
- package/dist/codecs/tool-output.codec.js.map +1 -0
- package/dist/codecs/tool-schema.codec.d.ts +36 -0
- package/dist/codecs/tool-schema.codec.d.ts.map +1 -0
- package/dist/codecs/tool-schema.codec.js +74 -0
- package/dist/codecs/tool-schema.codec.js.map +1 -0
- package/dist/codecs/unsafe-text.codec.d.ts +28 -0
- package/dist/codecs/unsafe-text.codec.d.ts.map +1 -0
- package/dist/codecs/unsafe-text.codec.js +63 -0
- package/dist/codecs/unsafe-text.codec.js.map +1 -0
- package/dist/graph/context-graph.d.ts +121 -0
- package/dist/graph/context-graph.d.ts.map +1 -0
- package/dist/graph/context-graph.js +166 -0
- package/dist/graph/context-graph.js.map +1 -0
- package/dist/graph/index.d.ts +8 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +24 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/kind-order.d.ts +60 -0
- package/dist/graph/kind-order.d.ts.map +1 -0
- package/dist/graph/kind-order.js +113 -0
- package/dist/graph/kind-order.js.map +1 -0
- package/dist/graph/queries.d.ts +68 -0
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +240 -0
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/views.d.ts +90 -0
- package/dist/graph/views.d.ts.map +1 -0
- package/dist/graph/views.js +173 -0
- package/dist/graph/views.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/compactor.d.ts +128 -0
- package/dist/pipeline/compactor.d.ts.map +1 -0
- package/dist/pipeline/compactor.js +346 -0
- package/dist/pipeline/compactor.js.map +1 -0
- package/dist/pipeline/index.d.ts +6 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +22 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/summarizer.d.ts +18 -0
- package/dist/pipeline/summarizer.d.ts.map +1 -0
- package/dist/pipeline/summarizer.js +68 -0
- package/dist/pipeline/summarizer.js.map +1 -0
- package/dist/policies/default-policy.d.ts +29 -0
- package/dist/policies/default-policy.d.ts.map +1 -0
- package/dist/policies/default-policy.js +58 -0
- package/dist/policies/default-policy.js.map +1 -0
- package/dist/policies/index.d.ts +5 -0
- package/dist/policies/index.d.ts.map +1 -0
- package/dist/policies/index.js +21 -0
- package/dist/policies/index.js.map +1 -0
- package/dist/providers/anthropic-compiler.d.ts +58 -0
- package/dist/providers/anthropic-compiler.d.ts.map +1 -0
- package/dist/providers/anthropic-compiler.js +182 -0
- package/dist/providers/anthropic-compiler.js.map +1 -0
- package/dist/providers/capabilities.d.ts +54 -0
- package/dist/providers/capabilities.d.ts.map +1 -0
- package/dist/providers/capabilities.js +87 -0
- package/dist/providers/capabilities.js.map +1 -0
- package/dist/providers/gemini-compiler.d.ts +51 -0
- package/dist/providers/gemini-compiler.d.ts.map +1 -0
- package/dist/providers/gemini-compiler.js +206 -0
- package/dist/providers/gemini-compiler.js.map +1 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +24 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai-compiler.d.ts +46 -0
- package/dist/providers/openai-compiler.d.ts.map +1 -0
- package/dist/providers/openai-compiler.js +149 -0
- package/dist/providers/openai-compiler.js.map +1 -0
- package/dist/types/attachment.d.ts +62 -0
- package/dist/types/attachment.d.ts.map +1 -0
- package/dist/types/attachment.js +6 -0
- package/dist/types/attachment.js.map +1 -0
- package/dist/types/block.d.ts +61 -0
- package/dist/types/block.d.ts.map +1 -0
- package/dist/types/block.js +8 -0
- package/dist/types/block.js.map +1 -0
- package/dist/types/codec.d.ts +58 -0
- package/dist/types/codec.d.ts.map +1 -0
- package/dist/types/codec.js +6 -0
- package/dist/types/codec.js.map +1 -0
- package/dist/types/compiled.d.ts +91 -0
- package/dist/types/compiled.d.ts.map +1 -0
- package/dist/types/compiled.js +6 -0
- package/dist/types/compiled.js.map +1 -0
- package/dist/types/hash.d.ts +24 -0
- package/dist/types/hash.d.ts.map +1 -0
- package/dist/types/hash.js +49 -0
- package/dist/types/hash.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +26 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/policy.d.ts +128 -0
- package/dist/types/policy.d.ts.map +1 -0
- package/dist/types/policy.js +55 -0
- package/dist/types/policy.js.map +1 -0
- package/package.json +55 -0
- package/postcss.config.js +4 -0
- package/src/__tests__/attachment-selector.test.ts +559 -0
- package/src/__tests__/cache-breakpoints.test.ts +566 -0
- package/src/__tests__/codecs.test.ts +417 -0
- package/src/__tests__/compactor.test.ts +608 -0
- package/src/__tests__/context-graph.test.ts +383 -0
- package/src/__tests__/hash.test.ts +274 -0
- package/src/__tests__/integration.test.ts +866 -0
- package/src/__tests__/kind-order.test.ts +312 -0
- package/src/__tests__/phase2-integration.test.ts +253 -0
- package/src/__tests__/queries.test.ts +387 -0
- package/src/__tests__/token-estimator.test.ts +326 -0
- package/src/adapters/anthropic-estimator.ts +125 -0
- package/src/adapters/attachment-resolver.ts +295 -0
- package/src/adapters/attachment-selector.ts +218 -0
- package/src/adapters/gemini-estimator.ts +93 -0
- package/src/adapters/index.ts +12 -0
- package/src/adapters/memory-store.ts +299 -0
- package/src/adapters/openai-estimator.ts +105 -0
- package/src/adapters/summarizer.ts +250 -0
- package/src/adapters/token-estimator.ts +74 -0
- package/src/builder/context-builder.ts +467 -0
- package/src/builder/context-fork.ts +471 -0
- package/src/builder/index.ts +6 -0
- package/src/codecs/base.ts +36 -0
- package/src/codecs/conversation-history.codec.ts +108 -0
- package/src/codecs/index.ts +57 -0
- package/src/codecs/redacted-stub.codec.ts +76 -0
- package/src/codecs/structured-reference.codec.ts +96 -0
- package/src/codecs/system-rules.codec.ts +74 -0
- package/src/codecs/tool-output.codec.ts +109 -0
- package/src/codecs/tool-schema.codec.ts +87 -0
- package/src/codecs/unsafe-text.codec.ts +74 -0
- package/src/graph/context-graph.ts +205 -0
- package/src/graph/index.ts +8 -0
- package/src/graph/kind-order.ts +125 -0
- package/src/graph/queries.ts +306 -0
- package/src/graph/views.ts +255 -0
- package/src/index.ts +31 -0
- package/src/pipeline/compactor.ts +563 -0
- package/src/pipeline/index.ts +6 -0
- package/src/pipeline/summarizer.ts +76 -0
- package/src/policies/default-policy.ts +69 -0
- package/src/policies/index.ts +5 -0
- package/src/providers/anthropic-compiler.ts +294 -0
- package/src/providers/capabilities.ts +144 -0
- package/src/providers/gemini-compiler.ts +272 -0
- package/src/providers/index.ts +8 -0
- package/src/providers/openai-compiler.ts +191 -0
- package/src/types/attachment.ts +86 -0
- package/src/types/block.ts +84 -0
- package/src/types/codec.ts +68 -0
- package/src/types/compiled.ts +109 -0
- package/src/types/hash.ts +58 -0
- package/src/types/index.ts +10 -0
- package/src/types/policy.ts +194 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +21 -0
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compactor: View-based context compaction with provenance tracking.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Prune tool outputs (keep errors, truncate large outputs)
|
|
6
|
+
* - Deduplicate identical blocks
|
|
7
|
+
* - Trim conversation history (keep recent + errors)
|
|
8
|
+
* - Summarize history (optional, needs Summarizer)
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: View-based compaction never mutates the input graph.
|
|
11
|
+
* Creates replacement blocks with full provenance (derivedFrom, method, version).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { ContextBlock, BlockRef, BlockKind } from '../types/block.js';
|
|
15
|
+
import type { ContextView } from '../graph/views.js';
|
|
16
|
+
import { computeBlockHash } from '../types/hash.js';
|
|
17
|
+
import type { TokenEstimator } from '../adapters/token-estimator.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compaction step identifier.
|
|
21
|
+
*/
|
|
22
|
+
export type CompactionStep =
|
|
23
|
+
| 'dedupe' // Remove duplicate blocks
|
|
24
|
+
| 'tool_output_prune' // Prune large tool outputs
|
|
25
|
+
| 'history_trim' // Trim conversation history
|
|
26
|
+
| 'summarize_history'; // Summarize old history
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* History compaction summarizer interface.
|
|
30
|
+
* Implementations use LLM to condense old conversation history.
|
|
31
|
+
*
|
|
32
|
+
* Note: This is different from the structured Summarizer in adapters/summarizer.ts
|
|
33
|
+
* which is designed for schema-validated outputs with provenance tracking.
|
|
34
|
+
*/
|
|
35
|
+
export interface HistorySummarizer {
|
|
36
|
+
/**
|
|
37
|
+
* Summarize a list of history blocks into a single summary block.
|
|
38
|
+
*
|
|
39
|
+
* @param blocks - History blocks to summarize
|
|
40
|
+
* @param targetTokens - Target token count for summary
|
|
41
|
+
* @returns Summary block replacing the input blocks
|
|
42
|
+
*/
|
|
43
|
+
summarize(
|
|
44
|
+
blocks: ContextBlock[],
|
|
45
|
+
targetTokens: number
|
|
46
|
+
): Promise<ContextBlock>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Tool output pruning configuration.
|
|
51
|
+
*/
|
|
52
|
+
export interface ToolOutputPruningConfig {
|
|
53
|
+
/** Maximum raw tail characters to keep (default: 500) */
|
|
54
|
+
maxRawTailChars: number;
|
|
55
|
+
|
|
56
|
+
/** Preserve error tail even if large (default: true) */
|
|
57
|
+
preserveErrorTail: boolean;
|
|
58
|
+
|
|
59
|
+
/** Maximum outputs per tool type (default: 3) */
|
|
60
|
+
maxOutputsPerTool: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Compaction configuration for the pipeline.
|
|
65
|
+
*/
|
|
66
|
+
export interface PipelineCompactionConfig {
|
|
67
|
+
/** Compaction steps to apply (in order) */
|
|
68
|
+
steps: CompactionStep[];
|
|
69
|
+
|
|
70
|
+
/** Tool output pruning config */
|
|
71
|
+
toolOutputPruning?: ToolOutputPruningConfig;
|
|
72
|
+
|
|
73
|
+
/** History trim config */
|
|
74
|
+
historyTrim?: {
|
|
75
|
+
/** Keep most recent N messages */
|
|
76
|
+
keepRecentMessages: number;
|
|
77
|
+
|
|
78
|
+
/** Always keep messages with errors */
|
|
79
|
+
keepErrorMessages: boolean;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Summarization config (optional, requires HistorySummarizer) */
|
|
83
|
+
summarization?: {
|
|
84
|
+
/** Minimum messages to trigger summarization */
|
|
85
|
+
minMessages: number;
|
|
86
|
+
|
|
87
|
+
/** Summarizer to use for history compaction */
|
|
88
|
+
summarizer?: HistorySummarizer;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Compaction result.
|
|
94
|
+
*/
|
|
95
|
+
export interface CompactionResult {
|
|
96
|
+
/** Compacted blocks (includes replacements) */
|
|
97
|
+
blocks: ContextBlock[];
|
|
98
|
+
|
|
99
|
+
/** Blocks that were removed */
|
|
100
|
+
removedBlocks: ContextBlock[];
|
|
101
|
+
|
|
102
|
+
/** Compaction report */
|
|
103
|
+
report: CompactionReport;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Compaction report with token savings and lossiness flags.
|
|
108
|
+
*/
|
|
109
|
+
export interface CompactionReport {
|
|
110
|
+
/** Tokens before compaction */
|
|
111
|
+
beforeTokens: number;
|
|
112
|
+
|
|
113
|
+
/** Tokens after compaction */
|
|
114
|
+
afterTokens: number;
|
|
115
|
+
|
|
116
|
+
/** Token savings */
|
|
117
|
+
savedTokens: number;
|
|
118
|
+
|
|
119
|
+
/** Compaction steps applied */
|
|
120
|
+
stepsApplied: CompactionStep[];
|
|
121
|
+
|
|
122
|
+
/** Step-specific reports */
|
|
123
|
+
stepReports: StepReport[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Per-step compaction report.
|
|
128
|
+
*/
|
|
129
|
+
export interface StepReport {
|
|
130
|
+
/** Step identifier */
|
|
131
|
+
step: CompactionStep;
|
|
132
|
+
|
|
133
|
+
/** Blocks removed */
|
|
134
|
+
blocksRemoved: number;
|
|
135
|
+
|
|
136
|
+
/** Blocks replaced */
|
|
137
|
+
blocksReplaced: number;
|
|
138
|
+
|
|
139
|
+
/** Tokens saved */
|
|
140
|
+
tokensSaved: number;
|
|
141
|
+
|
|
142
|
+
/** Lossy compaction (information lost) */
|
|
143
|
+
lossy: boolean;
|
|
144
|
+
|
|
145
|
+
/** Human-readable description */
|
|
146
|
+
description: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Default tool output pruning configuration.
|
|
151
|
+
*/
|
|
152
|
+
export const DEFAULT_TOOL_OUTPUT_PRUNING: ToolOutputPruningConfig = {
|
|
153
|
+
maxRawTailChars: 500,
|
|
154
|
+
preserveErrorTail: true,
|
|
155
|
+
maxOutputsPerTool: 3,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Compact a context view.
|
|
160
|
+
* Returns a new set of blocks with replacements tracked via provenance.
|
|
161
|
+
*
|
|
162
|
+
* @param view - Context view to compact
|
|
163
|
+
* @param config - Compaction configuration
|
|
164
|
+
* @param estimator - Token estimator for calculating savings
|
|
165
|
+
* @returns Compaction result
|
|
166
|
+
*/
|
|
167
|
+
export async function compactView(
|
|
168
|
+
view: ContextView,
|
|
169
|
+
config: PipelineCompactionConfig,
|
|
170
|
+
estimator: TokenEstimator
|
|
171
|
+
): Promise<CompactionResult> {
|
|
172
|
+
let blocks = [...view.blocks];
|
|
173
|
+
const removedBlocks: ContextBlock[] = [];
|
|
174
|
+
const stepReports: StepReport[] = [];
|
|
175
|
+
|
|
176
|
+
// Apply compaction steps in order
|
|
177
|
+
for (const step of config.steps) {
|
|
178
|
+
const beforeCount = blocks.length;
|
|
179
|
+
const beforeTokens = view.tokenEstimate?.tokens ?? 0;
|
|
180
|
+
|
|
181
|
+
switch (step) {
|
|
182
|
+
case 'dedupe': {
|
|
183
|
+
const result = deduplicateBlocks(blocks);
|
|
184
|
+
|
|
185
|
+
// Calculate token savings from removed duplicates
|
|
186
|
+
const removedEstimate = result.removed.length > 0
|
|
187
|
+
? await estimator.estimate(result.removed)
|
|
188
|
+
: { tokens: 0 };
|
|
189
|
+
|
|
190
|
+
blocks = result.blocks;
|
|
191
|
+
removedBlocks.push(...result.removed);
|
|
192
|
+
|
|
193
|
+
stepReports.push({
|
|
194
|
+
step,
|
|
195
|
+
blocksRemoved: result.removed.length,
|
|
196
|
+
blocksReplaced: 0,
|
|
197
|
+
tokensSaved: removedEstimate.tokens,
|
|
198
|
+
lossy: false,
|
|
199
|
+
description: `Removed ${result.removed.length} duplicate blocks`,
|
|
200
|
+
});
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
case 'tool_output_prune': {
|
|
205
|
+
const pruningConfig = config.toolOutputPruning ?? DEFAULT_TOOL_OUTPUT_PRUNING;
|
|
206
|
+
|
|
207
|
+
// Estimate tokens before pruning
|
|
208
|
+
const toolOutputBlocks = blocks.filter((b) => b.meta.kind === 'tool_output');
|
|
209
|
+
const beforeEstimate = toolOutputBlocks.length > 0
|
|
210
|
+
? await estimator.estimate(toolOutputBlocks)
|
|
211
|
+
: { tokens: 0 };
|
|
212
|
+
|
|
213
|
+
const result = pruneToolOutputs(blocks, pruningConfig);
|
|
214
|
+
|
|
215
|
+
// Estimate tokens after pruning (only tool output blocks)
|
|
216
|
+
const keptToolOutputs = result.blocks.filter((b) => b.meta.kind === 'tool_output');
|
|
217
|
+
const afterEstimate = keptToolOutputs.length > 0
|
|
218
|
+
? await estimator.estimate(keptToolOutputs)
|
|
219
|
+
: { tokens: 0 };
|
|
220
|
+
|
|
221
|
+
blocks = result.blocks;
|
|
222
|
+
removedBlocks.push(...result.removed);
|
|
223
|
+
|
|
224
|
+
stepReports.push({
|
|
225
|
+
step,
|
|
226
|
+
blocksRemoved: result.removed.length,
|
|
227
|
+
blocksReplaced: result.replaced.length,
|
|
228
|
+
tokensSaved: beforeEstimate.tokens - afterEstimate.tokens,
|
|
229
|
+
lossy: result.replaced.length > 0,
|
|
230
|
+
description: `Pruned ${result.replaced.length} tool outputs, removed ${result.removed.length}`,
|
|
231
|
+
});
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
case 'history_trim': {
|
|
236
|
+
const trimConfig = config.historyTrim ?? {
|
|
237
|
+
keepRecentMessages: 20,
|
|
238
|
+
keepErrorMessages: true,
|
|
239
|
+
};
|
|
240
|
+
const result = trimHistory(blocks, trimConfig);
|
|
241
|
+
|
|
242
|
+
// Calculate token savings from removed history blocks
|
|
243
|
+
const removedEstimate = result.removed.length > 0
|
|
244
|
+
? await estimator.estimate(result.removed)
|
|
245
|
+
: { tokens: 0 };
|
|
246
|
+
|
|
247
|
+
blocks = result.blocks;
|
|
248
|
+
removedBlocks.push(...result.removed);
|
|
249
|
+
|
|
250
|
+
stepReports.push({
|
|
251
|
+
step,
|
|
252
|
+
blocksRemoved: result.removed.length,
|
|
253
|
+
blocksReplaced: 0,
|
|
254
|
+
tokensSaved: removedEstimate.tokens,
|
|
255
|
+
lossy: result.removed.length > 0,
|
|
256
|
+
description: `Trimmed ${result.removed.length} old history messages`,
|
|
257
|
+
});
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
case 'summarize_history': {
|
|
262
|
+
const summaryConfig = config.summarization;
|
|
263
|
+
|
|
264
|
+
if (!summaryConfig?.summarizer) {
|
|
265
|
+
stepReports.push({
|
|
266
|
+
step,
|
|
267
|
+
blocksRemoved: 0,
|
|
268
|
+
blocksReplaced: 0,
|
|
269
|
+
tokensSaved: 0,
|
|
270
|
+
lossy: false,
|
|
271
|
+
description: 'Summarizer not configured, skipping',
|
|
272
|
+
});
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const historyBlocks = blocks.filter((b) => b.meta.kind === 'history');
|
|
277
|
+
|
|
278
|
+
if (historyBlocks.length < summaryConfig.minMessages) {
|
|
279
|
+
stepReports.push({
|
|
280
|
+
step,
|
|
281
|
+
blocksRemoved: 0,
|
|
282
|
+
blocksReplaced: 0,
|
|
283
|
+
tokensSaved: 0,
|
|
284
|
+
lossy: false,
|
|
285
|
+
description: `Insufficient history (${historyBlocks.length} < ${summaryConfig.minMessages})`,
|
|
286
|
+
});
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Split into recent (keep) and old (summarize)
|
|
291
|
+
const keepCount = 10; // Keep last 10 messages raw
|
|
292
|
+
const recent = historyBlocks.slice(-keepCount);
|
|
293
|
+
const old = historyBlocks.slice(0, -keepCount);
|
|
294
|
+
|
|
295
|
+
if (old.length === 0) {
|
|
296
|
+
stepReports.push({
|
|
297
|
+
step,
|
|
298
|
+
blocksRemoved: 0,
|
|
299
|
+
blocksReplaced: 0,
|
|
300
|
+
tokensSaved: 0,
|
|
301
|
+
lossy: false,
|
|
302
|
+
description: 'No old history to summarize',
|
|
303
|
+
});
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Estimate tokens before summarization
|
|
308
|
+
const beforeSummaryEstimate = await estimator.estimate(old);
|
|
309
|
+
const targetTokens = Math.floor(beforeSummaryEstimate.tokens * 0.3); // Compress to 30%
|
|
310
|
+
|
|
311
|
+
// Create summary block
|
|
312
|
+
const summaryBlock = await summaryConfig.summarizer.summarize(old, targetTokens);
|
|
313
|
+
|
|
314
|
+
// Estimate tokens for summary block
|
|
315
|
+
const afterSummaryEstimate = await estimator.estimateBlock(summaryBlock);
|
|
316
|
+
|
|
317
|
+
// Replace old blocks with summary
|
|
318
|
+
const nonHistoryBlocks = blocks.filter((b) => b.meta.kind !== 'history');
|
|
319
|
+
blocks = [...nonHistoryBlocks, summaryBlock, ...recent];
|
|
320
|
+
removedBlocks.push(...old);
|
|
321
|
+
|
|
322
|
+
stepReports.push({
|
|
323
|
+
step,
|
|
324
|
+
blocksRemoved: old.length,
|
|
325
|
+
blocksReplaced: 1,
|
|
326
|
+
tokensSaved: beforeSummaryEstimate.tokens - afterSummaryEstimate.tokens,
|
|
327
|
+
lossy: true,
|
|
328
|
+
description: `Summarized ${old.length} old messages into 1 summary block`,
|
|
329
|
+
});
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Calculate total savings - recalculate tokens for compacted blocks
|
|
336
|
+
const beforeTokens = view.tokenEstimate?.tokens ?? 0;
|
|
337
|
+
|
|
338
|
+
// Recalculate tokens for compacted blocks
|
|
339
|
+
const afterEstimate = blocks.length > 0
|
|
340
|
+
? await estimator.estimate(blocks)
|
|
341
|
+
: { tokens: 0 };
|
|
342
|
+
const afterTokens = afterEstimate.tokens;
|
|
343
|
+
const savedTokens = beforeTokens - afterTokens;
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
blocks,
|
|
347
|
+
removedBlocks,
|
|
348
|
+
report: {
|
|
349
|
+
beforeTokens,
|
|
350
|
+
afterTokens,
|
|
351
|
+
savedTokens,
|
|
352
|
+
stepsApplied: config.steps,
|
|
353
|
+
stepReports,
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Deduplicate identical blocks.
|
|
360
|
+
* Keeps first occurrence of each unique blockHash.
|
|
361
|
+
*
|
|
362
|
+
* @param blocks - Input blocks
|
|
363
|
+
* @returns Deduplicated blocks and removed duplicates
|
|
364
|
+
*/
|
|
365
|
+
function deduplicateBlocks(blocks: ContextBlock[]): {
|
|
366
|
+
blocks: ContextBlock[];
|
|
367
|
+
removed: ContextBlock[];
|
|
368
|
+
} {
|
|
369
|
+
const seen = new Set<string>();
|
|
370
|
+
const deduplicated: ContextBlock[] = [];
|
|
371
|
+
const removed: ContextBlock[] = [];
|
|
372
|
+
|
|
373
|
+
for (const block of blocks) {
|
|
374
|
+
if (seen.has(block.blockHash)) {
|
|
375
|
+
removed.push(block);
|
|
376
|
+
} else {
|
|
377
|
+
seen.add(block.blockHash);
|
|
378
|
+
deduplicated.push(block);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return { blocks: deduplicated, removed };
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Prune tool outputs.
|
|
387
|
+
* Keeps:
|
|
388
|
+
* - All error outputs (preserveErrorTail = true)
|
|
389
|
+
* - Last N outputs per tool type
|
|
390
|
+
* - Truncated version of large outputs (tail only)
|
|
391
|
+
*
|
|
392
|
+
* @param blocks - Input blocks
|
|
393
|
+
* @param config - Pruning configuration
|
|
394
|
+
* @returns Pruned blocks, removed blocks, and replaced blocks
|
|
395
|
+
*/
|
|
396
|
+
function pruneToolOutputs(
|
|
397
|
+
blocks: ContextBlock[],
|
|
398
|
+
config: ToolOutputPruningConfig
|
|
399
|
+
): {
|
|
400
|
+
blocks: ContextBlock[];
|
|
401
|
+
removed: ContextBlock[];
|
|
402
|
+
replaced: ContextBlock[];
|
|
403
|
+
} {
|
|
404
|
+
const toolOutputBlocks = blocks.filter((b) => b.meta.kind === 'tool_output');
|
|
405
|
+
const otherBlocks = blocks.filter((b) => b.meta.kind !== 'tool_output');
|
|
406
|
+
|
|
407
|
+
// Group by tool type (codecId)
|
|
408
|
+
const byTool = new Map<string, ContextBlock[]>();
|
|
409
|
+
for (const block of toolOutputBlocks) {
|
|
410
|
+
const toolId = block.meta.codecId;
|
|
411
|
+
if (!byTool.has(toolId)) {
|
|
412
|
+
byTool.set(toolId, []);
|
|
413
|
+
}
|
|
414
|
+
byTool.get(toolId)!.push(block);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const kept: ContextBlock[] = [];
|
|
418
|
+
const removed: ContextBlock[] = [];
|
|
419
|
+
const replaced: ContextBlock[] = [];
|
|
420
|
+
|
|
421
|
+
// For each tool type, keep recent outputs and prune old/large ones
|
|
422
|
+
for (const [toolId, toolBlocks] of byTool.entries()) {
|
|
423
|
+
// Sort by createdAt (most recent last)
|
|
424
|
+
const sorted = [...toolBlocks].sort((a, b) => a.meta.createdAt - b.meta.createdAt);
|
|
425
|
+
|
|
426
|
+
// Keep last N outputs
|
|
427
|
+
const toKeep = sorted.slice(-config.maxOutputsPerTool);
|
|
428
|
+
const toRemove = sorted.slice(0, -config.maxOutputsPerTool);
|
|
429
|
+
|
|
430
|
+
// Check if any outputs need truncation
|
|
431
|
+
for (const block of toKeep) {
|
|
432
|
+
const payload = block.payload as any;
|
|
433
|
+
|
|
434
|
+
// Check if output is large (needs truncation)
|
|
435
|
+
const isLarge = payload.output && typeof payload.output === 'string' && payload.output.length > config.maxRawTailChars;
|
|
436
|
+
const isError = payload.error || payload.status === 'error';
|
|
437
|
+
|
|
438
|
+
if (isLarge && (!isError || !config.preserveErrorTail)) {
|
|
439
|
+
// Create truncated replacement block
|
|
440
|
+
const truncatedPayload = {
|
|
441
|
+
...payload,
|
|
442
|
+
output: truncateTail(payload.output, config.maxRawTailChars),
|
|
443
|
+
_truncated: true,
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const replacementBlock = createReplacementBlock(
|
|
447
|
+
block,
|
|
448
|
+
truncatedPayload,
|
|
449
|
+
'tool_output_prune',
|
|
450
|
+
'1.0.0'
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
kept.push(replacementBlock);
|
|
454
|
+
replaced.push(block);
|
|
455
|
+
} else {
|
|
456
|
+
kept.push(block);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
removed.push(...toRemove);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
blocks: [...otherBlocks, ...kept],
|
|
465
|
+
removed,
|
|
466
|
+
replaced,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Trim conversation history.
|
|
472
|
+
* Keeps recent messages and optionally error messages.
|
|
473
|
+
*
|
|
474
|
+
* @param blocks - Input blocks
|
|
475
|
+
* @param config - Trim configuration
|
|
476
|
+
* @returns Trimmed blocks and removed blocks
|
|
477
|
+
*/
|
|
478
|
+
function trimHistory(
|
|
479
|
+
blocks: ContextBlock[],
|
|
480
|
+
config: { keepRecentMessages: number; keepErrorMessages: boolean }
|
|
481
|
+
): {
|
|
482
|
+
blocks: ContextBlock[];
|
|
483
|
+
removed: ContextBlock[];
|
|
484
|
+
} {
|
|
485
|
+
const historyBlocks = blocks.filter((b) => b.meta.kind === 'history');
|
|
486
|
+
const otherBlocks = blocks.filter((b) => b.meta.kind !== 'history');
|
|
487
|
+
|
|
488
|
+
if (historyBlocks.length === 0) {
|
|
489
|
+
return { blocks, removed: [] };
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Sort by createdAt
|
|
493
|
+
const sorted = [...historyBlocks].sort((a, b) => a.meta.createdAt - b.meta.createdAt);
|
|
494
|
+
|
|
495
|
+
// Keep recent messages
|
|
496
|
+
const recent = sorted.slice(-config.keepRecentMessages);
|
|
497
|
+
const old = sorted.slice(0, -config.keepRecentMessages);
|
|
498
|
+
|
|
499
|
+
// Optionally keep error messages from old
|
|
500
|
+
const errorMessages = config.keepErrorMessages
|
|
501
|
+
? old.filter((b) => {
|
|
502
|
+
const payload = b.payload as any;
|
|
503
|
+
return payload.messages?.some((m: any) => m.error);
|
|
504
|
+
})
|
|
505
|
+
: [];
|
|
506
|
+
|
|
507
|
+
const kept = [...recent, ...errorMessages];
|
|
508
|
+
const removed = old.filter((b) => !errorMessages.includes(b));
|
|
509
|
+
|
|
510
|
+
return {
|
|
511
|
+
blocks: [...otherBlocks, ...kept],
|
|
512
|
+
removed,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Truncate text to tail characters with ellipsis.
|
|
518
|
+
*
|
|
519
|
+
* @param text - Text to truncate
|
|
520
|
+
* @param maxChars - Maximum characters to keep
|
|
521
|
+
* @returns Truncated text
|
|
522
|
+
*/
|
|
523
|
+
function truncateTail(text: string, maxChars: number): string {
|
|
524
|
+
if (text.length <= maxChars) {
|
|
525
|
+
return text;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const tail = text.slice(-maxChars);
|
|
529
|
+
return `... [truncated ${text.length - maxChars} chars] ...\n${tail}`;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Create a replacement block with provenance.
|
|
534
|
+
*
|
|
535
|
+
* @param original - Original block
|
|
536
|
+
* @param newPayload - New payload
|
|
537
|
+
* @param method - Compaction method
|
|
538
|
+
* @param version - Compaction version
|
|
539
|
+
* @returns Replacement block
|
|
540
|
+
*/
|
|
541
|
+
function createReplacementBlock<TPayload>(
|
|
542
|
+
original: ContextBlock<TPayload>,
|
|
543
|
+
newPayload: TPayload,
|
|
544
|
+
method: string,
|
|
545
|
+
version: string
|
|
546
|
+
): ContextBlock<TPayload> {
|
|
547
|
+
// Compute new hash
|
|
548
|
+
const blockHash = computeBlockHash(
|
|
549
|
+
original.meta,
|
|
550
|
+
newPayload
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
// Create replacement block with provenance metadata
|
|
554
|
+
return {
|
|
555
|
+
blockHash,
|
|
556
|
+
meta: {
|
|
557
|
+
...original.meta,
|
|
558
|
+
source: `${original.meta.source ?? 'unknown'}:compacted`,
|
|
559
|
+
tags: [...(original.meta.tags ?? []), `compacted:${method}`],
|
|
560
|
+
},
|
|
561
|
+
payload: newPayload,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarizer implementations for history compaction.
|
|
3
|
+
*
|
|
4
|
+
* Uses LLM to condense old conversation history into compact summaries.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
8
|
+
import type { ContextBlock } from '../types/block.js';
|
|
9
|
+
import type { HistorySummarizer } from './compactor.js';
|
|
10
|
+
import { computeBlockHash } from '../types/hash.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Anthropic-based history summarizer.
|
|
14
|
+
* Uses Claude Haiku for cost-effective summarization.
|
|
15
|
+
*/
|
|
16
|
+
export class AnthropicSummarizer implements HistorySummarizer {
|
|
17
|
+
constructor(private anthropicClient: Anthropic) {}
|
|
18
|
+
|
|
19
|
+
async summarize(blocks: ContextBlock[], targetTokens: number): Promise<ContextBlock> {
|
|
20
|
+
// Render blocks to text (simplified - just stringify payload)
|
|
21
|
+
const messages = blocks.map((block) => {
|
|
22
|
+
const payload = block.payload as any;
|
|
23
|
+
if (payload.messages && Array.isArray(payload.messages)) {
|
|
24
|
+
return payload.messages
|
|
25
|
+
.map((m: any) => `${m.role}: ${JSON.stringify(m.content)}`)
|
|
26
|
+
.join('\n');
|
|
27
|
+
}
|
|
28
|
+
return JSON.stringify(payload);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const text = messages.join('\n\n');
|
|
32
|
+
|
|
33
|
+
// Call Anthropic with summarization prompt
|
|
34
|
+
const response = await this.anthropicClient.messages.create({
|
|
35
|
+
model: 'claude-haiku-4-5',
|
|
36
|
+
max_tokens: targetTokens,
|
|
37
|
+
messages: [
|
|
38
|
+
{
|
|
39
|
+
role: 'user',
|
|
40
|
+
content: `Summarize the following conversation history concisely, preserving key context and decisions:\n\n${text}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const summary =
|
|
46
|
+
response.content[0].type === 'text' ? response.content[0].text : '';
|
|
47
|
+
|
|
48
|
+
// Create summary block with provenance
|
|
49
|
+
const summaryPayload = {
|
|
50
|
+
summary,
|
|
51
|
+
originalBlockCount: blocks.length,
|
|
52
|
+
summarizedAt: Date.now(),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const firstBlock = blocks[0];
|
|
56
|
+
const blockHash = computeBlockHash(
|
|
57
|
+
{
|
|
58
|
+
...firstBlock.meta,
|
|
59
|
+
source: `${firstBlock.meta.source ?? 'unknown'}:summarized`,
|
|
60
|
+
},
|
|
61
|
+
summaryPayload
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
blockHash,
|
|
66
|
+
meta: {
|
|
67
|
+
...firstBlock.meta,
|
|
68
|
+
kind: 'history',
|
|
69
|
+
source: `${firstBlock.meta.source ?? 'unknown'}:summarized`,
|
|
70
|
+
tags: [...(firstBlock.meta.tags ?? []), 'summarized'],
|
|
71
|
+
createdAt: Date.now(),
|
|
72
|
+
},
|
|
73
|
+
payload: summaryPayload,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default context policy for general-purpose LLM conversations.
|
|
3
|
+
*
|
|
4
|
+
* This policy provides sensible defaults for:
|
|
5
|
+
* - Token budget: 180K context window with 8K completion reserve
|
|
6
|
+
* - Caching: Provider-native caching with breakpoints for pinned/reference content
|
|
7
|
+
* - Compaction: Tool output pruning + history summarization
|
|
8
|
+
* - Attachments: 10K token budget with purpose-based selection
|
|
9
|
+
* - Sensitivity: Public content only with redaction for restricted content
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ContextPolicy } from '../types/policy.js';
|
|
13
|
+
import {
|
|
14
|
+
DEFAULT_KIND_PRIORITIES,
|
|
15
|
+
DEFAULT_COMPACTION_CONFIG,
|
|
16
|
+
DEFAULT_SENSITIVITY_CONFIG,
|
|
17
|
+
DEFAULT_ATTACHMENT_POLICY,
|
|
18
|
+
} from '../types/policy.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Default context policy configuration.
|
|
22
|
+
*
|
|
23
|
+
* Use this as a starting point for most conversational workflows.
|
|
24
|
+
* Override specific properties as needed for your use case.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { DEFAULT_POLICY, ContextBuilder } from '@foundry/context';
|
|
29
|
+
*
|
|
30
|
+
* const builder = new ContextBuilder({
|
|
31
|
+
* ...DEFAULT_POLICY,
|
|
32
|
+
* contextWindow: 200_000, // Override for larger context
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export const DEFAULT_POLICY: ContextPolicy = {
|
|
37
|
+
// Provider configuration
|
|
38
|
+
provider: 'anthropic',
|
|
39
|
+
modelId: 'claude-sonnet-4-5',
|
|
40
|
+
|
|
41
|
+
// Token budget
|
|
42
|
+
contextWindow: 180_000,
|
|
43
|
+
completionReserve: 8_000,
|
|
44
|
+
|
|
45
|
+
// Overflow handling
|
|
46
|
+
overflowStrategy: 'compact',
|
|
47
|
+
|
|
48
|
+
// Block priorities
|
|
49
|
+
kindPriorities: DEFAULT_KIND_PRIORITIES,
|
|
50
|
+
|
|
51
|
+
// Compaction configuration
|
|
52
|
+
compaction: {
|
|
53
|
+
...DEFAULT_COMPACTION_CONFIG,
|
|
54
|
+
// Tool output pruning
|
|
55
|
+
pruneToolOutputs: true,
|
|
56
|
+
maxToolOutputAge: 3600, // 1 hour
|
|
57
|
+
maxToolOutputsPerKind: 10,
|
|
58
|
+
|
|
59
|
+
// History summarization
|
|
60
|
+
summarizeHistory: true,
|
|
61
|
+
maxHistoryMessages: 20,
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// Sensitivity filtering
|
|
65
|
+
sensitivity: DEFAULT_SENSITIVITY_CONFIG,
|
|
66
|
+
|
|
67
|
+
// Attachment selection
|
|
68
|
+
attachments: DEFAULT_ATTACHMENT_POLICY,
|
|
69
|
+
};
|