langfun 0.0.2.dev20240425__py3-none-any.whl → 0.0.2.dev20240428__py3-none-any.whl

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.
langfun/core/eval/base.py CHANGED
@@ -540,7 +540,7 @@ class Evaluable(lf.Component):
540
540
  f'<div style="color: {text_color}; white-space: pre-wrap;'
541
541
  'padding: 10px; border: 1px solid; margin-top: 10px">'
542
542
  )
543
- s.write(m.text)
543
+ s.write(m.get('formatted_text', m.text))
544
544
  if m.result is not None:
545
545
  s.write(
546
546
  '<div style="color: magenta; white-space: pre-wrap;'
langfun/core/langfunc.py CHANGED
@@ -261,7 +261,6 @@ class LangFunc(
261
261
  if lm_input is None:
262
262
  lm_input = self.render(**kwargs)
263
263
 
264
- lm_input.tag(message_lib.Message.TAG_LM_INPUT)
265
264
  if skip_lm:
266
265
  return lm_input
267
266
 
@@ -270,10 +269,6 @@ class LangFunc(
270
269
  # Send rendered text to LM.
271
270
  lm_output = self.lm(lm_input, cache_seed=cache_seed)
272
271
 
273
- # Track the input as the source of the output.
274
- lm_output.source = lm_input
275
- lm_output.tag(message_lib.Message.TAG_LM_RESPONSE)
276
-
277
272
  # Transform the output message.
278
273
  lm_output = self.transform_output(lm_output)
279
274
  lm_output.tag(message_lib.Message.TAG_LM_OUTPUT)
@@ -346,9 +346,42 @@ class LanguageModel(component.Component):
346
346
 
347
347
  with component.context(override_attrs=True, **kwargs):
348
348
  if self.cache is None:
349
- return self._sample(prompts)
349
+ results = self._sample(prompts)
350
350
  else:
351
- return self._sample_with_cache_lookup(prompts, cache_seed)
351
+ results = self._sample_with_cache_lookup(prompts, cache_seed)
352
+
353
+ for prompt, result in zip(prompts, results):
354
+
355
+ # Tag LM input.
356
+ prompt.tag(message_lib.Message.TAG_LM_INPUT)
357
+
358
+ for sample in result.samples:
359
+ # Update metadata for response message.
360
+
361
+ response = sample.response
362
+ response.metadata.score = sample.score
363
+ response.metadata.logprobs = sample.logprobs
364
+
365
+ # NOTE(daiyip): Current usage is computed at per-result level,
366
+ # which is accurate when n=1. For n > 1, we average the usage across
367
+ # multiple samples.
368
+ usage = result.usage
369
+ if len(result.samples) == 1 or usage is None:
370
+ response.metadata.usage = usage
371
+ else:
372
+ n = len(result.samples)
373
+ response.metadata.usage = LMSamplingUsage(
374
+ prompt_tokens=usage.prompt_tokens // n,
375
+ completion_tokens=usage.completion_tokens // n,
376
+ total_tokens=usage.total_tokens // n,
377
+ )
378
+
379
+ # Track the prompt for corresponding response.
380
+ response.source = prompt
381
+
382
+ # Tag LM response.
383
+ response.tag(message_lib.Message.TAG_LM_RESPONSE)
384
+ return results
352
385
 
353
386
  def _sample_with_cache_lookup(
354
387
  self, prompts: list[str | message_lib.Message], cache_seed: int
@@ -436,13 +469,8 @@ class LanguageModel(component.Component):
436
469
  result = self.sample(
437
470
  [prompt], sampling_options=sampling_options, cache_seed=cache_seed
438
471
  )[0]
439
- response = result.samples[0].response
440
- logprobs = result.samples[0].logprobs
441
- response.set('score', result.samples[0].score)
442
- response.metadata.logprobs = logprobs
443
- response.metadata.usage = result.usage
444
-
445
472
  elapse = time.time() - request_start
473
+ response = result.samples[0].response
446
474
  self._debug(prompt, response, call_counter, result.usage, elapse)
447
475
  return response
448
476
 
@@ -494,7 +522,9 @@ class LanguageModel(component.Component):
494
522
  title_suffix = console.colored(f' ({usage.prompt_tokens} tokens)', 'red')
495
523
 
496
524
  console.write(
497
- prompt,
525
+ # We use metadata 'formatted_text' for scenarios where the prompt text
526
+ # is formatted by the LM.
527
+ prompt.get('formatted_text', prompt.text),
498
528
  title=f'\n[{call_counter}] PROMPT SENT TO LM{title_suffix}:',
499
529
  color='green',
500
530
  )
@@ -111,11 +111,35 @@ class LanguageModelTest(unittest.TestCase):
111
111
  lm.sample(prompts=['foo', 'bar']),
112
112
  [
113
113
  lm_lib.LMSamplingResult(
114
- [lm_lib.LMSample('foo', score=-1.0)],
114
+ [
115
+ lm_lib.LMSample(
116
+ message_lib.AIMessage(
117
+ 'foo',
118
+ score=-1.0,
119
+ logprobs=None,
120
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
121
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
122
+ ),
123
+ score=-1.0,
124
+ logprobs=None,
125
+ )
126
+ ],
115
127
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
116
128
  ),
117
129
  lm_lib.LMSamplingResult(
118
- [lm_lib.LMSample('bar', score=-1.0)],
130
+ [
131
+ lm_lib.LMSample(
132
+ message_lib.AIMessage(
133
+ 'bar',
134
+ score=-1.0,
135
+ logprobs=None,
136
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
137
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
138
+ ),
139
+ score=-1.0,
140
+ logprobs=None,
141
+ )
142
+ ],
119
143
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
120
144
  ),
121
145
  ],
@@ -128,41 +152,119 @@ class LanguageModelTest(unittest.TestCase):
128
152
  ),
129
153
  [
130
154
  lm_lib.LMSamplingResult(
131
- [lm_lib.LMSample('foo' * 2, score=0.5)],
155
+ [
156
+ lm_lib.LMSample(
157
+ message_lib.AIMessage(
158
+ 'foo' * 2,
159
+ score=0.5,
160
+ logprobs=None,
161
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
162
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
163
+ ),
164
+ score=0.5,
165
+ logprobs=None,
166
+ ),
167
+ ],
132
168
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
133
169
  ),
134
170
  lm_lib.LMSamplingResult(
135
- [lm_lib.LMSample('bar' * 2, score=0.5)],
136
- usage=lm_lib.LMSamplingUsage(100, 100, 200),
171
+ [
172
+ lm_lib.LMSample(
173
+ message_lib.AIMessage(
174
+ 'bar' * 2,
175
+ score=0.5,
176
+ logprobs=None,
177
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
178
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
179
+ ),
180
+ score=0.5,
181
+ logprobs=None,
182
+ ),
183
+ ],
184
+ usage=lm_lib.LMSamplingUsage(
185
+ prompt_tokens=100, completion_tokens=100, total_tokens=200
186
+ ),
137
187
  ),
138
- ],
188
+ ]
139
189
  )
140
190
  # Test override individual flags within sampling_options.
141
191
  self.assertEqual(
142
192
  lm.sample(prompts=['foo', 'bar'], temperature=1.0),
143
193
  [
144
194
  lm_lib.LMSamplingResult(
145
- [lm_lib.LMSample('foo', score=1.0)],
195
+ [
196
+ lm_lib.LMSample(
197
+ message_lib.AIMessage(
198
+ 'foo',
199
+ score=1.0,
200
+ logprobs=None,
201
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
202
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
203
+ ),
204
+ score=1.0,
205
+ logprobs=None,
206
+ ),
207
+ ],
146
208
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
147
209
  ),
148
210
  lm_lib.LMSamplingResult(
149
- [lm_lib.LMSample('bar', score=1.0)],
150
- usage=lm_lib.LMSamplingUsage(100, 100, 200),
211
+ [
212
+ lm_lib.LMSample(
213
+ message_lib.AIMessage(
214
+ 'bar',
215
+ score=1.0,
216
+ logprobs=None,
217
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
218
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
219
+ ),
220
+ score=1.0,
221
+ logprobs=None,
222
+ ),
223
+ ],
224
+ usage=lm_lib.LMSamplingUsage(
225
+ prompt_tokens=100, completion_tokens=100, total_tokens=200
226
+ ),
151
227
  ),
152
- ],
228
+ ]
153
229
  )
154
230
  self.assertEqual(
155
231
  lm.sample(prompts=['foo', 'bar'], top_k=2, temperature=0.7),
156
232
  [
157
233
  lm_lib.LMSamplingResult(
158
- [lm_lib.LMSample('foo' * 2, score=0.7)],
234
+ [
235
+ lm_lib.LMSample(
236
+ message_lib.AIMessage(
237
+ 'foo' * 2,
238
+ score=0.7,
239
+ logprobs=None,
240
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
241
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
242
+ ),
243
+ score=0.7,
244
+ logprobs=None,
245
+ ),
246
+ ],
159
247
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
160
248
  ),
161
249
  lm_lib.LMSamplingResult(
162
- [lm_lib.LMSample('bar' * 2, score=0.7)],
163
- usage=lm_lib.LMSamplingUsage(100, 100, 200),
250
+ [
251
+ lm_lib.LMSample(
252
+ message_lib.AIMessage(
253
+ 'bar' * 2,
254
+ score=0.7,
255
+ logprobs=None,
256
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
257
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
258
+ ),
259
+ score=0.7,
260
+ logprobs=None,
261
+ ),
262
+ ],
263
+ usage=lm_lib.LMSamplingUsage(
264
+ prompt_tokens=100, completion_tokens=100, total_tokens=200
265
+ ),
164
266
  ),
165
- ],
267
+ ]
166
268
  )
167
269
 
168
270
  def test_call(self):
@@ -189,7 +291,16 @@ class LanguageModelTest(unittest.TestCase):
189
291
  lm_lib.LMSamplingResult(
190
292
  [
191
293
  lm_lib.LMSample(
192
- message_lib.AIMessage('foo', cache_seed=0), score=-1.0
294
+ message_lib.AIMessage(
295
+ 'foo',
296
+ cache_seed=0,
297
+ score=-1.0,
298
+ logprobs=None,
299
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
300
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
301
+ ),
302
+ score=-1.0,
303
+ logprobs=None,
193
304
  )
194
305
  ],
195
306
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
@@ -197,7 +308,16 @@ class LanguageModelTest(unittest.TestCase):
197
308
  lm_lib.LMSamplingResult(
198
309
  [
199
310
  lm_lib.LMSample(
200
- message_lib.AIMessage('bar', cache_seed=0), score=-1.0
311
+ message_lib.AIMessage(
312
+ 'bar',
313
+ cache_seed=0,
314
+ score=-1.0,
315
+ logprobs=None,
316
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
317
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
318
+ ),
319
+ score=-1.0,
320
+ logprobs=None,
201
321
  )
202
322
  ],
203
323
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
@@ -225,7 +345,16 @@ class LanguageModelTest(unittest.TestCase):
225
345
  lm_lib.LMSamplingResult(
226
346
  [
227
347
  lm_lib.LMSample(
228
- message_lib.AIMessage('foo', cache_seed=0), score=1.0
348
+ message_lib.AIMessage(
349
+ 'foo',
350
+ cache_seed=0,
351
+ score=1.0,
352
+ logprobs=None,
353
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
354
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
355
+ ),
356
+ score=1.0,
357
+ logprobs=None,
229
358
  )
230
359
  ],
231
360
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
@@ -233,7 +362,16 @@ class LanguageModelTest(unittest.TestCase):
233
362
  lm_lib.LMSamplingResult(
234
363
  [
235
364
  lm_lib.LMSample(
236
- message_lib.AIMessage('baz', cache_seed=0), score=1.0
365
+ message_lib.AIMessage(
366
+ 'baz',
367
+ cache_seed=0,
368
+ score=1.0,
369
+ logprobs=None,
370
+ usage=lm_lib.LMSamplingUsage(100, 100, 200),
371
+ tags=[message_lib.Message.TAG_LM_RESPONSE],
372
+ ),
373
+ score=1.0,
374
+ logprobs=None,
237
375
  )
238
376
  ],
239
377
  usage=lm_lib.LMSamplingUsage(100, 100, 200),
@@ -28,7 +28,19 @@ class EchoTest(unittest.TestCase):
28
28
  lm.sample(['hi']),
29
29
  [
30
30
  lf.LMSamplingResult(
31
- [lf.LMSample('hi', 1.0)],
31
+ [
32
+ lf.LMSample(
33
+ lf.AIMessage(
34
+ 'hi',
35
+ score=1.0,
36
+ logprobs=None,
37
+ usage=lf.LMSamplingUsage(2, 2, 4),
38
+ tags=[lf.Message.TAG_LM_RESPONSE],
39
+ ),
40
+ score=1.0,
41
+ logprobs=None,
42
+ )
43
+ ],
32
44
  lf.LMSamplingUsage(2, 2, 4))
33
45
  ]
34
46
  )
@@ -60,7 +72,19 @@ class StaticResponseTest(unittest.TestCase):
60
72
  lm.sample(['hi']),
61
73
  [
62
74
  lf.LMSamplingResult(
63
- [lf.LMSample(canned_response, 1.0)],
75
+ [
76
+ lf.LMSample(
77
+ lf.AIMessage(
78
+ canned_response,
79
+ score=1.0,
80
+ logprobs=None,
81
+ usage=lf.LMSamplingUsage(2, 38, 40),
82
+ tags=[lf.Message.TAG_LM_RESPONSE],
83
+ ),
84
+ score=1.0,
85
+ logprobs=None,
86
+ )
87
+ ],
64
88
  usage=lf.LMSamplingUsage(2, 38, 40)
65
89
  )
66
90
  ],
@@ -69,7 +93,19 @@ class StaticResponseTest(unittest.TestCase):
69
93
  lm.sample(['Tell me a joke.']),
70
94
  [
71
95
  lf.LMSamplingResult(
72
- [lf.LMSample(canned_response, 1.0)],
96
+ [
97
+ lf.LMSample(
98
+ lf.AIMessage(
99
+ canned_response,
100
+ score=1.0,
101
+ logprobs=None,
102
+ usage=lf.LMSamplingUsage(15, 38, 53),
103
+ tags=[lf.Message.TAG_LM_RESPONSE],
104
+ ),
105
+ score=1.0,
106
+ logprobs=None,
107
+ )
108
+ ],
73
109
  usage=lf.LMSamplingUsage(15, 38, 53)
74
110
  )
75
111
  ],
@@ -101,11 +137,35 @@ class StaticMappingTest(unittest.TestCase):
101
137
  lm.sample(['Hi', 'How are you?']),
102
138
  [
103
139
  lf.LMSamplingResult(
104
- [lf.LMSample('Hello', 1.0)],
140
+ [
141
+ lf.LMSample(
142
+ lf.AIMessage(
143
+ 'Hello',
144
+ score=1.0,
145
+ logprobs=None,
146
+ usage=lf.LMSamplingUsage(2, 5, 7),
147
+ tags=[lf.Message.TAG_LM_RESPONSE],
148
+ ),
149
+ score=1.0,
150
+ logprobs=None,
151
+ )
152
+ ],
105
153
  usage=lf.LMSamplingUsage(2, 5, 7)
106
154
  ),
107
155
  lf.LMSamplingResult(
108
- [lf.LMSample('I am fine, how about you?', 1.0)],
156
+ [
157
+ lf.LMSample(
158
+ lf.AIMessage(
159
+ 'I am fine, how about you?',
160
+ score=1.0,
161
+ logprobs=None,
162
+ usage=lf.LMSamplingUsage(12, 25, 37),
163
+ tags=[lf.Message.TAG_LM_RESPONSE],
164
+ ),
165
+ score=1.0,
166
+ logprobs=None,
167
+ )
168
+ ],
109
169
  usage=lf.LMSamplingUsage(12, 25, 37)
110
170
  )
111
171
  ]
@@ -126,11 +186,35 @@ class StaticSequenceTest(unittest.TestCase):
126
186
  lm.sample(['Hi', 'How are you?']),
127
187
  [
128
188
  lf.LMSamplingResult(
129
- [lf.LMSample('Hello', 1.0)],
189
+ [
190
+ lf.LMSample(
191
+ lf.AIMessage(
192
+ 'Hello',
193
+ score=1.0,
194
+ logprobs=None,
195
+ usage=lf.LMSamplingUsage(2, 5, 7),
196
+ tags=[lf.Message.TAG_LM_RESPONSE],
197
+ ),
198
+ score=1.0,
199
+ logprobs=None,
200
+ )
201
+ ],
130
202
  usage=lf.LMSamplingUsage(2, 5, 7)
131
203
  ),
132
204
  lf.LMSamplingResult(
133
- [lf.LMSample('I am fine, how about you?', 1.0)],
205
+ [
206
+ lf.LMSample(
207
+ lf.AIMessage(
208
+ 'I am fine, how about you?',
209
+ score=1.0,
210
+ logprobs=None,
211
+ usage=lf.LMSamplingUsage(12, 25, 37),
212
+ tags=[lf.Message.TAG_LM_RESPONSE],
213
+ ),
214
+ score=1.0,
215
+ logprobs=None,
216
+ )
217
+ ],
134
218
  usage=lf.LMSamplingUsage(12, 25, 37)
135
219
  )
136
220
  ]
@@ -184,23 +184,96 @@ class OpenAITest(unittest.TestCase):
184
184
  results[0],
185
185
  lf.LMSamplingResult(
186
186
  [
187
- lf.LMSample('Sample 0 for prompt 0.', score=0.0),
188
- lf.LMSample('Sample 1 for prompt 0.', score=0.1),
189
- lf.LMSample('Sample 2 for prompt 0.', score=0.2),
187
+ lf.LMSample(
188
+ lf.AIMessage(
189
+ 'Sample 0 for prompt 0.',
190
+ score=0.0,
191
+ logprobs=None,
192
+ usage=lf.LMSamplingUsage(
193
+ prompt_tokens=33,
194
+ completion_tokens=33,
195
+ total_tokens=66
196
+ ),
197
+ tags=[lf.Message.TAG_LM_RESPONSE],
198
+ ),
199
+ score=0.0,
200
+ logprobs=None,
201
+ ),
202
+ lf.LMSample(
203
+ lf.AIMessage(
204
+ 'Sample 1 for prompt 0.',
205
+ score=0.1,
206
+ logprobs=None,
207
+ usage=lf.LMSamplingUsage(
208
+ prompt_tokens=33,
209
+ completion_tokens=33,
210
+ total_tokens=66
211
+ ),
212
+ tags=[lf.Message.TAG_LM_RESPONSE],
213
+ ),
214
+ score=0.1,
215
+ logprobs=None,
216
+ ),
217
+ lf.LMSample(
218
+ lf.AIMessage(
219
+ 'Sample 2 for prompt 0.',
220
+ score=0.2,
221
+ logprobs=None,
222
+ usage=lf.LMSamplingUsage(
223
+ prompt_tokens=33,
224
+ completion_tokens=33,
225
+ total_tokens=66
226
+ ),
227
+ tags=[lf.Message.TAG_LM_RESPONSE],
228
+ ),
229
+ score=0.2,
230
+ logprobs=None,
231
+ ),
190
232
  ],
191
233
  usage=lf.LMSamplingUsage(
192
234
  prompt_tokens=100, completion_tokens=100, total_tokens=200
193
235
  ),
194
236
  ),
195
237
  )
196
-
197
238
  self.assertEqual(
198
239
  results[1],
199
- lf.LMSamplingResult([
200
- lf.LMSample('Sample 0 for prompt 1.', score=0.0),
201
- lf.LMSample('Sample 1 for prompt 1.', score=0.1),
202
- lf.LMSample('Sample 2 for prompt 1.', score=0.2),
203
- ]),
240
+ lf.LMSamplingResult(
241
+ [
242
+ lf.LMSample(
243
+ lf.AIMessage(
244
+ 'Sample 0 for prompt 1.',
245
+ score=0.0,
246
+ logprobs=None,
247
+ usage=None,
248
+ tags=[lf.Message.TAG_LM_RESPONSE],
249
+ ),
250
+ score=0.0,
251
+ logprobs=None,
252
+ ),
253
+ lf.LMSample(
254
+ lf.AIMessage(
255
+ 'Sample 1 for prompt 1.',
256
+ score=0.1,
257
+ logprobs=None,
258
+ usage=None,
259
+ tags=[lf.Message.TAG_LM_RESPONSE],
260
+ ),
261
+ score=0.1,
262
+ logprobs=None,
263
+ ),
264
+ lf.LMSample(
265
+ lf.AIMessage(
266
+ 'Sample 2 for prompt 1.',
267
+ score=0.2,
268
+ logprobs=None,
269
+ usage=None,
270
+ tags=[lf.Message.TAG_LM_RESPONSE],
271
+ ),
272
+ score=0.2,
273
+ logprobs=None,
274
+ ),
275
+ ],
276
+ ),
204
277
  )
205
278
 
206
279
  def test_sample_chat_completion(self):
@@ -216,9 +289,51 @@ class OpenAITest(unittest.TestCase):
216
289
  results[0],
217
290
  lf.LMSamplingResult(
218
291
  [
219
- lf.LMSample('Sample 0 for message.', score=0.0),
220
- lf.LMSample('Sample 1 for message.', score=0.0),
221
- lf.LMSample('Sample 2 for message.', score=0.0),
292
+ lf.LMSample(
293
+ lf.AIMessage(
294
+ 'Sample 0 for message.',
295
+ score=0.0,
296
+ logprobs=None,
297
+ usage=lf.LMSamplingUsage(
298
+ prompt_tokens=33,
299
+ completion_tokens=33,
300
+ total_tokens=66
301
+ ),
302
+ tags=[lf.Message.TAG_LM_RESPONSE],
303
+ ),
304
+ score=0.0,
305
+ logprobs=None,
306
+ ),
307
+ lf.LMSample(
308
+ lf.AIMessage(
309
+ 'Sample 1 for message.',
310
+ score=0.0,
311
+ logprobs=None,
312
+ usage=lf.LMSamplingUsage(
313
+ prompt_tokens=33,
314
+ completion_tokens=33,
315
+ total_tokens=66
316
+ ),
317
+ tags=[lf.Message.TAG_LM_RESPONSE],
318
+ ),
319
+ score=0.0,
320
+ logprobs=None,
321
+ ),
322
+ lf.LMSample(
323
+ lf.AIMessage(
324
+ 'Sample 2 for message.',
325
+ score=0.0,
326
+ logprobs=None,
327
+ usage=lf.LMSamplingUsage(
328
+ prompt_tokens=33,
329
+ completion_tokens=33,
330
+ total_tokens=66
331
+ ),
332
+ tags=[lf.Message.TAG_LM_RESPONSE],
333
+ ),
334
+ score=0.0,
335
+ logprobs=None,
336
+ ),
222
337
  ],
223
338
  usage=lf.LMSamplingUsage(
224
339
  prompt_tokens=100, completion_tokens=100, total_tokens=200
@@ -229,9 +344,51 @@ class OpenAITest(unittest.TestCase):
229
344
  results[1],
230
345
  lf.LMSamplingResult(
231
346
  [
232
- lf.LMSample('Sample 0 for message.', score=0.0),
233
- lf.LMSample('Sample 1 for message.', score=0.0),
234
- lf.LMSample('Sample 2 for message.', score=0.0),
347
+ lf.LMSample(
348
+ lf.AIMessage(
349
+ 'Sample 0 for message.',
350
+ score=0.0,
351
+ logprobs=None,
352
+ usage=lf.LMSamplingUsage(
353
+ prompt_tokens=33,
354
+ completion_tokens=33,
355
+ total_tokens=66
356
+ ),
357
+ tags=[lf.Message.TAG_LM_RESPONSE],
358
+ ),
359
+ score=0.0,
360
+ logprobs=None,
361
+ ),
362
+ lf.LMSample(
363
+ lf.AIMessage(
364
+ 'Sample 1 for message.',
365
+ score=0.0,
366
+ logprobs=None,
367
+ usage=lf.LMSamplingUsage(
368
+ prompt_tokens=33,
369
+ completion_tokens=33,
370
+ total_tokens=66
371
+ ),
372
+ tags=[lf.Message.TAG_LM_RESPONSE],
373
+ ),
374
+ score=0.0,
375
+ logprobs=None,
376
+ ),
377
+ lf.LMSample(
378
+ lf.AIMessage(
379
+ 'Sample 2 for message.',
380
+ score=0.0,
381
+ logprobs=None,
382
+ usage=lf.LMSamplingUsage(
383
+ prompt_tokens=33,
384
+ completion_tokens=33,
385
+ total_tokens=66
386
+ ),
387
+ tags=[lf.Message.TAG_LM_RESPONSE],
388
+ ),
389
+ score=0.0,
390
+ logprobs=None,
391
+ ),
235
392
  ],
236
393
  usage=lf.LMSamplingUsage(
237
394
  prompt_tokens=100, completion_tokens=100, total_tokens=200
@@ -251,8 +408,36 @@ class OpenAITest(unittest.TestCase):
251
408
  results[0],
252
409
  lf.LMSamplingResult(
253
410
  [
254
- lf.LMSample('Sample 0 for prompt 0.', score=0.0),
255
- lf.LMSample('Sample 1 for prompt 0.', score=0.1),
411
+ lf.LMSample(
412
+ lf.AIMessage(
413
+ 'Sample 0 for prompt 0.',
414
+ score=0.0,
415
+ logprobs=None,
416
+ usage=lf.LMSamplingUsage(
417
+ prompt_tokens=50,
418
+ completion_tokens=50,
419
+ total_tokens=100,
420
+ ),
421
+ tags=[lf.Message.TAG_LM_RESPONSE],
422
+ ),
423
+ score=0.0,
424
+ logprobs=None,
425
+ ),
426
+ lf.LMSample(
427
+ lf.AIMessage(
428
+ 'Sample 1 for prompt 0.',
429
+ score=0.1,
430
+ logprobs=None,
431
+ usage=lf.LMSamplingUsage(
432
+ prompt_tokens=50,
433
+ completion_tokens=50,
434
+ total_tokens=100,
435
+ ),
436
+ tags=[lf.Message.TAG_LM_RESPONSE],
437
+ ),
438
+ score=0.1,
439
+ logprobs=None,
440
+ ),
256
441
  ],
257
442
  usage=lf.LMSamplingUsage(
258
443
  prompt_tokens=100, completion_tokens=100, total_tokens=200
@@ -176,8 +176,11 @@ def query(
176
176
  returning the structured `message.result`.
177
177
  skip_lm: If True, returns the rendered prompt as a UserMessage object.
178
178
  otherwise return the LLM response based on the rendered prompt.
179
- **kwargs: Keyword arguments passed to the
180
- `lf.structured.NaturalLanguageToStructureed` transform.
179
+ **kwargs: Keyword arguments passed to render the prompt or configure the
180
+ `lf.structured.Mapping` class. Notable kwargs are:
181
+ - template_str: Change the root template for query.
182
+ - preamble: Change the preamble for query.
183
+ - mapping_template: Change the template for each mapping examle.
181
184
 
182
185
  Returns:
183
186
  The result based on the schema.
@@ -201,10 +204,17 @@ def query(
201
204
  return output if returns_message else output.text
202
205
 
203
206
  # Query with structured output.
207
+ prompt_kwargs = kwargs.copy()
208
+
209
+ # NOTE(daiyip): when `template_str` is passed in, it's intended to modify the
210
+ # QueryStructure template string. Therefore, we pop out the argument for
211
+ # prompt rendering.
212
+ prompt_kwargs.pop('template_str', None)
213
+
204
214
  if isinstance(prompt, str):
205
- prompt = lf.Template(prompt, **kwargs)
215
+ prompt = lf.Template(prompt, **prompt_kwargs)
206
216
  elif isinstance(prompt, lf.Template):
207
- prompt = prompt.rebind(**kwargs)
217
+ prompt = prompt.rebind(**prompt_kwargs, raise_on_no_change=False)
208
218
 
209
219
  if isinstance(prompt, lf.Template):
210
220
  prompt = prompt.render(lm=lm)
@@ -138,6 +138,39 @@ class QueryTest(unittest.TestCase):
138
138
  ),
139
139
  )
140
140
 
141
+ def test_str_to_structure_render_custom_template(self):
142
+ lm = fake.StaticResponse('1')
143
+ self.assert_render(
144
+ 'What is {{x}} + {{y}}?',
145
+ int,
146
+ x=1,
147
+ y=2,
148
+ lm=lm.clone(),
149
+ template_str='!!{{ DEFAULT }}!!',
150
+ expected_snippet=(
151
+ '!!Please respond to the last INPUT_OBJECT with OUTPUT_OBJECT '
152
+ 'according to OUTPUT_TYPE.\n\n'
153
+ 'INPUT_OBJECT:\n 1 + 1 =\n\n'
154
+ 'OUTPUT_TYPE:\n'
155
+ ' Answer\n\n'
156
+ ' ```python\n'
157
+ ' class Answer:\n'
158
+ ' final_answer: int\n'
159
+ ' ```\n\n'
160
+ 'OUTPUT_OBJECT:\n'
161
+ ' ```python\n'
162
+ ' Answer(\n'
163
+ ' final_answer=2\n'
164
+ ' )\n'
165
+ ' ```\n\n'
166
+ 'INPUT_OBJECT:\n'
167
+ ' What is 1 + 2?\n\n'
168
+ 'OUTPUT_TYPE:\n'
169
+ ' int\n\n'
170
+ 'OUTPUT_OBJECT:!!'
171
+ ),
172
+ )
173
+
141
174
  def test_str_to_str_render(self):
142
175
  lm = fake.StaticResponse('1')
143
176
  self.assert_render(
langfun/core/template.py CHANGED
@@ -48,7 +48,12 @@ class Template(
48
48
  component.Component,
49
49
  pg.typing.CustomTyping,
50
50
  ):
51
- """Langfun string template."""
51
+ """Langfun string template.
52
+
53
+ Langfun uses jinja2 as its template engine. Pleaes check out
54
+ https://jinja.palletsprojects.com/en/3.1.x/templates/ for detailed
55
+ explanation on the template language.
56
+ """
52
57
 
53
58
  template_str: Annotated[
54
59
  str,
@@ -101,6 +106,11 @@ class Template(
101
106
  # Declare template variables as symbolic attributes.
102
107
  template_vars = Template.resolve_vars(template_str)
103
108
  for var_name in template_vars:
109
+ if 'DEFAULT' == var_name:
110
+ raise ValueError(
111
+ '`{{ DEFAULT }}` cannot be used in pre-configured templates. '
112
+ f'Encountered: {template_str!r}'
113
+ )
104
114
  # NOTE(daiyip): This is to avoid warning from accessing
105
115
  # `pg.Object.schema`, which was replaced by `pg.Object.__schema__`.
106
116
  if var_name == 'schema' or not hasattr(cls, var_name):
@@ -153,7 +163,7 @@ class Template(
153
163
  # TODO(daiyip): Consider to delay template parsing upon usage.
154
164
  unassigned_vars = {}
155
165
  for k in self._variables:
156
- if not hasattr(self, k):
166
+ if k not in ('DEFAULT',) and not hasattr(self, k):
157
167
  unassigned_vars[k] = component.contextual()
158
168
  if unassigned_vars:
159
169
  self.rebind(unassigned_vars, skip_notification=True)
@@ -398,6 +408,93 @@ class Template(
398
408
  # Override __hash__ since __eq__ has changed.
399
409
  return object.__hash__(self)
400
410
 
411
+ #
412
+ # Special methods.
413
+ #
414
+
415
+ @property
416
+ def DEFAULT(self) -> 'Template':
417
+ """Referring to the default value used for this template.
418
+
419
+ This method is intended to be used in template for referring to the default
420
+ value of current template. There are two scenarios:
421
+
422
+ Scenario 1: Use instance-level template_str to override the class default.
423
+
424
+ ```
425
+ class Foo(lf.Template):
426
+ '''Foo template.
427
+
428
+ This is {{x}}.
429
+ '''
430
+
431
+ f = Foo(template_str='<h1>{{DEFAULT}}</h1>', x=1)
432
+ f.render()
433
+
434
+ >> <h1>This is 1.</h1>
435
+ ```
436
+
437
+ Scenario 2: Use an ad-hoc template to override a predefined field.
438
+
439
+ ```
440
+ class Bar(lf.Template):
441
+ '''Bar template.
442
+
443
+ {{preamble}}
444
+ {{prompt}}
445
+ '''
446
+ preamble: lf.Template = lf.Template('You are a chat bot.')
447
+ prompt: lf.Template = lf.Template('User: hi')
448
+
449
+ b = Bar(preamble=lf.Template('<h1>{{DEFAULT}}<h1>'),
450
+ prompt=lf.Template('<h2>{{DEFAULT}}</h2>')
451
+ b.render()
452
+
453
+ >> <h1>You are a chat bot.<h1>
454
+ >> <h2>User: hi</h2>
455
+ ```
456
+
457
+ Returns:
458
+ The default (pre-configured) value used for this template.
459
+ """
460
+ base_template = self.__class__.__schema__['template_str'].default_value
461
+ if base_template == pg.MISSING_VALUE:
462
+ if not self.sym_path:
463
+ raise ValueError(
464
+ f'No DEFAULT template found for {self!r}: '
465
+ 'The template neither has a default `template_str` nor is '
466
+ 'contained under another object.'
467
+ )
468
+ key = self.sym_path.key
469
+ assert self.sym_parent is not None
470
+ assigned_field = self.sym_parent.sym_attr_field(key)
471
+ container_cls = self.sym_parent.__class__
472
+
473
+ if (
474
+ assigned_field is None
475
+ or assigned_field.default_value == pg.MISSING_VALUE
476
+ ):
477
+ raise ValueError(
478
+ f'No DEFAULT template found for {self!r}: '
479
+ f'`{container_cls.__name__}.{key}` '
480
+ 'does not have a default value. '
481
+ )
482
+ base_template = assigned_field.default_value
483
+ if isinstance(base_template, Template):
484
+ base_template = base_template.template_str
485
+ if not isinstance(base_template, str):
486
+ raise ValueError(
487
+ f'No DEFAULT template found for {self!r}: The default '
488
+ f'value {base_template!r} of '
489
+ f'`{container_cls.__name__}.{key}` is not a '
490
+ '`lf.Template` object or str.'
491
+ )
492
+ t = Template(base_template)
493
+ # NOTE(daiyip): Set the parent of the newly created template to self so
494
+ # it could access all the contextual variables.
495
+ t.sym_setparent(self)
496
+ return t
497
+
401
498
 
402
499
  # Register converter from str to LangFunc, therefore we can always
403
500
  # pass strs to attributes that accept LangFunc.
@@ -312,6 +312,72 @@ class RenderTest(unittest.TestCase):
312
312
  'This is 1 and {{a}}',
313
313
  )
314
314
 
315
+ def test_render_with_default(self):
316
+
317
+ class Foo(Template):
318
+ """Foo.
319
+
320
+ This is {{x}}
321
+ """
322
+
323
+ f = Foo(template_str='!{{DEFAULT}}!', x=1)
324
+ self.assertEqual(f.DEFAULT.x, 1)
325
+ self.assertEqual(
326
+ f.render(), '!This is 1!'
327
+ )
328
+
329
+ class Bar(Template):
330
+ """Bar.
331
+
332
+ {{preamble}}
333
+ {{prompt}}
334
+ """
335
+
336
+ preamble: Template = Template('You are a chat bot.')
337
+ prompt: Template = Template('User: hi! {{name}}')
338
+
339
+ b = Bar(
340
+ preamble=Template('<h1>{{DEFAULT}}</h1>'),
341
+ prompt=Template('<h2>{{DEFAULT}}</h2>'),
342
+ name='Tom',
343
+ )
344
+ # Test variable access.
345
+ self.assertEqual(
346
+ b.render(),
347
+ inspect.cleandoc("""
348
+ <h1>You are a chat bot.</h1>
349
+ <h2>User: hi! Tom</h2>
350
+ """),
351
+ )
352
+
353
+ with self.assertRaisesRegex(ValueError, '`{{ DEFAULT }}` cannot be used'):
354
+
355
+ class Baz(Template): # pylint: disable=unused-variable
356
+ """Baz.
357
+
358
+ {{DEFAULT}}
359
+ """
360
+
361
+ with self.assertRaisesRegex(
362
+ ValueError, 'The template neither has a default `template_str` nor'
363
+ ):
364
+ Template('{{DEFAULT}}').render()
365
+
366
+ d = pg.Dict(x=Template('{{DEFAULT}}'))
367
+ with self.assertRaisesRegex(
368
+ ValueError, 'does not have a default value'
369
+ ):
370
+ _ = d.x.DEFAULT
371
+
372
+ class Tes(pg.Object):
373
+ x: str | None = None
374
+
375
+ t = Tes(x=Template('{{DEFAULT}}'))
376
+ with self.assertRaisesRegex(
377
+ ValueError, 'is not a `lf.Template` object or str'
378
+ ):
379
+ _ = t.x.DEFAULT
380
+
315
381
  def test_bad_render(self):
316
382
  with self.assertRaises(ValueError):
317
383
  Template('Hello {{x}}').render(allow_partial=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langfun
3
- Version: 0.0.2.dev20240425
3
+ Version: 0.0.2.dev20240428
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -6,10 +6,10 @@ langfun/core/concurrent.py,sha256=TRc49pJ3HQro2kb5FtcWkHjhBm8UcgE8RJybU5cU3-0,24
6
6
  langfun/core/concurrent_test.py,sha256=mwFMZhDUdppnDr7vDSTwcbMHwrdsIoKJwRYNtl4ZWL4,15185
7
7
  langfun/core/console.py,sha256=bk5rNPNm9rMGW5YT2HixxU04p2umnoabn5SDz6Dqe88,2317
8
8
  langfun/core/console_test.py,sha256=5SYJdxpJGLgdSSQqqMPoA1X6jpsLD8rgcyk-EgI65oE,1077
9
- langfun/core/langfunc.py,sha256=WXdTc3QsmGD_n80KD9dFRr5MHpGZ9E_y_Rhtk4t9-3w,11852
9
+ langfun/core/langfunc.py,sha256=bRujJfH4iTwKFtFxQf745uJkfltuFnPfOGLuP8ydcr4,11646
10
10
  langfun/core/langfunc_test.py,sha256=sQaKuZpGGmG80GRifhbxkj7nfzQLJKj4Vuw5y1s1K3U,8378
11
- langfun/core/language_model.py,sha256=mJfQ_Zqq9IyVyZUdYMQ1BPrpo4Gn8yxDJb_RghQFP_I,18911
12
- langfun/core/language_model_test.py,sha256=oWQjnyiJugSpHJKda-qLaSvmbm1sx_v-ZXrHvw_kNk4,14172
11
+ langfun/core/language_model.py,sha256=dypSV3kr6BLC7hsvV1_QOiqrHUHWtOjQfyFqH79WZmU,20052
12
+ langfun/core/language_model_test.py,sha256=T-itu7Li2smv2dkru0C0neCs2W4VJXlNTYahXU6jF54,19548
13
13
  langfun/core/memory.py,sha256=f-asN1F7Vehgdn_fK84v73GrEUOxRtaW934keutTKjk,2416
14
14
  langfun/core/message.py,sha256=QhvV9t5qaryPcruyxxcXi3gm9QDInkSldwTtK6sVJ3c,15734
15
15
  langfun/core/message_test.py,sha256=Z23pUM5vPnDrYkIIibe2KL73D5HKur_awI0ut_EQFQA,9501
@@ -21,8 +21,8 @@ langfun/core/sampling.py,sha256=vygWvgC8MFw0_AKNSmz-ywMXJYWf8cl0tI8QycvAmyI,5795
21
21
  langfun/core/sampling_test.py,sha256=U7PANpMsl9E_pa4_Y4FzesSjcwg-u-LKHGCWSgv-8FY,3663
22
22
  langfun/core/subscription.py,sha256=euawEuSZP-BHydaT-AQpfYFL0m5pWPGcW0upFhrojqc,10930
23
23
  langfun/core/subscription_test.py,sha256=Y4ZdbZEwm83YNZBxHff0QR4QUa4rdaNXA3_jfIcArBo,8717
24
- langfun/core/template.py,sha256=dr3tZCbXH2qWzigO_EFVHe0GDnnCu58Tru5Mvlzin4o,18447
25
- langfun/core/template_test.py,sha256=xty7PgdNhGpw7ZRZ6QGwhKZWG6dyRgI16Lg3p7IMLJg,13944
24
+ langfun/core/template.py,sha256=FZByYq6mhVDjT4HJ3yY-_TUZ13BiURzTJSKLw6QyLY4,21462
25
+ langfun/core/template_test.py,sha256=Mbv0dFjboGCVvbDkHD-HacZnlCi8Ku2Hpf2UjdwGSNo,15464
26
26
  langfun/core/text_formatting.py,sha256=ytjj7opnRJ6w-pkglL2CZUyfYDXLpNf65E42LBb31gc,5158
27
27
  langfun/core/text_formatting_test.py,sha256=nyKC6tn2L4hPJiqQHgxcbQsJJi4A4Nbj8FiO8iT6B80,1514
28
28
  langfun/core/coding/__init__.py,sha256=5utju_fwEsImaiftx4oXKl9FAM8p281k8-Esdh_-m1w,835
@@ -40,7 +40,7 @@ langfun/core/coding/python/parsing_test.py,sha256=9vAWF484kWIm6JZq8NFiMgKUDhXV-d
40
40
  langfun/core/coding/python/permissions.py,sha256=1QWGHvzL8MM0Ok_auQ9tURqZHtdOfJaDpBzZ29GUE-c,2544
41
41
  langfun/core/coding/python/permissions_test.py,sha256=w5EDb8QxpxgJyZkojyzVWQvDfg366zn99-g__6TbPQ0,2699
42
42
  langfun/core/eval/__init__.py,sha256=NSmPe2lxdxFoY4h8VkNyONPAFtOTUpK9WhmZRaqUgiI,1335
43
- langfun/core/eval/base.py,sha256=_XUc8KivNzgn39sJ0H5W-o_37yXrTBt_X_hKkckLCiA,60239
43
+ langfun/core/eval/base.py,sha256=1svQoZ0C2DGCVLvr0Qt0TcrlJKtJptdoOBVAxkxnHoU,60264
44
44
  langfun/core/eval/base_test.py,sha256=g3lRp2dcq411cLYHpn8spI4feyv2nOccs5PlFBwav3g,22512
45
45
  langfun/core/eval/matching.py,sha256=Ks-L9vyMNDj4R8zFczzByT_4DK2wAFatyCZupdHzx_g,9932
46
46
  langfun/core/eval/matching_test.py,sha256=5Qs9ETaLoyNcJ43f-_bK2Bfe--2Y3U79DnSA55-l6pc,4932
@@ -50,7 +50,7 @@ langfun/core/llms/__init__.py,sha256=1bPg1QI8duOZCYINm-jWi094x0JtLmsk4KX60qIC_gs
50
50
  langfun/core/llms/anthropic.py,sha256=7W9YdPN3SlAFhAIQlihMkrpo7tTY_4NvD0KIlCrqcsk,8505
51
51
  langfun/core/llms/anthropic_test.py,sha256=TMM30myyEhwF99Le4RvJEXOn8RYl0q1FRkt9Q9nl1jk,5540
52
52
  langfun/core/llms/fake.py,sha256=b-Xk5IPTbUt-elsyzd_i3n1tqzc_kgETXrEvgJruSMk,2824
53
- langfun/core/llms/fake_test.py,sha256=ZlDQgL41EX3eYTfBQNp2nB2LciqCmtoHgCsGvW4XhwI,4184
53
+ langfun/core/llms/fake_test.py,sha256=ipKfdOcuqVcJ8lDXVpnBVb9HHG0hAVkFkMoHpWjC2cI,7212
54
54
  langfun/core/llms/google_genai.py,sha256=n8zyJwh9UCTgb6-8LyvmjVNFGZQ4-zfzZ0ulkhHAnR8,8624
55
55
  langfun/core/llms/google_genai_test.py,sha256=_UcGTfl16-aDUlEWFC2W2F8y9jPUs53RBYA6MOCpGXw,7525
56
56
  langfun/core/llms/groq.py,sha256=NaGItVL_pkOpqPpI4bPGU27xLFRoaeizZ49v2s-4ERs,7844
@@ -58,7 +58,7 @@ langfun/core/llms/groq_test.py,sha256=M6GtlrsOvDun_j-sR8cPh4W_moHWZNSTiThu3kuwbb
58
58
  langfun/core/llms/llama_cpp.py,sha256=Y_KkMUf3Xfac49koMUtUslKl3h-HWp3-ntq7Jaa3bdo,2385
59
59
  langfun/core/llms/llama_cpp_test.py,sha256=ZxC6defGd_HX9SFRU9U4cJiQnBKundbOrchbXuC1Z2M,1683
60
60
  langfun/core/llms/openai.py,sha256=06nPhmw0zIA5Zqv3eqsrZtYLHnKwW7N8yt3LlFUFVpI,13247
61
- langfun/core/llms/openai_test.py,sha256=Yt_W6k8YXpT3bs0JroARofCGmn_Uq3u61LmZxqWS2DQ,8272
61
+ langfun/core/llms/openai_test.py,sha256=MiLqBaYliAkWVEwOBmX3HTj_eAuWLv77q8-I3VyVEBU,14841
62
62
  langfun/core/llms/cache/__init__.py,sha256=QAo3InUMDM_YpteNnVCSejI4zOsnjSMWKJKzkb3VY64,993
63
63
  langfun/core/llms/cache/base.py,sha256=cFfYvOIUae842pncqCAsRvqXCk2AnAsRYVx0mcIoAeY,3338
64
64
  langfun/core/llms/cache/in_memory.py,sha256=YfFyJEhLs73cUiB0ZfhMxYpdE8Iuxxw-dvMFwGHTSHw,4742
@@ -84,8 +84,8 @@ langfun/core/structured/mapping.py,sha256=Vq3bQZWi4iYjcVn8D2kvPXTAm9jrQ-_1ueHLbX
84
84
  langfun/core/structured/mapping_test.py,sha256=PiXklMeIa8L6KtMi3ju7J9Y39gZy0hIGz-Oeq4A_7XE,3835
85
85
  langfun/core/structured/parsing.py,sha256=keoVqEfzAbdULh6GawWFsTQzU91MzJXYFZjXGXLaD8g,11492
86
86
  langfun/core/structured/parsing_test.py,sha256=34wDrXaQ-EYhJLfDL8mX9K53oQMSzh5pVYdKjnESmK8,20895
87
- langfun/core/structured/prompting.py,sha256=mOmCWNVMnBk4rI7KBlEm5kmusPXoAKiWcohhzaw-s2o,7427
88
- langfun/core/structured/prompting_test.py,sha256=1Ik-RWs2fixpUTUKoN7FfJX48hDaVScZ-E1CB7J7F3Y,19860
87
+ langfun/core/structured/prompting.py,sha256=WICdX_figP2u98Hvg3BFSTF83nNKxM4x1STxkWe2_9Y,7925
88
+ langfun/core/structured/prompting_test.py,sha256=vslaCAUikfwOvqsKzqs_oyEacrefFsr2SWSqu6OHi3w,20813
89
89
  langfun/core/structured/schema.py,sha256=mJXirgqx3N7SA9zBO_ISHrzcV-ZRshLhnMJyCcSjGjY,25057
90
90
  langfun/core/structured/schema_generation.py,sha256=U3nRQsqmMZg_qIVDh2fiY3K4JLfsAL1LcKzIFP1iXFg,5316
91
91
  langfun/core/structured/schema_generation_test.py,sha256=RM9s71kMNg2jTePwInkiW9fK1ACN37eyPeF8OII-0zw,2950
@@ -101,8 +101,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
101
101
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
102
102
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
103
103
  langfun/core/templates/selfplay_test.py,sha256=DYVrkk7uNKCqJGEHH31HssU2BPuMItU1vJLzfcXIlYg,2156
104
- langfun-0.0.2.dev20240425.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
105
- langfun-0.0.2.dev20240425.dist-info/METADATA,sha256=OZw2iKQkUx9uF-tFzARKjqCekvCCVYMXL00JvSpRxVE,3436
106
- langfun-0.0.2.dev20240425.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
107
- langfun-0.0.2.dev20240425.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
108
- langfun-0.0.2.dev20240425.dist-info/RECORD,,
104
+ langfun-0.0.2.dev20240428.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
105
+ langfun-0.0.2.dev20240428.dist-info/METADATA,sha256=-0Gz3prcRxBlC7ikhHPW0_MirZXL4QcmdcKCxG_LSR4,3436
106
+ langfun-0.0.2.dev20240428.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
107
+ langfun-0.0.2.dev20240428.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
108
+ langfun-0.0.2.dev20240428.dist-info/RECORD,,