@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,467 @@
1
+ /**
2
+ * ContextBuilder: Fluent API for composing context graphs.
3
+ *
4
+ * Provides a declarative interface for building context from various sources:
5
+ * - System rules (pinned)
6
+ * - References (tool schemas, docs)
7
+ * - State (current workflow/session)
8
+ * - Memory (long-term, RAG results)
9
+ * - History (conversation turns)
10
+ * - Attachments (images, PDFs)
11
+ * - Current turn (user message)
12
+ */
13
+
14
+ import type { ContextBlock, BlockKind, SensitivityLevel } from '../types/block.js';
15
+ import type { BlockCodec } from '../types/codec.js';
16
+ import type { ContextPolicy, Provider } from '../types/policy.js';
17
+ import type { AttachmentRef } from '../types/attachment.js';
18
+ import type { CompiledContext } from '../types/compiled.js';
19
+ import { ContextGraph } from '../graph/context-graph.js';
20
+ import { SystemRulesCodec, type SystemRulesPayload } from '../codecs/system-rules.codec.js';
21
+ import { ConversationHistoryCodec, type ConversationHistoryPayload, type ConversationMessage } from '../codecs/conversation-history.codec.js';
22
+ import { computeBlockHash } from '../types/hash.js';
23
+
24
+ /**
25
+ * Fork options for creating specialized contexts.
26
+ */
27
+ export interface ForkOptions {
28
+ /** Maximum sensitivity level to include */
29
+ maxSensitivity?: SensitivityLevel;
30
+
31
+ /** Block kinds to include (omit = include all) */
32
+ includeKinds?: BlockKind[];
33
+
34
+ /** Block kinds to exclude */
35
+ excludeKinds?: BlockKind[];
36
+
37
+ /** Optional tag filter */
38
+ tags?: string[];
39
+ }
40
+
41
+ /**
42
+ * ContextBuilder: Fluent API for composing context.
43
+ *
44
+ * Usage:
45
+ * ```ts
46
+ * const builder = new ContextBuilder();
47
+ * builder
48
+ * .system({ text: 'You are a helpful assistant.' })
49
+ * .history(previousMessages)
50
+ * .turn('What is the capital of France?');
51
+ *
52
+ * const compiled = await builder.compile(policy, 'anthropic');
53
+ * ```
54
+ */
55
+ export class ContextBuilder {
56
+ private readonly graph: ContextGraph;
57
+ private blockCounter: number;
58
+
59
+ constructor() {
60
+ this.graph = new ContextGraph();
61
+ this.blockCounter = 0;
62
+ }
63
+
64
+ /**
65
+ * Add a pinned system rules block.
66
+ *
67
+ * @param rules - System rules payload
68
+ * @param options - Optional block metadata overrides
69
+ * @returns This builder (for chaining)
70
+ */
71
+ system(
72
+ rules: SystemRulesPayload,
73
+ options?: {
74
+ sensitivity?: SensitivityLevel;
75
+ source?: string;
76
+ tags?: string[];
77
+ }
78
+ ): this {
79
+ const block = this.createBlock(
80
+ 'pinned',
81
+ SystemRulesCodec,
82
+ rules,
83
+ options
84
+ );
85
+
86
+ this.graph.addBlock(block);
87
+ return this;
88
+ }
89
+
90
+ /**
91
+ * Add a reference block (tool schema, external doc, etc.).
92
+ *
93
+ * @param codec - Block codec for the reference type
94
+ * @param data - Reference payload
95
+ * @param options - Optional block metadata overrides
96
+ * @returns This builder (for chaining)
97
+ */
98
+ reference<TPayload>(
99
+ codec: BlockCodec<TPayload>,
100
+ data: TPayload,
101
+ options?: {
102
+ sensitivity?: SensitivityLevel;
103
+ source?: string;
104
+ tags?: string[];
105
+ }
106
+ ): this {
107
+ const block = this.createBlock(
108
+ 'reference',
109
+ codec,
110
+ data,
111
+ options
112
+ );
113
+
114
+ this.graph.addBlock(block);
115
+ return this;
116
+ }
117
+
118
+ /**
119
+ * Add a state block (current workflow/session state).
120
+ *
121
+ * @param codec - Block codec for the state type
122
+ * @param data - State payload
123
+ * @param options - Optional block metadata overrides
124
+ * @returns This builder (for chaining)
125
+ */
126
+ state<TPayload>(
127
+ codec: BlockCodec<TPayload>,
128
+ data: TPayload,
129
+ options?: {
130
+ sensitivity?: SensitivityLevel;
131
+ source?: string;
132
+ tags?: string[];
133
+ }
134
+ ): this {
135
+ const block = this.createBlock(
136
+ 'state',
137
+ codec,
138
+ data,
139
+ options
140
+ );
141
+
142
+ this.graph.addBlock(block);
143
+ return this;
144
+ }
145
+
146
+ /**
147
+ * Add a memory block (long-term memory, RAG results).
148
+ *
149
+ * @param codec - Block codec for the memory type
150
+ * @param data - Memory payload
151
+ * @param options - Optional block metadata overrides
152
+ * @returns This builder (for chaining)
153
+ */
154
+ memory<TPayload>(
155
+ codec: BlockCodec<TPayload>,
156
+ data: TPayload,
157
+ options?: {
158
+ sensitivity?: SensitivityLevel;
159
+ source?: string;
160
+ tags?: string[];
161
+ }
162
+ ): this {
163
+ const block = this.createBlock(
164
+ 'memory',
165
+ codec,
166
+ data,
167
+ options
168
+ );
169
+
170
+ this.graph.addBlock(block);
171
+ return this;
172
+ }
173
+
174
+ /**
175
+ * Add a conversation history block.
176
+ *
177
+ * @param messages - Array of conversation messages
178
+ * @param summary - Optional summary of earlier messages
179
+ * @param options - Optional block metadata overrides
180
+ * @returns This builder (for chaining)
181
+ */
182
+ history(
183
+ messages: ConversationMessage[],
184
+ summary?: string,
185
+ options?: {
186
+ sensitivity?: SensitivityLevel;
187
+ source?: string;
188
+ tags?: string[];
189
+ }
190
+ ): this {
191
+ const payload: ConversationHistoryPayload = {
192
+ messages,
193
+ summary,
194
+ };
195
+
196
+ const block = this.createBlock(
197
+ 'history',
198
+ ConversationHistoryCodec,
199
+ payload,
200
+ options
201
+ );
202
+
203
+ this.graph.addBlock(block);
204
+ return this;
205
+ }
206
+
207
+ /**
208
+ * Add attachment blocks (images, PDFs, etc.).
209
+ * Note: Attachments need to be resolved via AttachmentResolver before compilation.
210
+ *
211
+ * @param attachments - Array of attachments
212
+ * @param codec - Block codec for attachment type
213
+ * @param options - Optional block metadata overrides
214
+ * @returns This builder (for chaining)
215
+ */
216
+ attachments<TPayload>(
217
+ attachments: AttachmentRef[],
218
+ codec: BlockCodec<TPayload>,
219
+ options?: {
220
+ sensitivity?: SensitivityLevel;
221
+ source?: string;
222
+ tags?: string[];
223
+ }
224
+ ): this {
225
+ // For each attachment, create a reference block
226
+ // The actual resolution happens via AttachmentResolver
227
+ for (const attachment of attachments) {
228
+ const block = this.createBlock(
229
+ 'reference',
230
+ codec,
231
+ attachment as unknown as TPayload,
232
+ options
233
+ );
234
+
235
+ this.graph.addBlock(block);
236
+ }
237
+
238
+ return this;
239
+ }
240
+
241
+ /**
242
+ * Add a user turn block (current user message).
243
+ *
244
+ * @param text - User message text
245
+ * @param options - Optional block metadata overrides
246
+ * @returns This builder (for chaining)
247
+ */
248
+ turn(
249
+ text: string,
250
+ options?: {
251
+ sensitivity?: SensitivityLevel;
252
+ source?: string;
253
+ tags?: string[];
254
+ }
255
+ ): this {
256
+ // Use a simple text payload for turn blocks
257
+ const payload = { text };
258
+
259
+ const block = this.createBlock(
260
+ 'turn',
261
+ {
262
+ codecId: 'user-turn',
263
+ version: '1.0.0',
264
+ payloadSchema: {} as any,
265
+ canonicalize: (p: any) => ({ text: p.text.trim() }),
266
+ hash: (c: any) => {
267
+ return computeBlockHash(
268
+ { kind: 'turn', sensitivity: 'public', codecId: 'user-turn', codecVersion: '1.0.0' },
269
+ c
270
+ );
271
+ },
272
+ render: (block: any) => ({
273
+ anthropic: { role: 'user', content: block.payload.text },
274
+ openai: { role: 'user', content: block.payload.text },
275
+ gemini: { role: 'user', parts: [{ text: block.payload.text }] },
276
+ }),
277
+ validate: (p: any) => p,
278
+ },
279
+ payload,
280
+ options
281
+ );
282
+
283
+ this.graph.addBlock(block);
284
+ return this;
285
+ }
286
+
287
+ /**
288
+ * Create a forked context with filtering.
289
+ * Useful for creating specialized contexts (e.g., public-only for external models).
290
+ *
291
+ * @param options - Fork filtering options
292
+ * @returns New ContextBuilder with filtered blocks
293
+ */
294
+ fork(options: ForkOptions): ContextBuilder {
295
+ const forked = new ContextBuilder();
296
+
297
+ // Filter blocks based on options
298
+ const allBlocks = this.graph.getAllBlocks();
299
+
300
+ for (const block of allBlocks) {
301
+ let include = true;
302
+
303
+ // Sensitivity filter
304
+ if (options.maxSensitivity !== undefined) {
305
+ const sensitivityOrder: Record<SensitivityLevel, number> = {
306
+ public: 0,
307
+ internal: 1,
308
+ restricted: 2,
309
+ };
310
+
311
+ if (sensitivityOrder[block.meta.sensitivity] > sensitivityOrder[options.maxSensitivity]) {
312
+ include = false;
313
+ }
314
+ }
315
+
316
+ // Kind filter (include)
317
+ if (options.includeKinds !== undefined) {
318
+ if (!options.includeKinds.includes(block.meta.kind)) {
319
+ include = false;
320
+ }
321
+ }
322
+
323
+ // Kind filter (exclude)
324
+ if (options.excludeKinds !== undefined) {
325
+ if (options.excludeKinds.includes(block.meta.kind)) {
326
+ include = false;
327
+ }
328
+ }
329
+
330
+ // Tag filter
331
+ if (options.tags !== undefined && options.tags.length > 0) {
332
+ const blockTags = block.meta.tags ?? [];
333
+ const hasMatchingTag = options.tags.some((tag) => blockTags.includes(tag));
334
+ if (!hasMatchingTag) {
335
+ include = false;
336
+ }
337
+ }
338
+
339
+ if (include) {
340
+ forked.graph.addBlock(
341
+ block,
342
+ this.graph.getDerivedFrom(block.blockHash),
343
+ this.graph.getReferences(block.blockHash)
344
+ );
345
+ }
346
+ }
347
+
348
+ return forked;
349
+ }
350
+
351
+ /**
352
+ * Compile the context for a specific provider.
353
+ * This is a placeholder - actual compilation happens in provider compilers.
354
+ *
355
+ * @param policy - Context policy configuration
356
+ * @param provider - Target provider
357
+ * @returns Compiled context
358
+ */
359
+ async compile(policy: ContextPolicy, provider: Provider): Promise<CompiledContext> {
360
+ // This is a placeholder - the actual implementation will be in provider compilers
361
+ // For now, we'll just create a view and return basic structure
362
+ // Create a simple stub estimator (would use provider-specific estimator in production)
363
+ const stubEstimator = {
364
+ estimate: async (blocks: ContextBlock<unknown>[]) => ({
365
+ tokens: blocks.length * 100,
366
+ confidence: 'low' as const,
367
+ }),
368
+ estimateBlock: async (block: ContextBlock<unknown>) => ({
369
+ tokens: 100,
370
+ confidence: 'low' as const,
371
+ }),
372
+ };
373
+
374
+ const view = await this.graph.createView({
375
+ tokenEstimator: stubEstimator,
376
+ maxTokens: policy.contextWindow - policy.completionReserve,
377
+ });
378
+
379
+ return {
380
+ provider,
381
+ modelId: policy.modelId,
382
+ messages: [],
383
+ estimatedTokens: 0,
384
+ blocks: [...view.blocks],
385
+ meta: {
386
+ compiledAt: Math.floor(Date.now() / 1000),
387
+ contextWindow: policy.contextWindow,
388
+ completionReserve: policy.completionReserve,
389
+ availableTokens: policy.contextWindow - policy.completionReserve,
390
+ overflowed: false,
391
+ compacted: false,
392
+ truncated: false,
393
+ tokensByKind: {},
394
+ },
395
+ };
396
+ }
397
+
398
+ /**
399
+ * Get the underlying context graph.
400
+ *
401
+ * @returns Context graph
402
+ */
403
+ getGraph(): ContextGraph {
404
+ return this.graph;
405
+ }
406
+
407
+ /**
408
+ * Get the number of blocks in the builder.
409
+ *
410
+ * @returns Block count
411
+ */
412
+ getBlockCount(): number {
413
+ return this.graph.getBlockCount();
414
+ }
415
+
416
+ /**
417
+ * Clear all blocks from the builder.
418
+ */
419
+ clear(): void {
420
+ this.graph.clear();
421
+ this.blockCounter = 0;
422
+ }
423
+
424
+ /**
425
+ * Create a block with generated hash and metadata.
426
+ *
427
+ * @param kind - Block kind
428
+ * @param codec - Block codec
429
+ * @param payload - Block payload
430
+ * @param options - Optional metadata overrides
431
+ * @returns Context block
432
+ */
433
+ private createBlock<TPayload>(
434
+ kind: BlockKind,
435
+ codec: BlockCodec<TPayload>,
436
+ payload: TPayload,
437
+ options?: {
438
+ sensitivity?: SensitivityLevel;
439
+ source?: string;
440
+ tags?: string[];
441
+ }
442
+ ): ContextBlock<TPayload> {
443
+ // Validate payload
444
+ codec.validate(payload);
445
+
446
+ // Canonicalize and compute hash
447
+ const canonicalized = codec.canonicalize(payload);
448
+ const blockHash = codec.hash(canonicalized);
449
+
450
+ // Generate unique ID for this block instance
451
+ this.blockCounter++;
452
+
453
+ return {
454
+ blockHash,
455
+ meta: {
456
+ kind,
457
+ sensitivity: options?.sensitivity ?? 'public',
458
+ codecId: codec.codecId,
459
+ codecVersion: codec.version,
460
+ createdAt: Math.floor(Date.now() / 1000),
461
+ source: options?.source,
462
+ tags: options?.tags,
463
+ },
464
+ payload,
465
+ };
466
+ }
467
+ }