prompt-identifiers-baml 0.1.0 → 0.1.1

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 CHANGED
@@ -11,24 +11,22 @@ npm install prompt-identifiers-baml prompt-identifiers @boundaryml/baml
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { wrapBamlFunction } from 'prompt-identifiers-baml';
15
- import { b } from './baml_client';
14
+ import { wrapBamlFunction } from "prompt-identifiers-baml";
15
+ import { b } from "./baml_client";
16
16
 
17
17
  // Wrap your BAML function
18
18
  const analyzeUser = wrapBamlFunction(b.AnalyzeUser, {
19
- config: { inputFormat: 'UUID', outputFormat: 'SafeNumeric' },
19
+ config: { inputFormat: "UUID", outputFormat: "SafeNumeric" },
20
20
  });
21
21
 
22
22
  // Use normally - IDs are automatically encoded/decoded
23
23
  const result = await analyzeUser({
24
- user_id: '123e4567-e89b-42d3-a456-426655440000',
25
- items: [
26
- { id: '987fcdeb-51a2-43f7-8d9c-0123456789ab', name: 'Order 1' },
27
- ],
24
+ user_id: "123e4567-e89b-42d3-a456-426655440000",
25
+ items: [{ id: "987fcdeb-51a2-43f7-8d9c-0123456789ab", name: "Order 1" }],
28
26
  });
29
27
 
30
28
  // The BAML function receives:
31
- // { user_id: '<000>', items: [{ id: '<001>', name: 'Order 1' }] }
29
+ // { user_id: '~000~', items: [{ id: '~001~', name: 'Order 1' }] }
32
30
  //
33
31
  // You receive the response with original UUIDs restored
34
32
  ```
@@ -36,10 +34,10 @@ const result = await analyzeUser({
36
34
  ## How It Works
37
35
 
38
36
  1. **Before BAML call**: Deep traverses input object and encodes all ID fields
39
- - `123e4567-e89b-42d3-a456-426655440000` → `<000>`
37
+ - `123e4567-e89b-42d3-a456-426655440000` → `~000~`
40
38
 
41
39
  2. **After BAML call**: Deep traverses output object and decodes all placeholders
42
- - `<000>` → `123e4567-e89b-42d3-a456-426655440000`
40
+ - `~000~` → `123e4567-e89b-42d3-a456-426655440000`
43
41
 
44
42
  This is completely transparent - you work with real IDs, the LLM works with compact placeholders.
45
43
 
@@ -49,21 +47,29 @@ This is completely transparent - you work with real IDs, the LLM works with comp
49
47
  wrapBamlFunction(fn, {
50
48
  // Required: encoding configuration
51
49
  config: {
52
- inputFormat: 'UUID', // or 'ULID' or custom RegExp
53
- outputFormat: 'SafeNumeric', // or 'Numeric', 'IdToken', { template: '...' }
50
+ inputFormat: "UUID", // or 'ULID' or custom RegExp
51
+ outputFormat: "SafeNumeric", // or 'Numeric', 'IdToken', { template: '...' }
54
52
  },
55
53
 
56
54
  // Optional: specify which fields to encode
57
55
  // If not provided, all matching strings are encoded
58
- encodeFields: ['user_id', 'items[].id', 'metadata.owner_id'],
56
+ encodeFields: ["user_id", "items[].id", "metadata.owner_id"],
57
+
58
+ // Optional: enable debug mode for detailed diagnostics
59
+ debug: true,
59
60
 
60
61
  // Optional: callbacks for logging/debugging
61
62
  onEncode: (result) => {
62
- console.log(`Encoded ${result.encodedCount} IDs`);
63
- console.log('Mapping:', result.mapping);
63
+ console.log("Mapping:", result.mapping);
64
+ // debugData is only present when debug: true
65
+ if (result.debugData) {
66
+ console.log(`Encoded ${result.debugData.encodedCount} IDs in ${result.debugData.durationMs}ms`);
67
+ }
64
68
  },
65
69
  onDecode: (result) => {
66
- console.log(`Decoded ${result.decodedCount} placeholders`);
70
+ if (result.debugData) {
71
+ console.log(`Decoded ${result.debugData.decodedCount} placeholders in ${result.debugData.durationMs}ms`);
72
+ }
67
73
  },
68
74
  });
69
75
  ```
@@ -72,40 +78,40 @@ wrapBamlFunction(fn, {
72
78
 
73
79
  The `encodeFields` option supports dot notation and array wildcards:
74
80
 
75
- | Pattern | Description | Example Match |
76
- |---------|-------------|---------------|
77
- | `user_id` | Top-level field | `{ user_id: '...' }` |
78
- | `data.user_id` | Nested field | `{ data: { user_id: '...' } }` |
79
- | `items[].id` | Array item field | `{ items: [{ id: '...' }] }` |
80
- | `data.users[].profile.id` | Deep nested | `{ data: { users: [{ profile: { id: '...' } }] } }` |
81
+ | Pattern | Description | Example Match |
82
+ | ------------------------- | ---------------- | --------------------------------------------------- |
83
+ | `user_id` | Top-level field | `{ user_id: '...' }` |
84
+ | `data.user_id` | Nested field | `{ data: { user_id: '...' } }` |
85
+ | `items[].id` | Array item field | `{ items: [{ id: '...' }] }` |
86
+ | `data.users[].profile.id` | Deep nested | `{ data: { users: [{ profile: { id: '...' } }] } }` |
81
87
 
82
88
  ### Input Formats
83
89
 
84
- | Format | Description | Example |
85
- |--------|-------------|---------|
86
- | `'UUID'` | RFC 4122 UUIDs | `123e4567-e89b-42d3-a456-426655440000` |
87
- | `'ULID'` | Crockford Base32 ULIDs | `01ARZ3NDEKTSV4RRFFQ69G5FAV` |
88
- | `RegExp` | Custom pattern | `/user-\d{6}/gi` |
90
+ | Format | Description | Example |
91
+ | -------- | ---------------------- | -------------------------------------- |
92
+ | `'UUID'` | RFC 4122 UUIDs | `123e4567-e89b-42d3-a456-426655440000` |
93
+ | `'ULID'` | Crockford Base32 ULIDs | `01ARZ3NDEKTSV4RRFFQ69G5FAV` |
94
+ | `RegExp` | Custom pattern | `/user-\d{6}/gi` |
89
95
 
90
96
  ### Output Formats
91
97
 
92
- | Format | Description | Example |
93
- |--------|-------------|---------|
94
- | `'SafeNumeric'` | Collision-safe with angle brackets (recommended) | `<000>`, `<001>` |
95
- | `'Numeric'` | Simple numeric with smart triplet expansion | `000`, `001` |
96
- | `'IdToken'` | Base62 encoding | `0`, `A`, `z`, `10` |
97
- | `{ template: '...' }` | Custom template | `{ template: '[ID:{i}]' }` → `[ID:0]` |
98
+ | Format | Description | Example |
99
+ | --------------------- | ------------------------------------------------- | ------------------------------------- |
100
+ | `'SafeNumeric'` | Collision-safe with tildes (recommended) | `~000~`, `~001~` |
101
+ | `'Numeric'` | Simple numeric with smart triplet expansion | `000`, `001` |
102
+ | `'IdToken'` | Base62 encoding | `0`, `A`, `z`, `10` |
103
+ | `{ template: '...' }` | Custom template | `{ template: '[ID:{i}]' }` → `[ID:0]` |
98
104
 
99
105
  ## Streaming Support
100
106
 
101
107
  Use `wrapBamlStreamingFunction` for BAML streaming functions:
102
108
 
103
109
  ```typescript
104
- import { wrapBamlStreamingFunction } from 'prompt-identifiers-baml';
105
- import { b } from './baml_client';
110
+ import { wrapBamlStreamingFunction } from "prompt-identifiers-baml";
111
+ import { b } from "./baml_client";
106
112
 
107
113
  const streamAnalysis = wrapBamlStreamingFunction(b.stream.AnalyzeUser, {
108
- config: { inputFormat: 'UUID', outputFormat: 'SafeNumeric' },
114
+ config: { inputFormat: "UUID", outputFormat: "SafeNumeric" },
109
115
  });
110
116
 
111
117
  // IDs are decoded in real-time as partials arrive
@@ -121,15 +127,15 @@ for await (const partial of streamAnalysis({ user_id: uuid })) {
121
127
  Manually encode an object (useful for custom integrations):
122
128
 
123
129
  ```typescript
124
- import { encodeObject } from 'prompt-identifiers-baml';
130
+ import { encodeObject } from "prompt-identifiers-baml";
125
131
 
126
132
  const { encoded, mapping } = encodeObject(
127
- { user_id: 'uuid-here', data: { owner: 'other-uuid' } },
128
- { inputFormat: 'UUID', outputFormat: 'SafeNumeric' }
133
+ { user_id: "uuid-here", data: { owner: "other-uuid" } },
134
+ { inputFormat: "UUID", outputFormat: "SafeNumeric" }
129
135
  );
130
136
 
131
- // encoded: { user_id: '<000>', data: { owner: '<001>' } }
132
- // mapping: { '<000>': 'uuid-here', '<001>': 'other-uuid' }
137
+ // encoded: { user_id: '~000~', data: { owner: '~001~' } }
138
+ // mapping: { '~000~': 'uuid-here', '~001~': 'other-uuid' }
133
139
  ```
134
140
 
135
141
  ### decodeObject
@@ -137,11 +143,11 @@ const { encoded, mapping } = encodeObject(
137
143
  Manually decode an object:
138
144
 
139
145
  ```typescript
140
- import { decodeObject } from 'prompt-identifiers-baml';
146
+ import { decodeObject } from "prompt-identifiers-baml";
141
147
 
142
148
  const decoded = decodeObject(
143
- { user_id: '<000>', summary: 'User <000> is active' },
144
- { '<000>': 'uuid-here' }
149
+ { user_id: "~000~", summary: "User ~000~ is active" },
150
+ { "~000~": "uuid-here" }
145
151
  );
146
152
 
147
153
  // decoded: { user_id: 'uuid-here', summary: 'User uuid-here is active' }
@@ -165,11 +171,13 @@ const result: AnalyzeUserOutput = await analyzeUser({
165
171
  ## Auto-Detection vs Explicit Fields
166
172
 
167
173
  **Auto-detection mode** (no `encodeFields`):
174
+
168
175
  - Encodes ALL string fields matching the input pattern
169
176
  - Simple to use, works for most cases
170
177
  - May encode fields you don't want encoded
171
178
 
172
179
  **Explicit fields** (with `encodeFields`):
180
+
173
181
  - Only encodes specified fields
174
182
  - More precise control
175
183
  - Recommended for production use
@@ -177,13 +185,13 @@ const result: AnalyzeUserOutput = await analyzeUser({
177
185
  ```typescript
178
186
  // Auto-detection: all UUIDs encoded
179
187
  const wrapped1 = wrapBamlFunction(fn, {
180
- config: { inputFormat: 'UUID', outputFormat: 'SafeNumeric' },
188
+ config: { inputFormat: "UUID", outputFormat: "SafeNumeric" },
181
189
  });
182
190
 
183
191
  // Explicit: only user_id and item IDs encoded
184
192
  const wrapped2 = wrapBamlFunction(fn, {
185
- config: { inputFormat: 'UUID', outputFormat: 'SafeNumeric' },
186
- encodeFields: ['user_id', 'items[].id'],
193
+ config: { inputFormat: "UUID", outputFormat: "SafeNumeric" },
194
+ encodeFields: ["user_id", "items[].id"],
187
195
  });
188
196
  ```
189
197
 
package/dist/index.d.mts CHANGED
@@ -7,6 +7,28 @@ import { EncodeConfig } from 'prompt-identifiers';
7
7
  * in inputs and decode them in outputs.
8
8
  */
9
9
 
10
+ /** Debug data included in onEncode callback when debug is true */
11
+ interface EncodeDebugData {
12
+ /** Number of unique IDs encoded */
13
+ encodedCount: number;
14
+ /** Original input object before encoding */
15
+ input: unknown;
16
+ /** Encoded input object */
17
+ output: unknown;
18
+ /** Time spent encoding in milliseconds */
19
+ durationMs: number;
20
+ }
21
+ /** Debug data included in onDecode callback when debug is true */
22
+ interface DecodeDebugData {
23
+ /** Number of fields containing decoded placeholders */
24
+ decodedCount: number;
25
+ /** Raw output from LLM (encoded) */
26
+ input: unknown;
27
+ /** Decoded output with original IDs restored */
28
+ output: unknown;
29
+ /** Time spent decoding in milliseconds */
30
+ durationMs: number;
31
+ }
10
32
  /** Configuration options for the BAML wrapper */
11
33
  interface WrapBamlFunctionOptions {
12
34
  /** Encoding configuration (inputFormat and outputFormat) */
@@ -25,18 +47,26 @@ interface WrapBamlFunctionOptions {
25
47
  * encodeFields: ['user_id', 'items[].id', 'metadata.owner_id']
26
48
  */
27
49
  encodeFields?: string[];
50
+ /**
51
+ * Enable debug mode to populate debugData in callbacks with
52
+ * input/output snapshots, counts, and timing information.
53
+ */
54
+ debug?: boolean;
28
55
  /**
29
56
  * Optional callback fired after encoding IDs in the input.
57
+ * Receives the placeholder→ID mapping. When debug is true,
58
+ * also receives debugData with input, output, counts, and timing.
30
59
  */
31
60
  onEncode?: (result: {
32
61
  mapping: Record<string, string>;
33
- encodedCount: number;
62
+ debugData?: EncodeDebugData;
34
63
  }) => void;
35
64
  /**
36
65
  * Optional callback fired after decoding IDs in the output.
66
+ * When debug is true, receives debugData with input, output, counts, and timing.
37
67
  */
38
68
  onDecode?: (result: {
39
- decodedCount: number;
69
+ debugData?: DecodeDebugData;
40
70
  }) => void;
41
71
  }
42
72
  /** A BAML function type (sync or async) */
@@ -111,4 +141,4 @@ declare function encodeObject<T>(obj: T, config: EncodeConfig, encodeFields?: st
111
141
  */
112
142
  declare function decodeObject<T>(obj: T, mapping: Record<string, string>): T;
113
143
 
114
- export { type BamlFunction, type BamlStreamingFunction, type WrapBamlFunctionOptions, decodeObject, encodeObject, wrapBamlFunction, wrapBamlStreamingFunction };
144
+ export { type BamlFunction, type BamlStreamingFunction, type DecodeDebugData, type EncodeDebugData, type WrapBamlFunctionOptions, decodeObject, encodeObject, wrapBamlFunction, wrapBamlStreamingFunction };
package/dist/index.d.ts CHANGED
@@ -7,6 +7,28 @@ import { EncodeConfig } from 'prompt-identifiers';
7
7
  * in inputs and decode them in outputs.
8
8
  */
9
9
 
10
+ /** Debug data included in onEncode callback when debug is true */
11
+ interface EncodeDebugData {
12
+ /** Number of unique IDs encoded */
13
+ encodedCount: number;
14
+ /** Original input object before encoding */
15
+ input: unknown;
16
+ /** Encoded input object */
17
+ output: unknown;
18
+ /** Time spent encoding in milliseconds */
19
+ durationMs: number;
20
+ }
21
+ /** Debug data included in onDecode callback when debug is true */
22
+ interface DecodeDebugData {
23
+ /** Number of fields containing decoded placeholders */
24
+ decodedCount: number;
25
+ /** Raw output from LLM (encoded) */
26
+ input: unknown;
27
+ /** Decoded output with original IDs restored */
28
+ output: unknown;
29
+ /** Time spent decoding in milliseconds */
30
+ durationMs: number;
31
+ }
10
32
  /** Configuration options for the BAML wrapper */
11
33
  interface WrapBamlFunctionOptions {
12
34
  /** Encoding configuration (inputFormat and outputFormat) */
@@ -25,18 +47,26 @@ interface WrapBamlFunctionOptions {
25
47
  * encodeFields: ['user_id', 'items[].id', 'metadata.owner_id']
26
48
  */
27
49
  encodeFields?: string[];
50
+ /**
51
+ * Enable debug mode to populate debugData in callbacks with
52
+ * input/output snapshots, counts, and timing information.
53
+ */
54
+ debug?: boolean;
28
55
  /**
29
56
  * Optional callback fired after encoding IDs in the input.
57
+ * Receives the placeholder→ID mapping. When debug is true,
58
+ * also receives debugData with input, output, counts, and timing.
30
59
  */
31
60
  onEncode?: (result: {
32
61
  mapping: Record<string, string>;
33
- encodedCount: number;
62
+ debugData?: EncodeDebugData;
34
63
  }) => void;
35
64
  /**
36
65
  * Optional callback fired after decoding IDs in the output.
66
+ * When debug is true, receives debugData with input, output, counts, and timing.
37
67
  */
38
68
  onDecode?: (result: {
39
- decodedCount: number;
69
+ debugData?: DecodeDebugData;
40
70
  }) => void;
41
71
  }
42
72
  /** A BAML function type (sync or async) */
@@ -111,4 +141,4 @@ declare function encodeObject<T>(obj: T, config: EncodeConfig, encodeFields?: st
111
141
  */
112
142
  declare function decodeObject<T>(obj: T, mapping: Record<string, string>): T;
113
143
 
114
- export { type BamlFunction, type BamlStreamingFunction, type WrapBamlFunctionOptions, decodeObject, encodeObject, wrapBamlFunction, wrapBamlStreamingFunction };
144
+ export { type BamlFunction, type BamlStreamingFunction, type DecodeDebugData, type EncodeDebugData, type WrapBamlFunctionOptions, decodeObject, encodeObject, wrapBamlFunction, wrapBamlStreamingFunction };
package/dist/index.js CHANGED
@@ -84,7 +84,7 @@ function formatPlaceholder(outputFormat, index) {
84
84
  if (outputFormat === "SafeNumeric") {
85
85
  const s = index.toString();
86
86
  const width = Math.max(3, Math.ceil(s.length / 3) * 3);
87
- return `<${s.padStart(width, "0")}>`;
87
+ return `~${s.padStart(width, "0")}~`;
88
88
  }
89
89
  if (outputFormat === "Numeric") {
90
90
  const s = index.toString();
@@ -170,9 +170,7 @@ function deepEncode(value, ctx, path = []) {
170
170
  return encodeStringWithContext(value, ctx);
171
171
  }
172
172
  if (Array.isArray(value)) {
173
- return value.map(
174
- (item, index) => deepEncode(item, ctx, [...path, String(index)])
175
- );
173
+ return value.map((item, index) => deepEncode(item, ctx, [...path, String(index)]));
176
174
  }
177
175
  if (typeof value === "object") {
178
176
  const result = {};
@@ -207,7 +205,7 @@ function deepDecode(value, mapping, countRef) {
207
205
  return value;
208
206
  }
209
207
  function wrapBamlFunction(fn, options) {
210
- const { config, encodeFields, onEncode, onDecode } = options;
208
+ const { config, encodeFields, onEncode, onDecode, debug } = options;
211
209
  const fieldPaths = encodeFields ? encodeFields.map(parseFieldPath) : null;
212
210
  return async (input) => {
213
211
  const ctx = {
@@ -217,20 +215,40 @@ function wrapBamlFunction(fn, options) {
217
215
  mapping: {},
218
216
  nextIndex: 0
219
217
  };
218
+ const startEncode = debug ? performance.now() : 0;
220
219
  const encodedInput = deepEncode(input, ctx);
220
+ const encodeDurationMs = debug ? performance.now() - startEncode : 0;
221
221
  onEncode?.({
222
222
  mapping: ctx.mapping,
223
- encodedCount: Object.keys(ctx.mapping).length
223
+ ...debug && {
224
+ debugData: {
225
+ encodedCount: Object.keys(ctx.mapping).length,
226
+ input,
227
+ output: encodedInput,
228
+ durationMs: encodeDurationMs
229
+ }
230
+ }
224
231
  });
225
232
  const output = await fn(encodedInput);
226
233
  const countRef = { count: 0 };
234
+ const startDecode = debug ? performance.now() : 0;
227
235
  const decodedOutput = deepDecode(output, ctx.mapping, countRef);
228
- onDecode?.({ decodedCount: countRef.count });
236
+ const decodeDurationMs = debug ? performance.now() - startDecode : 0;
237
+ onDecode?.({
238
+ ...debug && {
239
+ debugData: {
240
+ decodedCount: countRef.count,
241
+ input: output,
242
+ output: decodedOutput,
243
+ durationMs: decodeDurationMs
244
+ }
245
+ }
246
+ });
229
247
  return decodedOutput;
230
248
  };
231
249
  }
232
250
  function wrapBamlStreamingFunction(fn, options) {
233
- const { config, encodeFields, onEncode, onDecode } = options;
251
+ const { config, encodeFields, onEncode, onDecode, debug } = options;
234
252
  const fieldPaths = encodeFields ? encodeFields.map(parseFieldPath) : null;
235
253
  return async function* (input) {
236
254
  const ctx = {
@@ -240,20 +258,40 @@ function wrapBamlStreamingFunction(fn, options) {
240
258
  mapping: {},
241
259
  nextIndex: 0
242
260
  };
261
+ const startEncode = debug ? performance.now() : 0;
243
262
  const encodedInput = deepEncode(input, ctx);
263
+ const encodeDurationMs = debug ? performance.now() - startEncode : 0;
244
264
  onEncode?.({
245
265
  mapping: ctx.mapping,
246
- encodedCount: Object.keys(ctx.mapping).length
266
+ ...debug && {
267
+ debugData: {
268
+ encodedCount: Object.keys(ctx.mapping).length,
269
+ input,
270
+ output: encodedInput,
271
+ durationMs: encodeDurationMs
272
+ }
273
+ }
247
274
  });
248
275
  const generator = fn(encodedInput);
249
276
  let totalDecoded = 0;
277
+ const startDecode = debug ? performance.now() : 0;
250
278
  while (true) {
251
279
  const { value, done } = await generator.next();
252
280
  if (done) {
253
281
  const countRef2 = { count: 0 };
254
282
  const decodedValue2 = deepDecode(value, ctx.mapping, countRef2);
255
283
  totalDecoded += countRef2.count;
256
- onDecode?.({ decodedCount: totalDecoded });
284
+ const decodeDurationMs = debug ? performance.now() - startDecode : 0;
285
+ onDecode?.({
286
+ ...debug && {
287
+ debugData: {
288
+ decodedCount: totalDecoded,
289
+ input: value,
290
+ output: decodedValue2,
291
+ durationMs: decodeDurationMs
292
+ }
293
+ }
294
+ });
257
295
  return decodedValue2;
258
296
  }
259
297
  const countRef = { count: 0 };
package/dist/index.mjs CHANGED
@@ -57,7 +57,7 @@ function formatPlaceholder(outputFormat, index) {
57
57
  if (outputFormat === "SafeNumeric") {
58
58
  const s = index.toString();
59
59
  const width = Math.max(3, Math.ceil(s.length / 3) * 3);
60
- return `<${s.padStart(width, "0")}>`;
60
+ return `~${s.padStart(width, "0")}~`;
61
61
  }
62
62
  if (outputFormat === "Numeric") {
63
63
  const s = index.toString();
@@ -143,9 +143,7 @@ function deepEncode(value, ctx, path = []) {
143
143
  return encodeStringWithContext(value, ctx);
144
144
  }
145
145
  if (Array.isArray(value)) {
146
- return value.map(
147
- (item, index) => deepEncode(item, ctx, [...path, String(index)])
148
- );
146
+ return value.map((item, index) => deepEncode(item, ctx, [...path, String(index)]));
149
147
  }
150
148
  if (typeof value === "object") {
151
149
  const result = {};
@@ -180,7 +178,7 @@ function deepDecode(value, mapping, countRef) {
180
178
  return value;
181
179
  }
182
180
  function wrapBamlFunction(fn, options) {
183
- const { config, encodeFields, onEncode, onDecode } = options;
181
+ const { config, encodeFields, onEncode, onDecode, debug } = options;
184
182
  const fieldPaths = encodeFields ? encodeFields.map(parseFieldPath) : null;
185
183
  return async (input) => {
186
184
  const ctx = {
@@ -190,20 +188,40 @@ function wrapBamlFunction(fn, options) {
190
188
  mapping: {},
191
189
  nextIndex: 0
192
190
  };
191
+ const startEncode = debug ? performance.now() : 0;
193
192
  const encodedInput = deepEncode(input, ctx);
193
+ const encodeDurationMs = debug ? performance.now() - startEncode : 0;
194
194
  onEncode?.({
195
195
  mapping: ctx.mapping,
196
- encodedCount: Object.keys(ctx.mapping).length
196
+ ...debug && {
197
+ debugData: {
198
+ encodedCount: Object.keys(ctx.mapping).length,
199
+ input,
200
+ output: encodedInput,
201
+ durationMs: encodeDurationMs
202
+ }
203
+ }
197
204
  });
198
205
  const output = await fn(encodedInput);
199
206
  const countRef = { count: 0 };
207
+ const startDecode = debug ? performance.now() : 0;
200
208
  const decodedOutput = deepDecode(output, ctx.mapping, countRef);
201
- onDecode?.({ decodedCount: countRef.count });
209
+ const decodeDurationMs = debug ? performance.now() - startDecode : 0;
210
+ onDecode?.({
211
+ ...debug && {
212
+ debugData: {
213
+ decodedCount: countRef.count,
214
+ input: output,
215
+ output: decodedOutput,
216
+ durationMs: decodeDurationMs
217
+ }
218
+ }
219
+ });
202
220
  return decodedOutput;
203
221
  };
204
222
  }
205
223
  function wrapBamlStreamingFunction(fn, options) {
206
- const { config, encodeFields, onEncode, onDecode } = options;
224
+ const { config, encodeFields, onEncode, onDecode, debug } = options;
207
225
  const fieldPaths = encodeFields ? encodeFields.map(parseFieldPath) : null;
208
226
  return async function* (input) {
209
227
  const ctx = {
@@ -213,20 +231,40 @@ function wrapBamlStreamingFunction(fn, options) {
213
231
  mapping: {},
214
232
  nextIndex: 0
215
233
  };
234
+ const startEncode = debug ? performance.now() : 0;
216
235
  const encodedInput = deepEncode(input, ctx);
236
+ const encodeDurationMs = debug ? performance.now() - startEncode : 0;
217
237
  onEncode?.({
218
238
  mapping: ctx.mapping,
219
- encodedCount: Object.keys(ctx.mapping).length
239
+ ...debug && {
240
+ debugData: {
241
+ encodedCount: Object.keys(ctx.mapping).length,
242
+ input,
243
+ output: encodedInput,
244
+ durationMs: encodeDurationMs
245
+ }
246
+ }
220
247
  });
221
248
  const generator = fn(encodedInput);
222
249
  let totalDecoded = 0;
250
+ const startDecode = debug ? performance.now() : 0;
223
251
  while (true) {
224
252
  const { value, done } = await generator.next();
225
253
  if (done) {
226
254
  const countRef2 = { count: 0 };
227
255
  const decodedValue2 = deepDecode(value, ctx.mapping, countRef2);
228
256
  totalDecoded += countRef2.count;
229
- onDecode?.({ decodedCount: totalDecoded });
257
+ const decodeDurationMs = debug ? performance.now() - startDecode : 0;
258
+ onDecode?.({
259
+ ...debug && {
260
+ debugData: {
261
+ decodedCount: totalDecoded,
262
+ input: value,
263
+ output: decodedValue2,
264
+ durationMs: decodeDurationMs
265
+ }
266
+ }
267
+ });
230
268
  return decodedValue2;
231
269
  }
232
270
  const countRef = { count: 0 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prompt-identifiers-baml",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "BAML integration for prompt-identifiers. Efficient ID compression for token optimization.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -54,7 +54,7 @@
54
54
  "ts-jest": "^29.0.0",
55
55
  "tsup": "^8.5.1",
56
56
  "typescript": "^5.0.0",
57
- "prompt-identifiers": "0.1.0"
57
+ "prompt-identifiers": "0.1.1"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",