@czap/astro 0.1.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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/Satellite.d.ts +42 -0
  4. package/dist/Satellite.d.ts.map +1 -0
  5. package/dist/Satellite.js +55 -0
  6. package/dist/Satellite.js.map +1 -0
  7. package/dist/client-directives/gpu.d.ts +3 -0
  8. package/dist/client-directives/gpu.d.ts.map +1 -0
  9. package/dist/client-directives/gpu.js +5 -0
  10. package/dist/client-directives/gpu.js.map +1 -0
  11. package/dist/client-directives/llm.d.ts +3 -0
  12. package/dist/client-directives/llm.d.ts.map +1 -0
  13. package/dist/client-directives/llm.js +5 -0
  14. package/dist/client-directives/llm.js.map +1 -0
  15. package/dist/client-directives/satellite.d.ts +3 -0
  16. package/dist/client-directives/satellite.d.ts.map +1 -0
  17. package/dist/client-directives/satellite.js +5 -0
  18. package/dist/client-directives/satellite.js.map +1 -0
  19. package/dist/client-directives/stream.d.ts +3 -0
  20. package/dist/client-directives/stream.d.ts.map +1 -0
  21. package/dist/client-directives/stream.js +5 -0
  22. package/dist/client-directives/stream.js.map +1 -0
  23. package/dist/client-directives/wasm.d.ts +3 -0
  24. package/dist/client-directives/wasm.d.ts.map +1 -0
  25. package/dist/client-directives/wasm.js +6 -0
  26. package/dist/client-directives/wasm.js.map +1 -0
  27. package/dist/client-directives/worker.d.ts +3 -0
  28. package/dist/client-directives/worker.d.ts.map +1 -0
  29. package/dist/client-directives/worker.js +5 -0
  30. package/dist/client-directives/worker.js.map +1 -0
  31. package/dist/detect-upgrade.d.ts +16 -0
  32. package/dist/detect-upgrade.d.ts.map +1 -0
  33. package/dist/detect-upgrade.js +105 -0
  34. package/dist/detect-upgrade.js.map +1 -0
  35. package/dist/headers.d.ts +45 -0
  36. package/dist/headers.d.ts.map +1 -0
  37. package/dist/headers.js +64 -0
  38. package/dist/headers.js.map +1 -0
  39. package/dist/index.d.ts +30 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +26 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/integration.d.ts +76 -0
  44. package/dist/integration.d.ts.map +1 -0
  45. package/dist/integration.js +240 -0
  46. package/dist/integration.js.map +1 -0
  47. package/dist/middleware.d.ts +69 -0
  48. package/dist/middleware.d.ts.map +1 -0
  49. package/dist/middleware.js +75 -0
  50. package/dist/middleware.js.map +1 -0
  51. package/dist/quantize.d.ts +50 -0
  52. package/dist/quantize.d.ts.map +1 -0
  53. package/dist/quantize.js +122 -0
  54. package/dist/quantize.js.map +1 -0
  55. package/dist/runtime/boundary.d.ts +123 -0
  56. package/dist/runtime/boundary.d.ts.map +1 -0
  57. package/dist/runtime/boundary.js +164 -0
  58. package/dist/runtime/boundary.js.map +1 -0
  59. package/dist/runtime/globals.d.ts +32 -0
  60. package/dist/runtime/globals.d.ts.map +1 -0
  61. package/dist/runtime/globals.js +45 -0
  62. package/dist/runtime/globals.js.map +1 -0
  63. package/dist/runtime/gpu.d.ts +15 -0
  64. package/dist/runtime/gpu.d.ts.map +1 -0
  65. package/dist/runtime/gpu.js +266 -0
  66. package/dist/runtime/gpu.js.map +1 -0
  67. package/dist/runtime/index.d.ts +7 -0
  68. package/dist/runtime/index.d.ts.map +1 -0
  69. package/dist/runtime/index.js +5 -0
  70. package/dist/runtime/index.js.map +1 -0
  71. package/dist/runtime/llm-receipt-tracker.d.ts +21 -0
  72. package/dist/runtime/llm-receipt-tracker.d.ts.map +1 -0
  73. package/dist/runtime/llm-receipt-tracker.js +60 -0
  74. package/dist/runtime/llm-receipt-tracker.js.map +1 -0
  75. package/dist/runtime/llm-render-pipeline.d.ts +89 -0
  76. package/dist/runtime/llm-render-pipeline.d.ts.map +1 -0
  77. package/dist/runtime/llm-render-pipeline.js +241 -0
  78. package/dist/runtime/llm-render-pipeline.js.map +1 -0
  79. package/dist/runtime/llm-session.d.ts +126 -0
  80. package/dist/runtime/llm-session.d.ts.map +1 -0
  81. package/dist/runtime/llm-session.js +385 -0
  82. package/dist/runtime/llm-session.js.map +1 -0
  83. package/dist/runtime/llm.d.ts +16 -0
  84. package/dist/runtime/llm.d.ts.map +1 -0
  85. package/dist/runtime/llm.js +273 -0
  86. package/dist/runtime/llm.js.map +1 -0
  87. package/dist/runtime/policy.d.ts +100 -0
  88. package/dist/runtime/policy.d.ts.map +1 -0
  89. package/dist/runtime/policy.js +147 -0
  90. package/dist/runtime/policy.js.map +1 -0
  91. package/dist/runtime/receipt-chain.d.ts +22 -0
  92. package/dist/runtime/receipt-chain.d.ts.map +1 -0
  93. package/dist/runtime/receipt-chain.js +80 -0
  94. package/dist/runtime/receipt-chain.js.map +1 -0
  95. package/dist/runtime/runtime-session.d.ts +34 -0
  96. package/dist/runtime/runtime-session.d.ts.map +1 -0
  97. package/dist/runtime/runtime-session.js +102 -0
  98. package/dist/runtime/runtime-session.js.map +1 -0
  99. package/dist/runtime/satellite.d.ts +13 -0
  100. package/dist/runtime/satellite.d.ts.map +1 -0
  101. package/dist/runtime/satellite.js +59 -0
  102. package/dist/runtime/satellite.js.map +1 -0
  103. package/dist/runtime/slots.d.ts +34 -0
  104. package/dist/runtime/slots.d.ts.map +1 -0
  105. package/dist/runtime/slots.js +108 -0
  106. package/dist/runtime/slots.js.map +1 -0
  107. package/dist/runtime/stream-session.d.ts +47 -0
  108. package/dist/runtime/stream-session.d.ts.map +1 -0
  109. package/dist/runtime/stream-session.js +82 -0
  110. package/dist/runtime/stream-session.js.map +1 -0
  111. package/dist/runtime/stream.d.ts +9 -0
  112. package/dist/runtime/stream.d.ts.map +1 -0
  113. package/dist/runtime/stream.js +308 -0
  114. package/dist/runtime/stream.js.map +1 -0
  115. package/dist/runtime/url-policy.d.ts +28 -0
  116. package/dist/runtime/url-policy.d.ts.map +1 -0
  117. package/dist/runtime/url-policy.js +87 -0
  118. package/dist/runtime/url-policy.js.map +1 -0
  119. package/dist/runtime/wasm.d.ts +20 -0
  120. package/dist/runtime/wasm.d.ts.map +1 -0
  121. package/dist/runtime/wasm.js +70 -0
  122. package/dist/runtime/wasm.js.map +1 -0
  123. package/dist/runtime/worker.d.ts +11 -0
  124. package/dist/runtime/worker.d.ts.map +1 -0
  125. package/dist/runtime/worker.js +249 -0
  126. package/dist/runtime/worker.js.map +1 -0
  127. package/package.json +106 -0
  128. package/src/Satellite.astro +39 -0
  129. package/src/Satellite.ts +84 -0
  130. package/src/client-directives/gpu.ts +5 -0
  131. package/src/client-directives/llm.ts +5 -0
  132. package/src/client-directives/satellite.ts +5 -0
  133. package/src/client-directives/stream.ts +5 -0
  134. package/src/client-directives/wasm.ts +6 -0
  135. package/src/client-directives/worker.ts +5 -0
  136. package/src/detect-upgrade.ts +105 -0
  137. package/src/headers.ts +84 -0
  138. package/src/index.ts +30 -0
  139. package/src/integration.ts +309 -0
  140. package/src/middleware.ts +133 -0
  141. package/src/quantize.ts +173 -0
  142. package/src/runtime/boundary.ts +263 -0
  143. package/src/runtime/globals.ts +57 -0
  144. package/src/runtime/gpu.ts +291 -0
  145. package/src/runtime/index.ts +12 -0
  146. package/src/runtime/llm-receipt-tracker.ts +88 -0
  147. package/src/runtime/llm-render-pipeline.ts +366 -0
  148. package/src/runtime/llm-session.ts +548 -0
  149. package/src/runtime/llm.ts +344 -0
  150. package/src/runtime/policy.ts +229 -0
  151. package/src/runtime/receipt-chain.ts +106 -0
  152. package/src/runtime/runtime-session.ts +139 -0
  153. package/src/runtime/satellite.ts +80 -0
  154. package/src/runtime/slots.ts +136 -0
  155. package/src/runtime/stream-session.ts +125 -0
  156. package/src/runtime/stream.ts +407 -0
  157. package/src/runtime/url-policy.ts +107 -0
  158. package/src/runtime/wasm.ts +85 -0
  159. package/src/runtime/worker.ts +307 -0
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Internal render-pipeline building block used by the `client:llm`
3
+ * directive. Owns the token buffer, the `GenFrame` scheduler, the
4
+ * quality controller, and the fast-lane state machine.
5
+ *
6
+ * @module
7
+ */
8
+ import { GenFrame, TokenBuffer, UIQuality } from '@czap/core';
9
+ import type { UIFrame } from '@czap/core';
10
+
11
+ type DeviceTier = 'none' | 'transitions' | 'animations' | 'physics' | 'compute';
12
+
13
+ /**
14
+ * Bundle of runtime objects one LLM session owns: the token buffer,
15
+ * the adaptive quality controller, and the frame scheduler.
16
+ */
17
+ export interface LLMRenderRuntime {
18
+ /** Ring of incoming text fragments feeding the scheduler. */
19
+ readonly tokenBuffer: TokenBuffer.Shape<string>;
20
+ /** Adaptive quality controller. Reassigned on each reset. */
21
+ quality: ReturnType<typeof UIQuality.make>;
22
+ /** Frame scheduler bound to `tokenBuffer` + `quality`. */
23
+ scheduler: ReturnType<typeof GenFrame.make>;
24
+ }
25
+
26
+ /**
27
+ * Host callbacks the pipeline invokes when it wants to render a text
28
+ * delta or a finalised `UIFrame`. Callbacks return `true` when the
29
+ * frame/text was actually rendered so the pipeline can advance state.
30
+ */
31
+ export interface LLMRenderHost {
32
+ renderText(text: string, accumulated: string, mode: string): boolean;
33
+ renderFrame(frame: UIFrame, accumulated: string, mode: string): boolean;
34
+ emitToken(text: string, accumulated: string): void;
35
+ emitFrame(frame: UIFrame): void;
36
+ }
37
+
38
+ /**
39
+ * Pipeline construction options. `mode` is the LLM render mode label;
40
+ * `getDeviceTier` is called on every quality evaluation so tier
41
+ * changes flow into the scheduler without explicit re-wiring.
42
+ */
43
+ export interface LLMRenderPipelineConfig {
44
+ /** User-provided render mode label (e.g. `"fast"`, `"stream"`). */
45
+ readonly mode: string;
46
+ /** Current device tier getter; consulted per evaluation. */
47
+ readonly getDeviceTier: () => DeviceTier;
48
+ }
49
+
50
+ /** Manages render runtime pooling, token buffering, frame flushing, and fast lane logic. */
51
+ export interface LLMRenderPipeline {
52
+ readonly fastLanePrimed: boolean;
53
+ readonly flushQueued: boolean;
54
+ readonly queuedTextFragments: string[];
55
+ readonly llmRuntime: LLMRenderRuntime | null;
56
+ accumulated: string;
57
+
58
+ isRenderTierEnabled(): boolean;
59
+ canQueueRenderBurst(): boolean;
60
+ shouldUseFastLane(toolCallBufferIsNull: boolean, receiptChainIsNull: boolean, runtimeState: string): boolean;
61
+
62
+ getLLMRuntime(): LLMRenderRuntime;
63
+ promoteFastLane(): void;
64
+ resetRenderRuntime(): void;
65
+
66
+ renderImmediateText(text: string, host: LLMRenderHost): boolean;
67
+ renderFrame(frame: UIFrame, host: LLMRenderHost): boolean;
68
+ flushFrames(
69
+ activeRuntime: LLMRenderRuntime,
70
+ canRender: boolean,
71
+ host: LLMRenderHost,
72
+ recordFrame: (frame: UIFrame) => void,
73
+ shouldRecordFrame?: boolean,
74
+ ): boolean;
75
+ flushQueuedText(host: LLMRenderHost, recordFrame: (frame: UIFrame) => void, shouldRecordFrame?: boolean): void;
76
+ enqueueFlush(host: LLMRenderHost, recordFrame: (frame: UIFrame) => void, shouldRecordFrame?: boolean): void;
77
+ flushPendingText(host: LLMRenderHost, recordFrame: (frame: UIFrame) => void): void;
78
+
79
+ pushText(fragment: string): void;
80
+ clearQueuedText(): void;
81
+ setFastLanePrimed(value: boolean): void;
82
+ resetPipelineState(): void;
83
+ releaseRuntime(): void;
84
+ }
85
+
86
+ // -- Standby runtime pool (module-level singleton) --
87
+
88
+ let standbyLLMRuntime: LLMRenderRuntime | null = null;
89
+
90
+ function resetLLMRuntime(runtime: LLMRenderRuntime): void {
91
+ runtime.tokenBuffer.reset();
92
+ runtime.quality = UIQuality.make();
93
+ runtime.scheduler.reset();
94
+ }
95
+
96
+ function createSessionRenderRuntime(config: Pick<LLMRenderPipelineConfig, 'getDeviceTier'>): LLMRenderRuntime {
97
+ const tokenBuffer = TokenBuffer.make<string>({ capacity: 128 });
98
+ const llmRuntime: LLMRenderRuntime = {
99
+ tokenBuffer,
100
+ quality: UIQuality.make(),
101
+ scheduler: null as never,
102
+ };
103
+ llmRuntime.scheduler = GenFrame.make({
104
+ tokenBuffer,
105
+ getQualityTier: () => llmRuntime.quality.evaluate(tokenBuffer.occupancy, config.getDeviceTier()),
106
+ });
107
+ return llmRuntime;
108
+ }
109
+
110
+ /**
111
+ * Claim the standby LLM runtime (if any) or mint a fresh one. The
112
+ * standby pool holds at most one runtime so cold-start cost is
113
+ * amortised across successive `client:llm` mounts on the same page.
114
+ */
115
+ export function claimStandbyLLMRuntime(config: Pick<LLMRenderPipelineConfig, 'getDeviceTier'>): LLMRenderRuntime {
116
+ const claimed = standbyLLMRuntime;
117
+ standbyLLMRuntime = null;
118
+ if (claimed) {
119
+ resetLLMRuntime(claimed);
120
+ return claimed;
121
+ }
122
+
123
+ return createSessionRenderRuntime(config);
124
+ }
125
+
126
+ /**
127
+ * Return a no-longer-needed LLM runtime to the standby pool. Resets
128
+ * the runtime in place so the next claimer observes a clean slate.
129
+ * If the pool is already occupied the runtime is simply discarded.
130
+ */
131
+ export function releaseStandbyLLMRuntime(runtime: LLMRenderRuntime): void {
132
+ resetLLMRuntime(runtime);
133
+ if (standbyLLMRuntime === null) {
134
+ standbyLLMRuntime = runtime;
135
+ }
136
+ }
137
+
138
+ // -- Pipeline implementation --
139
+
140
+ /**
141
+ * Build a fresh {@link LLMRenderPipeline}. The pipeline lazily claims
142
+ * a runtime from the standby pool on first use and exposes every hook
143
+ * the `client:llm` directive needs to drive its render loop.
144
+ */
145
+ export function createLLMRenderPipeline(config: LLMRenderPipelineConfig): LLMRenderPipeline {
146
+ let _accumulated = '';
147
+ let _queuedTextFragments: string[] = [];
148
+ let _flushQueued = false;
149
+ let _fastLanePrimed = false;
150
+ let _llmRuntime: LLMRenderRuntime | null = null;
151
+ let _disposed = false;
152
+ let _queuedTextCount = 0;
153
+ let _queuedRecordFrame = false;
154
+ let _queuedHost: LLMRenderHost | null = null;
155
+ let _queuedRecordFrameHandler: ((frame: UIFrame) => void) | null = null;
156
+
157
+ const flushTask = (): void => {
158
+ if (!_flushQueued) {
159
+ return;
160
+ }
161
+
162
+ _flushQueued = false;
163
+ const host = _queuedHost;
164
+ const recordFrame = _queuedRecordFrameHandler;
165
+ const shouldRecordFrame = _queuedRecordFrame;
166
+ _queuedHost = null;
167
+ _queuedRecordFrameHandler = null;
168
+ _queuedRecordFrame = false;
169
+
170
+ if (_disposed || !host || !recordFrame) {
171
+ _queuedTextFragments = [];
172
+ _queuedTextCount = 0;
173
+ return;
174
+ }
175
+
176
+ pipeline.flushQueuedText(host, recordFrame, shouldRecordFrame);
177
+ };
178
+
179
+ const pipeline: LLMRenderPipeline = {
180
+ get fastLanePrimed() {
181
+ return _fastLanePrimed;
182
+ },
183
+ get flushQueued() {
184
+ return _flushQueued;
185
+ },
186
+ get queuedTextFragments() {
187
+ return _queuedTextFragments;
188
+ },
189
+ get llmRuntime() {
190
+ return _llmRuntime;
191
+ },
192
+ get accumulated() {
193
+ return _accumulated;
194
+ },
195
+ set accumulated(value: string) {
196
+ _accumulated = value;
197
+ },
198
+
199
+ isRenderTierEnabled(): boolean {
200
+ return config.getDeviceTier() !== 'none';
201
+ },
202
+
203
+ canQueueRenderBurst(): boolean {
204
+ return pipeline.isRenderTierEnabled();
205
+ },
206
+
207
+ shouldUseFastLane(toolCallBufferIsNull: boolean, receiptChainIsNull: boolean, runtimeState: string): boolean {
208
+ return (
209
+ !_fastLanePrimed &&
210
+ !_llmRuntime &&
211
+ _queuedTextCount === 0 &&
212
+ !_flushQueued &&
213
+ toolCallBufferIsNull &&
214
+ receiptChainIsNull &&
215
+ _accumulated.length === 0 &&
216
+ runtimeState !== 'reconnecting' &&
217
+ pipeline.isRenderTierEnabled()
218
+ );
219
+ },
220
+
221
+ getLLMRuntime(): LLMRenderRuntime {
222
+ if (_llmRuntime) {
223
+ return _llmRuntime;
224
+ }
225
+
226
+ _llmRuntime = claimStandbyLLMRuntime(config);
227
+ return _llmRuntime;
228
+ },
229
+
230
+ promoteFastLane(): void {
231
+ if (!_fastLanePrimed || _llmRuntime) {
232
+ return;
233
+ }
234
+
235
+ pipeline.getLLMRuntime();
236
+ },
237
+
238
+ resetRenderRuntime(): void {
239
+ if (_llmRuntime) {
240
+ resetLLMRuntime(_llmRuntime);
241
+ }
242
+ },
243
+
244
+ renderImmediateText(text: string, host: LLMRenderHost): boolean {
245
+ _accumulated += text;
246
+ return host.renderText(text, _accumulated, config.mode);
247
+ },
248
+
249
+ renderFrame(frame: UIFrame, host: LLMRenderHost): boolean {
250
+ const text = frame.tokens.join('');
251
+ if (!text) {
252
+ return false;
253
+ }
254
+
255
+ _accumulated += text;
256
+ return host.renderFrame(frame, _accumulated, config.mode);
257
+ },
258
+
259
+ flushFrames(
260
+ activeRuntime: LLMRenderRuntime,
261
+ canRender: boolean,
262
+ host: LLMRenderHost,
263
+ recordFrame: (frame: UIFrame) => void,
264
+ shouldRecordFrame = true,
265
+ ): boolean {
266
+ let renderedFrames = false;
267
+ while (true) {
268
+ const frame = activeRuntime.scheduler.tick();
269
+ if (!frame || frame.tokens.length === 0) {
270
+ return renderedFrames;
271
+ }
272
+
273
+ if (shouldRecordFrame) {
274
+ recordFrame(frame);
275
+ }
276
+ if (!canRender || !pipeline.renderFrame(frame, host)) {
277
+ continue;
278
+ }
279
+
280
+ renderedFrames = true;
281
+ host.emitFrame(frame);
282
+ }
283
+ },
284
+
285
+ flushQueuedText(host: LLMRenderHost, recordFrame: (frame: UIFrame) => void, shouldRecordFrame = true): void {
286
+ const fragments = _queuedTextFragments;
287
+ _queuedTextFragments = [];
288
+ _queuedTextCount = 0;
289
+
290
+ const canRender = pipeline.isRenderTierEnabled();
291
+ if (!canRender) {
292
+ return;
293
+ }
294
+
295
+ const activeRuntime = pipeline.getLLMRuntime();
296
+ for (const fragment of fragments) {
297
+ activeRuntime.tokenBuffer.push(fragment);
298
+ }
299
+
300
+ if (pipeline.flushFrames(activeRuntime, canRender, host, recordFrame, shouldRecordFrame)) {
301
+ host.emitToken(fragments.length === 1 ? fragments[0]! : fragments.join(''), _accumulated);
302
+ }
303
+ },
304
+
305
+ enqueueFlush(host: LLMRenderHost, recordFrame: (frame: UIFrame) => void, shouldRecordFrame = true): void {
306
+ _queuedHost = host;
307
+ _queuedRecordFrameHandler = recordFrame;
308
+ _queuedRecordFrame ||= shouldRecordFrame;
309
+ if (_flushQueued) {
310
+ return;
311
+ }
312
+
313
+ _flushQueued = true;
314
+ queueMicrotask(flushTask);
315
+ },
316
+
317
+ flushPendingText(host: LLMRenderHost, recordFrame: (frame: UIFrame) => void): void {
318
+ if (!_flushQueued && _queuedTextCount === 0) {
319
+ return;
320
+ }
321
+
322
+ _flushQueued = false;
323
+ _queuedHost = null;
324
+ _queuedRecordFrameHandler = null;
325
+ const shouldRecordFrame = _queuedRecordFrame;
326
+ _queuedRecordFrame = false;
327
+ pipeline.flushQueuedText(host, recordFrame, shouldRecordFrame);
328
+ },
329
+
330
+ pushText(fragment: string): void {
331
+ _queuedTextFragments.push(fragment);
332
+ _queuedTextCount += 1;
333
+ },
334
+
335
+ clearQueuedText(): void {
336
+ _queuedTextFragments = [];
337
+ _queuedTextCount = 0;
338
+ },
339
+
340
+ setFastLanePrimed(value: boolean): void {
341
+ _fastLanePrimed = value;
342
+ },
343
+
344
+ resetPipelineState(): void {
345
+ _accumulated = '';
346
+ _queuedTextFragments = [];
347
+ _queuedTextCount = 0;
348
+ _flushQueued = false;
349
+ _queuedRecordFrame = false;
350
+ _queuedHost = null;
351
+ _queuedRecordFrameHandler = null;
352
+ _fastLanePrimed = false;
353
+ pipeline.resetRenderRuntime();
354
+ },
355
+
356
+ releaseRuntime(): void {
357
+ if (_llmRuntime) {
358
+ releaseStandbyLLMRuntime(_llmRuntime);
359
+ _llmRuntime = null;
360
+ }
361
+ _disposed = true;
362
+ },
363
+ };
364
+
365
+ return pipeline;
366
+ }