ai.matey.utils 0.2.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/conversation-history.js +139 -0
  3. package/dist/cjs/conversation-history.js.map +1 -0
  4. package/dist/cjs/index.js +42 -0
  5. package/dist/cjs/index.js.map +1 -0
  6. package/dist/cjs/model-cache.js +163 -0
  7. package/dist/cjs/model-cache.js.map +1 -0
  8. package/dist/cjs/parameter-normalizer.js +451 -0
  9. package/dist/cjs/parameter-normalizer.js.map +1 -0
  10. package/dist/cjs/streaming-modes.js +277 -0
  11. package/dist/cjs/streaming-modes.js.map +1 -0
  12. package/dist/cjs/streaming.js +892 -0
  13. package/dist/cjs/streaming.js.map +1 -0
  14. package/dist/cjs/structured-output.js +398 -0
  15. package/dist/cjs/structured-output.js.map +1 -0
  16. package/dist/cjs/system-message.js +222 -0
  17. package/dist/cjs/system-message.js.map +1 -0
  18. package/dist/cjs/validation.js +534 -0
  19. package/dist/cjs/validation.js.map +1 -0
  20. package/dist/cjs/warnings.js +301 -0
  21. package/dist/cjs/warnings.js.map +1 -0
  22. package/dist/esm/conversation-history.js +134 -0
  23. package/dist/esm/conversation-history.js.map +1 -0
  24. package/dist/esm/index.js +26 -0
  25. package/dist/esm/index.js.map +1 -0
  26. package/dist/esm/model-cache.js +158 -0
  27. package/dist/esm/model-cache.js.map +1 -0
  28. package/dist/esm/parameter-normalizer.js +434 -0
  29. package/dist/esm/parameter-normalizer.js.map +1 -0
  30. package/dist/esm/streaming-modes.js +265 -0
  31. package/dist/esm/streaming-modes.js.map +1 -0
  32. package/dist/esm/streaming.js +860 -0
  33. package/dist/esm/streaming.js.map +1 -0
  34. package/dist/esm/structured-output.js +387 -0
  35. package/dist/esm/structured-output.js.map +1 -0
  36. package/dist/esm/system-message.js +213 -0
  37. package/dist/esm/system-message.js.map +1 -0
  38. package/dist/esm/validation.js +523 -0
  39. package/dist/esm/validation.js.map +1 -0
  40. package/dist/esm/warnings.js +284 -0
  41. package/dist/esm/warnings.js.map +1 -0
  42. package/dist/types/conversation-history.d.ts +70 -0
  43. package/dist/types/conversation-history.d.ts.map +1 -0
  44. package/dist/types/index.d.ts +17 -0
  45. package/dist/types/index.d.ts.map +1 -0
  46. package/dist/types/model-cache.d.ts +88 -0
  47. package/dist/types/model-cache.d.ts.map +1 -0
  48. package/dist/types/parameter-normalizer.d.ts +154 -0
  49. package/dist/types/parameter-normalizer.d.ts.map +1 -0
  50. package/dist/types/streaming-modes.d.ts +139 -0
  51. package/dist/types/streaming-modes.d.ts.map +1 -0
  52. package/dist/types/streaming.d.ts +384 -0
  53. package/dist/types/streaming.d.ts.map +1 -0
  54. package/dist/types/structured-output.d.ts +157 -0
  55. package/dist/types/structured-output.d.ts.map +1 -0
  56. package/dist/types/system-message.d.ts +78 -0
  57. package/dist/types/system-message.d.ts.map +1 -0
  58. package/dist/types/validation.d.ts +46 -0
  59. package/dist/types/validation.d.ts.map +1 -0
  60. package/dist/types/warnings.d.ts +149 -0
  61. package/dist/types/warnings.d.ts.map +1 -0
  62. package/package.json +75 -0
  63. package/readme.md +280 -0
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ /**
3
+ * Streaming Mode Conversion Utilities
4
+ *
5
+ * This module handles conversion between delta and accumulated streaming modes.
6
+ * Use these utilities when you need to transform IR stream chunks between formats.
7
+ *
8
+ * For general stream operations (map, filter, collect), see ./streaming.ts
9
+ *
10
+ * @example Converting stream modes
11
+ * ```typescript
12
+ * import { convertStreamMode, createAccumulatorState } from 'ai.matey.utils';
13
+ *
14
+ * const converter = createAccumulatorState();
15
+ * const accumulated = await convertStreamMode(deltaStream, 'accumulated', { converter });
16
+ * ```
17
+ *
18
+ * @module streaming-modes
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.createAccumulatorState = createAccumulatorState;
22
+ exports.detectChunkMode = detectChunkMode;
23
+ exports.needsConversion = needsConversion;
24
+ exports.convertStreamMode = convertStreamMode;
25
+ exports.convertChunkMode = convertChunkMode;
26
+ exports.getEffectiveStreamMode = getEffectiveStreamMode;
27
+ exports.mergeStreamingConfig = mergeStreamingConfig;
28
+ exports.ensureStreamMode = ensureStreamMode;
29
+ exports.addAccumulatedToStream = addAccumulatedToStream;
30
+ exports.stripAccumulatedFromStream = stripAccumulatedFromStream;
31
+ const ai_matey_types_1 = require("ai.matey.types");
32
+ /**
33
+ * Create a new stream accumulator state.
34
+ */
35
+ function createAccumulatorState() {
36
+ return {
37
+ accumulated: '',
38
+ chunkCount: 0,
39
+ lastSequence: -1,
40
+ };
41
+ }
42
+ // ============================================================================
43
+ // Mode Detection
44
+ // ============================================================================
45
+ /**
46
+ * Detect the streaming mode of a content chunk.
47
+ *
48
+ * @param chunk Content chunk to inspect
49
+ * @returns Detected streaming mode
50
+ */
51
+ function detectChunkMode(chunk) {
52
+ // If both delta and accumulated are present, it's providing both
53
+ if (chunk.delta && chunk.accumulated) {
54
+ return 'accumulated'; // Preferred mode when both available
55
+ }
56
+ // If only accumulated, it's accumulated mode
57
+ if (chunk.accumulated) {
58
+ return 'accumulated';
59
+ }
60
+ // Default: delta mode
61
+ return 'delta';
62
+ }
63
+ /**
64
+ * Check if a chunk needs conversion to target mode.
65
+ *
66
+ * @param chunk Content chunk to check
67
+ * @param targetMode Desired streaming mode
68
+ * @param preserveIfMatch Whether to skip conversion if already in target mode
69
+ * @returns true if conversion is needed
70
+ */
71
+ function needsConversion(chunk, targetMode, preserveIfMatch = true) {
72
+ if (!preserveIfMatch) {
73
+ return true;
74
+ }
75
+ const currentMode = detectChunkMode(chunk);
76
+ // No conversion needed if already in target mode
77
+ if (currentMode === targetMode) {
78
+ return false;
79
+ }
80
+ // If target is delta and chunk has delta, no conversion needed
81
+ if (targetMode === 'delta' && chunk.delta) {
82
+ return false;
83
+ }
84
+ // If target is accumulated and chunk has accumulated, no conversion needed
85
+ if (targetMode === 'accumulated' && chunk.accumulated) {
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+ // ============================================================================
91
+ // Stream Conversion
92
+ // ============================================================================
93
+ /**
94
+ * Convert IR stream to target streaming mode.
95
+ *
96
+ * This function transforms an IR stream to use the specified streaming mode:
97
+ * - Delta mode: Only incremental deltas
98
+ * - Accumulated mode: Full text in each chunk
99
+ *
100
+ * @param stream Source IR stream
101
+ * @param options Conversion options
102
+ * @returns Converted IR stream
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // Convert to accumulated mode
107
+ * const accumulated = convertStreamMode(deltaStream, { mode: 'accumulated' });
108
+ *
109
+ * // Convert to delta mode
110
+ * const delta = convertStreamMode(accumulatedStream, { mode: 'delta' });
111
+ * ```
112
+ */
113
+ async function* convertStreamMode(stream, options = {}) {
114
+ const { mode = ai_matey_types_1.DEFAULT_CONVERSION_OPTIONS.mode, preserveIfMatch = ai_matey_types_1.DEFAULT_CONVERSION_OPTIONS.preserveIfMatch, transform, validateSequence = ai_matey_types_1.DEFAULT_CONVERSION_OPTIONS.validateSequence, } = options;
115
+ const state = createAccumulatorState();
116
+ for await (const chunk of stream) {
117
+ // Only convert content chunks
118
+ if (chunk.type !== 'content') {
119
+ yield chunk;
120
+ continue;
121
+ }
122
+ // Validate sequence if requested
123
+ if (validateSequence && chunk.sequence !== undefined) {
124
+ if (chunk.sequence <= state.lastSequence) {
125
+ throw new Error(`Out of order chunk: expected sequence > ${state.lastSequence}, got ${chunk.sequence}`);
126
+ }
127
+ state.lastSequence = chunk.sequence;
128
+ }
129
+ // Check if conversion is needed
130
+ if (!needsConversion(chunk, mode, preserveIfMatch)) {
131
+ yield chunk;
132
+ continue;
133
+ }
134
+ // Convert chunk to target mode
135
+ const converted = convertChunkMode(chunk, mode, state, transform);
136
+ yield converted;
137
+ state.chunkCount++;
138
+ }
139
+ }
140
+ /**
141
+ * Convert a single content chunk to target mode.
142
+ *
143
+ * @param chunk Source content chunk
144
+ * @param targetMode Target streaming mode
145
+ * @param state Accumulator state (updated in place)
146
+ * @param transform Optional transform function
147
+ * @returns Converted content chunk
148
+ */
149
+ function convertChunkMode(chunk, targetMode, state, transform) {
150
+ // Update accumulated state
151
+ state.accumulated += chunk.delta;
152
+ if (targetMode === 'delta') {
153
+ // Delta mode: ensure only delta is present
154
+ return {
155
+ type: 'content',
156
+ sequence: chunk.sequence,
157
+ delta: chunk.delta,
158
+ role: chunk.role,
159
+ };
160
+ }
161
+ else {
162
+ // Accumulated mode: provide accumulated text
163
+ const accumulated = transform ? transform(state.accumulated) : state.accumulated;
164
+ return {
165
+ type: 'content',
166
+ sequence: chunk.sequence,
167
+ delta: chunk.delta, // Still provide delta for compatibility
168
+ accumulated,
169
+ role: chunk.role,
170
+ };
171
+ }
172
+ }
173
+ // ============================================================================
174
+ // Configuration Helpers
175
+ // ============================================================================
176
+ /**
177
+ * Get effective streaming mode from cascading configuration.
178
+ *
179
+ * Priority order (highest to lowest):
180
+ * 1. Request-level streamMode
181
+ * 2. Conversion options mode
182
+ * 3. Streaming config mode
183
+ * 4. Default ('delta')
184
+ *
185
+ * @param requestMode Stream mode from request
186
+ * @param conversionMode Stream mode from conversion options
187
+ * @param config Streaming configuration
188
+ * @returns Effective streaming mode
189
+ */
190
+ function getEffectiveStreamMode(requestMode, conversionMode, config) {
191
+ return requestMode || conversionMode || config?.mode || ai_matey_types_1.DEFAULT_STREAMING_CONFIG.mode;
192
+ }
193
+ /**
194
+ * Merge streaming configurations with priority.
195
+ *
196
+ * @param configs Configuration objects in priority order (first wins)
197
+ * @returns Merged configuration
198
+ */
199
+ function mergeStreamingConfig(...configs) {
200
+ const result = { ...ai_matey_types_1.DEFAULT_STREAMING_CONFIG };
201
+ // Apply configs in reverse order (last has lowest priority)
202
+ for (let i = configs.length - 1; i >= 0; i--) {
203
+ const config = configs[i];
204
+ if (!config) {
205
+ continue;
206
+ }
207
+ if (config.mode !== undefined) {
208
+ result.mode = config.mode;
209
+ }
210
+ if (config.includeBoth !== undefined) {
211
+ result.includeBoth = config.includeBoth;
212
+ }
213
+ if (config.bufferStrategy !== undefined) {
214
+ result.bufferStrategy = config.bufferStrategy;
215
+ }
216
+ }
217
+ return result;
218
+ }
219
+ // ============================================================================
220
+ // Stream Utilities
221
+ // ============================================================================
222
+ /**
223
+ * Ensure all chunks in a stream have a specific mode.
224
+ *
225
+ * If chunks don't have the required format, converts them.
226
+ *
227
+ * @param stream Source stream
228
+ * @param mode Required mode
229
+ * @returns Stream with all chunks in required mode
230
+ */
231
+ async function* ensureStreamMode(stream, mode) {
232
+ yield* convertStreamMode(stream, { mode, preserveIfMatch: true });
233
+ }
234
+ /**
235
+ * Add accumulated field to all content chunks (dual-mode streaming).
236
+ *
237
+ * Useful for backends that want to provide both delta and accumulated.
238
+ *
239
+ * @param stream Source stream (delta-only)
240
+ * @returns Stream with both delta and accumulated in content chunks
241
+ */
242
+ async function* addAccumulatedToStream(stream) {
243
+ const state = createAccumulatorState();
244
+ for await (const chunk of stream) {
245
+ if (chunk.type === 'content') {
246
+ state.accumulated += chunk.delta;
247
+ yield {
248
+ ...chunk,
249
+ accumulated: state.accumulated,
250
+ };
251
+ state.chunkCount++;
252
+ }
253
+ else {
254
+ yield chunk;
255
+ }
256
+ }
257
+ }
258
+ /**
259
+ * Strip accumulated field from all content chunks (delta-only streaming).
260
+ *
261
+ * Useful for reducing bandwidth when accumulated isn't needed.
262
+ *
263
+ * @param stream Source stream
264
+ * @returns Stream with only delta in content chunks
265
+ */
266
+ async function* stripAccumulatedFromStream(stream) {
267
+ for await (const chunk of stream) {
268
+ if (chunk.type === 'content') {
269
+ const { accumulated: _accumulated, ...deltaOnly } = chunk;
270
+ yield deltaOnly;
271
+ }
272
+ else {
273
+ yield chunk;
274
+ }
275
+ }
276
+ }
277
+ //# sourceMappingURL=streaming-modes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-modes.js","sourceRoot":"","sources":["../../src/streaming-modes.ts"],"names":[],"mappings":"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"}