@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.
Files changed (280) hide show
  1. package/README.md +270 -0
  2. package/dist/__tests__/attachment-selector.test.d.ts +11 -0
  3. package/dist/__tests__/attachment-selector.test.d.ts.map +1 -0
  4. package/dist/__tests__/attachment-selector.test.js +449 -0
  5. package/dist/__tests__/attachment-selector.test.js.map +1 -0
  6. package/dist/__tests__/cache-breakpoints.test.d.ts +11 -0
  7. package/dist/__tests__/cache-breakpoints.test.d.ts.map +1 -0
  8. package/dist/__tests__/cache-breakpoints.test.js +398 -0
  9. package/dist/__tests__/cache-breakpoints.test.js.map +1 -0
  10. package/dist/__tests__/codecs.test.d.ts +7 -0
  11. package/dist/__tests__/codecs.test.d.ts.map +1 -0
  12. package/dist/__tests__/codecs.test.js +331 -0
  13. package/dist/__tests__/codecs.test.js.map +1 -0
  14. package/dist/__tests__/compactor.test.d.ts +11 -0
  15. package/dist/__tests__/compactor.test.d.ts.map +1 -0
  16. package/dist/__tests__/compactor.test.js +519 -0
  17. package/dist/__tests__/compactor.test.js.map +1 -0
  18. package/dist/__tests__/context-graph.test.d.ts +7 -0
  19. package/dist/__tests__/context-graph.test.d.ts.map +1 -0
  20. package/dist/__tests__/context-graph.test.js +262 -0
  21. package/dist/__tests__/context-graph.test.js.map +1 -0
  22. package/dist/__tests__/hash.test.d.ts +7 -0
  23. package/dist/__tests__/hash.test.d.ts.map +1 -0
  24. package/dist/__tests__/hash.test.js +228 -0
  25. package/dist/__tests__/hash.test.js.map +1 -0
  26. package/dist/__tests__/integration.test.d.ts +15 -0
  27. package/dist/__tests__/integration.test.d.ts.map +1 -0
  28. package/dist/__tests__/integration.test.js +728 -0
  29. package/dist/__tests__/integration.test.js.map +1 -0
  30. package/dist/__tests__/kind-order.test.d.ts +7 -0
  31. package/dist/__tests__/kind-order.test.d.ts.map +1 -0
  32. package/dist/__tests__/kind-order.test.js +243 -0
  33. package/dist/__tests__/kind-order.test.js.map +1 -0
  34. package/dist/__tests__/phase2-integration.test.d.ts +5 -0
  35. package/dist/__tests__/phase2-integration.test.d.ts.map +1 -0
  36. package/dist/__tests__/phase2-integration.test.js +222 -0
  37. package/dist/__tests__/phase2-integration.test.js.map +1 -0
  38. package/dist/__tests__/queries.test.d.ts +7 -0
  39. package/dist/__tests__/queries.test.d.ts.map +1 -0
  40. package/dist/__tests__/queries.test.js +254 -0
  41. package/dist/__tests__/queries.test.js.map +1 -0
  42. package/dist/__tests__/token-estimator.test.d.ts +7 -0
  43. package/dist/__tests__/token-estimator.test.d.ts.map +1 -0
  44. package/dist/__tests__/token-estimator.test.js +267 -0
  45. package/dist/__tests__/token-estimator.test.js.map +1 -0
  46. package/dist/adapters/anthropic-estimator.d.ts +38 -0
  47. package/dist/adapters/anthropic-estimator.d.ts.map +1 -0
  48. package/dist/adapters/anthropic-estimator.js +108 -0
  49. package/dist/adapters/anthropic-estimator.js.map +1 -0
  50. package/dist/adapters/attachment-resolver.d.ts +96 -0
  51. package/dist/adapters/attachment-resolver.d.ts.map +1 -0
  52. package/dist/adapters/attachment-resolver.js +176 -0
  53. package/dist/adapters/attachment-resolver.js.map +1 -0
  54. package/dist/adapters/attachment-selector.d.ts +59 -0
  55. package/dist/adapters/attachment-selector.d.ts.map +1 -0
  56. package/dist/adapters/attachment-selector.js +163 -0
  57. package/dist/adapters/attachment-selector.js.map +1 -0
  58. package/dist/adapters/gemini-estimator.d.ts +27 -0
  59. package/dist/adapters/gemini-estimator.d.ts.map +1 -0
  60. package/dist/adapters/gemini-estimator.js +80 -0
  61. package/dist/adapters/gemini-estimator.js.map +1 -0
  62. package/dist/adapters/index.d.ts +12 -0
  63. package/dist/adapters/index.d.ts.map +1 -0
  64. package/dist/adapters/index.js +28 -0
  65. package/dist/adapters/index.js.map +1 -0
  66. package/dist/adapters/memory-store.d.ts +139 -0
  67. package/dist/adapters/memory-store.d.ts.map +1 -0
  68. package/dist/adapters/memory-store.js +187 -0
  69. package/dist/adapters/memory-store.js.map +1 -0
  70. package/dist/adapters/openai-estimator.d.ts +35 -0
  71. package/dist/adapters/openai-estimator.d.ts.map +1 -0
  72. package/dist/adapters/openai-estimator.js +89 -0
  73. package/dist/adapters/openai-estimator.js.map +1 -0
  74. package/dist/adapters/summarizer.d.ts +121 -0
  75. package/dist/adapters/summarizer.d.ts.map +1 -0
  76. package/dist/adapters/summarizer.js +121 -0
  77. package/dist/adapters/summarizer.js.map +1 -0
  78. package/dist/adapters/token-estimator.d.ts +63 -0
  79. package/dist/adapters/token-estimator.d.ts.map +1 -0
  80. package/dist/adapters/token-estimator.js +37 -0
  81. package/dist/adapters/token-estimator.js.map +1 -0
  82. package/dist/builder/context-builder.d.ts +186 -0
  83. package/dist/builder/context-builder.d.ts.map +1 -0
  84. package/dist/builder/context-builder.js +305 -0
  85. package/dist/builder/context-builder.js.map +1 -0
  86. package/dist/builder/context-fork.d.ts +166 -0
  87. package/dist/builder/context-fork.d.ts.map +1 -0
  88. package/dist/builder/context-fork.js +282 -0
  89. package/dist/builder/context-fork.js.map +1 -0
  90. package/dist/builder/index.d.ts +6 -0
  91. package/dist/builder/index.d.ts.map +1 -0
  92. package/dist/builder/index.js +22 -0
  93. package/dist/builder/index.js.map +1 -0
  94. package/dist/codecs/base.d.ts +18 -0
  95. package/dist/codecs/base.d.ts.map +1 -0
  96. package/dist/codecs/base.js +39 -0
  97. package/dist/codecs/base.js.map +1 -0
  98. package/dist/codecs/conversation-history.codec.d.ts +81 -0
  99. package/dist/codecs/conversation-history.codec.d.ts.map +1 -0
  100. package/dist/codecs/conversation-history.codec.js +89 -0
  101. package/dist/codecs/conversation-history.codec.js.map +1 -0
  102. package/dist/codecs/index.d.ts +31 -0
  103. package/dist/codecs/index.d.ts.map +1 -0
  104. package/dist/codecs/index.js +71 -0
  105. package/dist/codecs/index.js.map +1 -0
  106. package/dist/codecs/redacted-stub.codec.d.ts +32 -0
  107. package/dist/codecs/redacted-stub.codec.d.ts.map +1 -0
  108. package/dist/codecs/redacted-stub.codec.js +64 -0
  109. package/dist/codecs/redacted-stub.codec.js.map +1 -0
  110. package/dist/codecs/structured-reference.codec.d.ts +40 -0
  111. package/dist/codecs/structured-reference.codec.d.ts.map +1 -0
  112. package/dist/codecs/structured-reference.codec.js +81 -0
  113. package/dist/codecs/structured-reference.codec.js.map +1 -0
  114. package/dist/codecs/system-rules.codec.d.ts +32 -0
  115. package/dist/codecs/system-rules.codec.d.ts.map +1 -0
  116. package/dist/codecs/system-rules.codec.js +62 -0
  117. package/dist/codecs/system-rules.codec.js.map +1 -0
  118. package/dist/codecs/tool-output.codec.d.ts +66 -0
  119. package/dist/codecs/tool-output.codec.d.ts.map +1 -0
  120. package/dist/codecs/tool-output.codec.js +95 -0
  121. package/dist/codecs/tool-output.codec.js.map +1 -0
  122. package/dist/codecs/tool-schema.codec.d.ts +36 -0
  123. package/dist/codecs/tool-schema.codec.d.ts.map +1 -0
  124. package/dist/codecs/tool-schema.codec.js +74 -0
  125. package/dist/codecs/tool-schema.codec.js.map +1 -0
  126. package/dist/codecs/unsafe-text.codec.d.ts +28 -0
  127. package/dist/codecs/unsafe-text.codec.d.ts.map +1 -0
  128. package/dist/codecs/unsafe-text.codec.js +63 -0
  129. package/dist/codecs/unsafe-text.codec.js.map +1 -0
  130. package/dist/graph/context-graph.d.ts +121 -0
  131. package/dist/graph/context-graph.d.ts.map +1 -0
  132. package/dist/graph/context-graph.js +166 -0
  133. package/dist/graph/context-graph.js.map +1 -0
  134. package/dist/graph/index.d.ts +8 -0
  135. package/dist/graph/index.d.ts.map +1 -0
  136. package/dist/graph/index.js +24 -0
  137. package/dist/graph/index.js.map +1 -0
  138. package/dist/graph/kind-order.d.ts +60 -0
  139. package/dist/graph/kind-order.d.ts.map +1 -0
  140. package/dist/graph/kind-order.js +113 -0
  141. package/dist/graph/kind-order.js.map +1 -0
  142. package/dist/graph/queries.d.ts +68 -0
  143. package/dist/graph/queries.d.ts.map +1 -0
  144. package/dist/graph/queries.js +240 -0
  145. package/dist/graph/queries.js.map +1 -0
  146. package/dist/graph/views.d.ts +90 -0
  147. package/dist/graph/views.d.ts.map +1 -0
  148. package/dist/graph/views.js +173 -0
  149. package/dist/graph/views.js.map +1 -0
  150. package/dist/index.d.ts +16 -0
  151. package/dist/index.d.ts.map +1 -0
  152. package/dist/index.js +40 -0
  153. package/dist/index.js.map +1 -0
  154. package/dist/pipeline/compactor.d.ts +128 -0
  155. package/dist/pipeline/compactor.d.ts.map +1 -0
  156. package/dist/pipeline/compactor.js +346 -0
  157. package/dist/pipeline/compactor.js.map +1 -0
  158. package/dist/pipeline/index.d.ts +6 -0
  159. package/dist/pipeline/index.d.ts.map +1 -0
  160. package/dist/pipeline/index.js +22 -0
  161. package/dist/pipeline/index.js.map +1 -0
  162. package/dist/pipeline/summarizer.d.ts +18 -0
  163. package/dist/pipeline/summarizer.d.ts.map +1 -0
  164. package/dist/pipeline/summarizer.js +68 -0
  165. package/dist/pipeline/summarizer.js.map +1 -0
  166. package/dist/policies/default-policy.d.ts +29 -0
  167. package/dist/policies/default-policy.d.ts.map +1 -0
  168. package/dist/policies/default-policy.js +58 -0
  169. package/dist/policies/default-policy.js.map +1 -0
  170. package/dist/policies/index.d.ts +5 -0
  171. package/dist/policies/index.d.ts.map +1 -0
  172. package/dist/policies/index.js +21 -0
  173. package/dist/policies/index.js.map +1 -0
  174. package/dist/providers/anthropic-compiler.d.ts +58 -0
  175. package/dist/providers/anthropic-compiler.d.ts.map +1 -0
  176. package/dist/providers/anthropic-compiler.js +182 -0
  177. package/dist/providers/anthropic-compiler.js.map +1 -0
  178. package/dist/providers/capabilities.d.ts +54 -0
  179. package/dist/providers/capabilities.d.ts.map +1 -0
  180. package/dist/providers/capabilities.js +87 -0
  181. package/dist/providers/capabilities.js.map +1 -0
  182. package/dist/providers/gemini-compiler.d.ts +51 -0
  183. package/dist/providers/gemini-compiler.d.ts.map +1 -0
  184. package/dist/providers/gemini-compiler.js +206 -0
  185. package/dist/providers/gemini-compiler.js.map +1 -0
  186. package/dist/providers/index.d.ts +8 -0
  187. package/dist/providers/index.d.ts.map +1 -0
  188. package/dist/providers/index.js +24 -0
  189. package/dist/providers/index.js.map +1 -0
  190. package/dist/providers/openai-compiler.d.ts +46 -0
  191. package/dist/providers/openai-compiler.d.ts.map +1 -0
  192. package/dist/providers/openai-compiler.js +149 -0
  193. package/dist/providers/openai-compiler.js.map +1 -0
  194. package/dist/types/attachment.d.ts +62 -0
  195. package/dist/types/attachment.d.ts.map +1 -0
  196. package/dist/types/attachment.js +6 -0
  197. package/dist/types/attachment.js.map +1 -0
  198. package/dist/types/block.d.ts +61 -0
  199. package/dist/types/block.d.ts.map +1 -0
  200. package/dist/types/block.js +8 -0
  201. package/dist/types/block.js.map +1 -0
  202. package/dist/types/codec.d.ts +58 -0
  203. package/dist/types/codec.d.ts.map +1 -0
  204. package/dist/types/codec.js +6 -0
  205. package/dist/types/codec.js.map +1 -0
  206. package/dist/types/compiled.d.ts +91 -0
  207. package/dist/types/compiled.d.ts.map +1 -0
  208. package/dist/types/compiled.js +6 -0
  209. package/dist/types/compiled.js.map +1 -0
  210. package/dist/types/hash.d.ts +24 -0
  211. package/dist/types/hash.d.ts.map +1 -0
  212. package/dist/types/hash.js +49 -0
  213. package/dist/types/hash.js.map +1 -0
  214. package/dist/types/index.d.ts +10 -0
  215. package/dist/types/index.d.ts.map +1 -0
  216. package/dist/types/index.js +26 -0
  217. package/dist/types/index.js.map +1 -0
  218. package/dist/types/policy.d.ts +128 -0
  219. package/dist/types/policy.d.ts.map +1 -0
  220. package/dist/types/policy.js +55 -0
  221. package/dist/types/policy.js.map +1 -0
  222. package/package.json +55 -0
  223. package/postcss.config.js +4 -0
  224. package/src/__tests__/attachment-selector.test.ts +559 -0
  225. package/src/__tests__/cache-breakpoints.test.ts +566 -0
  226. package/src/__tests__/codecs.test.ts +417 -0
  227. package/src/__tests__/compactor.test.ts +608 -0
  228. package/src/__tests__/context-graph.test.ts +383 -0
  229. package/src/__tests__/hash.test.ts +274 -0
  230. package/src/__tests__/integration.test.ts +866 -0
  231. package/src/__tests__/kind-order.test.ts +312 -0
  232. package/src/__tests__/phase2-integration.test.ts +253 -0
  233. package/src/__tests__/queries.test.ts +387 -0
  234. package/src/__tests__/token-estimator.test.ts +326 -0
  235. package/src/adapters/anthropic-estimator.ts +125 -0
  236. package/src/adapters/attachment-resolver.ts +295 -0
  237. package/src/adapters/attachment-selector.ts +218 -0
  238. package/src/adapters/gemini-estimator.ts +93 -0
  239. package/src/adapters/index.ts +12 -0
  240. package/src/adapters/memory-store.ts +299 -0
  241. package/src/adapters/openai-estimator.ts +105 -0
  242. package/src/adapters/summarizer.ts +250 -0
  243. package/src/adapters/token-estimator.ts +74 -0
  244. package/src/builder/context-builder.ts +467 -0
  245. package/src/builder/context-fork.ts +471 -0
  246. package/src/builder/index.ts +6 -0
  247. package/src/codecs/base.ts +36 -0
  248. package/src/codecs/conversation-history.codec.ts +108 -0
  249. package/src/codecs/index.ts +57 -0
  250. package/src/codecs/redacted-stub.codec.ts +76 -0
  251. package/src/codecs/structured-reference.codec.ts +96 -0
  252. package/src/codecs/system-rules.codec.ts +74 -0
  253. package/src/codecs/tool-output.codec.ts +109 -0
  254. package/src/codecs/tool-schema.codec.ts +87 -0
  255. package/src/codecs/unsafe-text.codec.ts +74 -0
  256. package/src/graph/context-graph.ts +205 -0
  257. package/src/graph/index.ts +8 -0
  258. package/src/graph/kind-order.ts +125 -0
  259. package/src/graph/queries.ts +306 -0
  260. package/src/graph/views.ts +255 -0
  261. package/src/index.ts +31 -0
  262. package/src/pipeline/compactor.ts +563 -0
  263. package/src/pipeline/index.ts +6 -0
  264. package/src/pipeline/summarizer.ts +76 -0
  265. package/src/policies/default-policy.ts +69 -0
  266. package/src/policies/index.ts +5 -0
  267. package/src/providers/anthropic-compiler.ts +294 -0
  268. package/src/providers/capabilities.ts +144 -0
  269. package/src/providers/gemini-compiler.ts +272 -0
  270. package/src/providers/index.ts +8 -0
  271. package/src/providers/openai-compiler.ts +191 -0
  272. package/src/types/attachment.ts +86 -0
  273. package/src/types/block.ts +84 -0
  274. package/src/types/codec.ts +68 -0
  275. package/src/types/compiled.ts +109 -0
  276. package/src/types/hash.ts +58 -0
  277. package/src/types/index.ts +10 -0
  278. package/src/types/policy.ts +194 -0
  279. package/tsconfig.json +21 -0
  280. package/vitest.config.ts +21 -0
@@ -0,0 +1,255 @@
1
+ /**
2
+ * ContextView: Immutable, deterministically-ordered snapshot of context blocks.
3
+ *
4
+ * Views provide stable ordering (KIND_ORDER + lexicographic) and token estimation.
5
+ */
6
+
7
+ import { createHash } from 'crypto';
8
+ import type { ContextBlock } from '../types/block.js';
9
+ import type { ContextGraph } from './context-graph.js';
10
+ import type { BlockQuery } from './queries.js';
11
+ import type { TokenEstimator } from '../adapters/token-estimator.js';
12
+ import { compareKinds } from './kind-order.js';
13
+
14
+ /**
15
+ * View options for creating a ContextView.
16
+ */
17
+ export interface ViewOptions {
18
+ /** Query to filter blocks (default: all blocks) */
19
+ query?: BlockQuery;
20
+
21
+ /** Token estimator for budget enforcement (optional) */
22
+ tokenEstimator?: TokenEstimator;
23
+
24
+ /** Maximum token budget (requires tokenEstimator) */
25
+ maxTokens?: number;
26
+ }
27
+
28
+ /**
29
+ * Token estimation result for a view.
30
+ */
31
+ export interface ViewTokenEstimate {
32
+ /** Estimated token count */
33
+ tokens: number;
34
+
35
+ /** Confidence level */
36
+ confidence: 'exact' | 'high' | 'low';
37
+
38
+ /** Whether token budget was exceeded (blocks were truncated) */
39
+ truncated: boolean;
40
+ }
41
+
42
+ /**
43
+ * ContextView: Immutable snapshot of blocks with deterministic ordering.
44
+ *
45
+ * Ordering rules:
46
+ * 1. Primary: KIND_ORDER (pinned → reference → memory → state → tool_output → history → turn)
47
+ * 2. Secondary: Lexicographic by blockHash within same kind
48
+ */
49
+ export interface ContextView {
50
+ /** Ordered blocks (immutable) */
51
+ readonly blocks: ReadonlyArray<ContextBlock<unknown>>;
52
+
53
+ /** Token estimation (if estimator provided) */
54
+ readonly tokenEstimate?: ViewTokenEstimate;
55
+
56
+ /**
57
+ * Stable prefix hash (computed from ordered block hashes).
58
+ * Two views with identical ordered blocks have identical prefix hashes.
59
+ */
60
+ readonly stablePrefixHash: string;
61
+
62
+ /** View creation timestamp */
63
+ readonly createdAt: number;
64
+ }
65
+
66
+ /**
67
+ * Sort blocks deterministically by KIND_ORDER + lexicographic.
68
+ *
69
+ * @param blocks - Blocks to sort
70
+ * @returns Sorted blocks (new array)
71
+ */
72
+ export function sortBlocksDeterministic(
73
+ blocks: ContextBlock<unknown>[]
74
+ ): ContextBlock<unknown>[] {
75
+ return [...blocks].sort((a, b) => {
76
+ // Primary: KIND_ORDER
77
+ const kindCmp = compareKinds(a.meta.kind, b.meta.kind);
78
+ if (kindCmp !== 0) {
79
+ return kindCmp;
80
+ }
81
+
82
+ // Secondary: Lexicographic by blockHash
83
+ return a.blockHash.localeCompare(b.blockHash);
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Compute stable prefix hash from ordered block hashes.
89
+ *
90
+ * @param blocks - Ordered blocks
91
+ * @returns Hex-encoded SHA-256 hash
92
+ */
93
+ export function computeStablePrefixHash(blocks: ReadonlyArray<ContextBlock<unknown>>): string {
94
+ // Concatenate block hashes in order
95
+ const concatenated = blocks.map((b) => b.blockHash).join('|');
96
+
97
+ // Compute SHA-256 hash
98
+ const hash = createHash('sha256')
99
+ .update(concatenated)
100
+ .digest('hex');
101
+
102
+ return hash;
103
+ }
104
+
105
+ /**
106
+ * Apply token budget to blocks (truncate if needed).
107
+ * Returns blocks that fit within budget + estimation metadata.
108
+ *
109
+ * @param blocks - Ordered blocks
110
+ * @param estimator - Token estimator
111
+ * @param maxTokens - Maximum token budget
112
+ * @returns Truncated blocks + estimation result
113
+ */
114
+ async function applyTokenBudget(
115
+ blocks: ContextBlock<unknown>[],
116
+ estimator: TokenEstimator,
117
+ maxTokens: number
118
+ ): Promise<{ blocks: ContextBlock<unknown>[]; estimate: ViewTokenEstimate }> {
119
+ let totalTokens = 0;
120
+ let lowestConfidence: 'exact' | 'high' | 'low' = 'exact';
121
+ const includedBlocks: ContextBlock<unknown>[] = [];
122
+
123
+ for (const block of blocks) {
124
+ // Estimate tokens for this block
125
+ const blockEstimate = await estimator.estimateBlock(block);
126
+ const projectedTotal = totalTokens + blockEstimate.tokens;
127
+
128
+ // Check if adding this block would exceed budget
129
+ if (projectedTotal > maxTokens) {
130
+ // Budget exceeded - stop here
131
+ return {
132
+ blocks: includedBlocks,
133
+ estimate: {
134
+ tokens: totalTokens,
135
+ confidence: lowestConfidence,
136
+ truncated: true,
137
+ },
138
+ };
139
+ }
140
+
141
+ // Include block
142
+ includedBlocks.push(block);
143
+ totalTokens += blockEstimate.tokens;
144
+
145
+ // Track lowest confidence
146
+ if (blockEstimate.confidence === 'low') {
147
+ lowestConfidence = 'low';
148
+ } else if (blockEstimate.confidence === 'high' && lowestConfidence === 'exact') {
149
+ lowestConfidence = 'high';
150
+ }
151
+ }
152
+
153
+ // All blocks fit within budget
154
+ return {
155
+ blocks: includedBlocks,
156
+ estimate: {
157
+ tokens: totalTokens,
158
+ confidence: lowestConfidence,
159
+ truncated: false,
160
+ },
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Create a ContextView from a graph and options.
166
+ *
167
+ * @param graph - Context graph
168
+ * @param options - View options
169
+ * @returns ContextView
170
+ */
171
+ export async function createContextView(
172
+ graph: ContextGraph,
173
+ options: ViewOptions
174
+ ): Promise<ContextView> {
175
+ // Select blocks matching query
176
+ const query = options.query ?? {};
177
+ let selectedBlocks = graph.select(query);
178
+
179
+ // Sort blocks deterministically
180
+ selectedBlocks = sortBlocksDeterministic(selectedBlocks);
181
+
182
+ // Apply token budget if provided
183
+ let tokenEstimate: ViewTokenEstimate | undefined;
184
+ if (options.tokenEstimator && options.maxTokens !== undefined) {
185
+ const result = await applyTokenBudget(
186
+ selectedBlocks,
187
+ options.tokenEstimator,
188
+ options.maxTokens
189
+ );
190
+ selectedBlocks = result.blocks;
191
+ tokenEstimate = result.estimate;
192
+ } else if (options.tokenEstimator) {
193
+ // Estimate without budget enforcement
194
+ const estimate = await options.tokenEstimator.estimate(selectedBlocks);
195
+ tokenEstimate = {
196
+ tokens: estimate.tokens,
197
+ confidence: estimate.confidence,
198
+ truncated: false,
199
+ };
200
+ }
201
+
202
+ // Compute stable prefix hash
203
+ const stablePrefixHash = computeStablePrefixHash(selectedBlocks);
204
+
205
+ return {
206
+ blocks: selectedBlocks,
207
+ tokenEstimate,
208
+ stablePrefixHash,
209
+ createdAt: Math.floor(Date.now() / 1000),
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Check if two views have identical content (same blocks in same order).
215
+ *
216
+ * @param a - First view
217
+ * @param b - Second view
218
+ * @returns True if views have identical content
219
+ */
220
+ export function viewsEqual(a: ContextView, b: ContextView): boolean {
221
+ return a.stablePrefixHash === b.stablePrefixHash;
222
+ }
223
+
224
+ /**
225
+ * Merge multiple views into a single view (preserves ordering).
226
+ * Deduplicates blocks by hash.
227
+ *
228
+ * @param views - Views to merge
229
+ * @returns Merged view
230
+ */
231
+ export function mergeViews(...views: ContextView[]): ContextView {
232
+ const seenHashes = new Set<string>();
233
+ const mergedBlocks: ContextBlock<unknown>[] = [];
234
+
235
+ for (const view of views) {
236
+ for (const block of view.blocks) {
237
+ if (!seenHashes.has(block.blockHash)) {
238
+ seenHashes.add(block.blockHash);
239
+ mergedBlocks.push(block);
240
+ }
241
+ }
242
+ }
243
+
244
+ // Re-sort merged blocks
245
+ const sortedBlocks = sortBlocksDeterministic(mergedBlocks);
246
+
247
+ // Compute new prefix hash
248
+ const stablePrefixHash = computeStablePrefixHash(sortedBlocks);
249
+
250
+ return {
251
+ blocks: sortedBlocks,
252
+ stablePrefixHash,
253
+ createdAt: Math.floor(Date.now() / 1000),
254
+ };
255
+ }
package/src/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @foundry/context - Context management library for LLM conversations
3
+ *
4
+ * Phase 1: Core Types & Codecs
5
+ * Phase 2: Context Graph & Token Estimation
6
+ * Phase 3: Builder & Compilation Pipeline
7
+ */
8
+
9
+ // Core types
10
+ export * from './types/index.js';
11
+
12
+ // Graph utilities (KIND_ORDER, ContextGraph, queries, views)
13
+ export * from './graph/index.js';
14
+
15
+ // Built-in codecs
16
+ export * from './codecs/index.js';
17
+
18
+ // Token estimators
19
+ export * from './adapters/index.js';
20
+
21
+ // Context builder (Phase 3)
22
+ export * from './builder/index.js';
23
+
24
+ // Pipeline utilities (compaction, fork)
25
+ export * from './pipeline/index.js';
26
+
27
+ // Provider compilers
28
+ export * from './providers/index.js';
29
+
30
+ // Policy configurations
31
+ export * from './policies/index.js';