langfun 0.1.2.dev202510200805__py3-none-any.whl → 0.1.2.dev202511160804__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.

Potentially problematic release.


This version of langfun might be problematic. Click here for more details.

Files changed (146) hide show
  1. langfun/core/__init__.py +1 -0
  2. langfun/core/agentic/action.py +107 -12
  3. langfun/core/agentic/action_eval.py +9 -2
  4. langfun/core/agentic/action_test.py +25 -0
  5. langfun/core/async_support.py +32 -3
  6. langfun/core/coding/python/correction.py +19 -9
  7. langfun/core/coding/python/execution.py +14 -12
  8. langfun/core/coding/python/generation.py +21 -16
  9. langfun/core/coding/python/sandboxing.py +23 -3
  10. langfun/core/component.py +42 -3
  11. langfun/core/concurrent.py +70 -6
  12. langfun/core/concurrent_test.py +1 -0
  13. langfun/core/console.py +1 -1
  14. langfun/core/data/conversion/anthropic.py +12 -3
  15. langfun/core/data/conversion/anthropic_test.py +8 -6
  16. langfun/core/data/conversion/gemini.py +9 -2
  17. langfun/core/data/conversion/gemini_test.py +12 -9
  18. langfun/core/data/conversion/openai.py +145 -31
  19. langfun/core/data/conversion/openai_test.py +161 -17
  20. langfun/core/eval/base.py +48 -44
  21. langfun/core/eval/base_test.py +4 -4
  22. langfun/core/eval/matching.py +5 -2
  23. langfun/core/eval/patching.py +3 -3
  24. langfun/core/eval/scoring.py +4 -3
  25. langfun/core/eval/v2/__init__.py +1 -0
  26. langfun/core/eval/v2/checkpointing.py +39 -5
  27. langfun/core/eval/v2/checkpointing_test.py +1 -1
  28. langfun/core/eval/v2/eval_test_helper.py +97 -1
  29. langfun/core/eval/v2/evaluation.py +88 -16
  30. langfun/core/eval/v2/evaluation_test.py +9 -3
  31. langfun/core/eval/v2/example.py +45 -39
  32. langfun/core/eval/v2/example_test.py +3 -3
  33. langfun/core/eval/v2/experiment.py +51 -8
  34. langfun/core/eval/v2/metric_values.py +31 -3
  35. langfun/core/eval/v2/metric_values_test.py +32 -0
  36. langfun/core/eval/v2/metrics.py +157 -44
  37. langfun/core/eval/v2/metrics_test.py +39 -18
  38. langfun/core/eval/v2/progress.py +30 -1
  39. langfun/core/eval/v2/progress_test.py +27 -0
  40. langfun/core/eval/v2/progress_tracking_test.py +3 -0
  41. langfun/core/eval/v2/reporting.py +90 -71
  42. langfun/core/eval/v2/reporting_test.py +20 -6
  43. langfun/core/eval/v2/runners/__init__.py +26 -0
  44. langfun/core/eval/v2/{runners.py → runners/base.py} +22 -124
  45. langfun/core/eval/v2/runners/debug.py +40 -0
  46. langfun/core/eval/v2/runners/debug_test.py +79 -0
  47. langfun/core/eval/v2/runners/parallel.py +100 -0
  48. langfun/core/eval/v2/runners/parallel_test.py +98 -0
  49. langfun/core/eval/v2/runners/sequential.py +47 -0
  50. langfun/core/eval/v2/runners/sequential_test.py +175 -0
  51. langfun/core/langfunc.py +45 -130
  52. langfun/core/langfunc_test.py +6 -4
  53. langfun/core/language_model.py +103 -16
  54. langfun/core/language_model_test.py +9 -3
  55. langfun/core/llms/__init__.py +7 -1
  56. langfun/core/llms/anthropic.py +157 -2
  57. langfun/core/llms/azure_openai.py +29 -17
  58. langfun/core/llms/cache/base.py +25 -3
  59. langfun/core/llms/cache/in_memory.py +48 -7
  60. langfun/core/llms/cache/in_memory_test.py +14 -4
  61. langfun/core/llms/compositional.py +25 -1
  62. langfun/core/llms/deepseek.py +30 -2
  63. langfun/core/llms/fake.py +32 -1
  64. langfun/core/llms/gemini.py +14 -9
  65. langfun/core/llms/google_genai.py +29 -1
  66. langfun/core/llms/groq.py +28 -3
  67. langfun/core/llms/llama_cpp.py +23 -4
  68. langfun/core/llms/openai.py +36 -3
  69. langfun/core/llms/openai_compatible.py +148 -27
  70. langfun/core/llms/openai_compatible_test.py +207 -20
  71. langfun/core/llms/openai_test.py +0 -2
  72. langfun/core/llms/rest.py +12 -1
  73. langfun/core/llms/vertexai.py +51 -8
  74. langfun/core/logging.py +1 -1
  75. langfun/core/mcp/client.py +77 -22
  76. langfun/core/mcp/client_test.py +8 -35
  77. langfun/core/mcp/session.py +94 -29
  78. langfun/core/mcp/session_test.py +54 -0
  79. langfun/core/mcp/tool.py +151 -22
  80. langfun/core/mcp/tool_test.py +197 -0
  81. langfun/core/memory.py +1 -0
  82. langfun/core/message.py +160 -55
  83. langfun/core/message_test.py +65 -81
  84. langfun/core/modalities/__init__.py +8 -0
  85. langfun/core/modalities/audio.py +21 -1
  86. langfun/core/modalities/image.py +19 -1
  87. langfun/core/modalities/mime.py +62 -3
  88. langfun/core/modalities/pdf.py +19 -1
  89. langfun/core/modalities/video.py +21 -1
  90. langfun/core/modality.py +167 -29
  91. langfun/core/modality_test.py +42 -12
  92. langfun/core/natural_language.py +1 -1
  93. langfun/core/sampling.py +4 -4
  94. langfun/core/sampling_test.py +20 -4
  95. langfun/core/structured/__init__.py +2 -24
  96. langfun/core/structured/completion.py +34 -44
  97. langfun/core/structured/completion_test.py +23 -43
  98. langfun/core/structured/description.py +54 -50
  99. langfun/core/structured/function_generation.py +29 -12
  100. langfun/core/structured/mapping.py +81 -37
  101. langfun/core/structured/parsing.py +95 -79
  102. langfun/core/structured/parsing_test.py +0 -3
  103. langfun/core/structured/querying.py +215 -142
  104. langfun/core/structured/querying_test.py +65 -29
  105. langfun/core/structured/schema/__init__.py +48 -0
  106. langfun/core/structured/schema/base.py +664 -0
  107. langfun/core/structured/schema/base_test.py +531 -0
  108. langfun/core/structured/schema/json.py +174 -0
  109. langfun/core/structured/schema/json_test.py +121 -0
  110. langfun/core/structured/schema/python.py +316 -0
  111. langfun/core/structured/schema/python_test.py +410 -0
  112. langfun/core/structured/schema_generation.py +33 -14
  113. langfun/core/structured/scoring.py +47 -36
  114. langfun/core/structured/tokenization.py +26 -11
  115. langfun/core/subscription.py +2 -2
  116. langfun/core/template.py +175 -50
  117. langfun/core/template_test.py +123 -17
  118. langfun/env/__init__.py +8 -2
  119. langfun/env/base_environment.py +320 -128
  120. langfun/env/base_environment_test.py +473 -0
  121. langfun/env/base_feature.py +92 -15
  122. langfun/env/base_feature_test.py +228 -0
  123. langfun/env/base_sandbox.py +84 -361
  124. langfun/env/base_sandbox_test.py +1235 -0
  125. langfun/env/event_handlers/__init__.py +1 -1
  126. langfun/env/event_handlers/chain.py +233 -0
  127. langfun/env/event_handlers/chain_test.py +253 -0
  128. langfun/env/event_handlers/event_logger.py +95 -98
  129. langfun/env/event_handlers/event_logger_test.py +21 -21
  130. langfun/env/event_handlers/metric_writer.py +225 -140
  131. langfun/env/event_handlers/metric_writer_test.py +23 -6
  132. langfun/env/interface.py +854 -40
  133. langfun/env/interface_test.py +112 -2
  134. langfun/env/load_balancers_test.py +23 -2
  135. langfun/env/test_utils.py +126 -84
  136. {langfun-0.1.2.dev202510200805.dist-info → langfun-0.1.2.dev202511160804.dist-info}/METADATA +1 -1
  137. langfun-0.1.2.dev202511160804.dist-info/RECORD +211 -0
  138. langfun/core/eval/v2/runners_test.py +0 -343
  139. langfun/core/structured/schema.py +0 -987
  140. langfun/core/structured/schema_test.py +0 -982
  141. langfun/env/base_test.py +0 -1481
  142. langfun/env/event_handlers/base.py +0 -350
  143. langfun-0.1.2.dev202510200805.dist-info/RECORD +0 -195
  144. {langfun-0.1.2.dev202510200805.dist-info → langfun-0.1.2.dev202511160804.dist-info}/WHEEL +0 -0
  145. {langfun-0.1.2.dev202510200805.dist-info → langfun-0.1.2.dev202511160804.dist-info}/licenses/LICENSE +0 -0
  146. {langfun-0.1.2.dev202510200805.dist-info → langfun-0.1.2.dev202511160804.dist-info}/top_level.txt +0 -0
@@ -14,14 +14,14 @@
14
14
  """Environment event logger."""
15
15
 
16
16
  from typing import Annotated
17
- from langfun.env.event_handlers import base
17
+ from langfun.env import interface
18
18
  import pyglove as pg
19
19
 
20
20
 
21
21
  _METRIC_NAMESPACE = '/langfun/env'
22
22
 
23
23
 
24
- class MetricWriter(pg.Object, base.EventHandler):
24
+ class MetricWriter(pg.Object, interface.EventHandler):
25
25
  """Event handler for streamz metrics."""
26
26
 
27
27
  app: Annotated[
@@ -100,6 +100,7 @@ class MetricWriter(pg.Object, base.EventHandler):
100
100
  parameters={
101
101
  'app': str,
102
102
  'environment_id': str,
103
+ 'image_id': str,
103
104
  'error': str,
104
105
  }
105
106
  )
@@ -109,6 +110,7 @@ class MetricWriter(pg.Object, base.EventHandler):
109
110
  parameters={
110
111
  'app': str,
111
112
  'environment_id': str,
113
+ 'image_id': str,
112
114
  'error': str
113
115
  }
114
116
  )
@@ -118,6 +120,7 @@ class MetricWriter(pg.Object, base.EventHandler):
118
120
  parameters={
119
121
  'app': str,
120
122
  'environment_id': str,
123
+ 'image_id': str,
121
124
  'status': str,
122
125
  },
123
126
  )
@@ -127,6 +130,7 @@ class MetricWriter(pg.Object, base.EventHandler):
127
130
  parameters={
128
131
  'app': str,
129
132
  'environment_id': str,
133
+ 'image_id': str,
130
134
  'error': str,
131
135
  }
132
136
  )
@@ -136,6 +140,7 @@ class MetricWriter(pg.Object, base.EventHandler):
136
140
  parameters={
137
141
  'app': str,
138
142
  'environment_id': str,
143
+ 'image_id': str,
139
144
  'activity': str,
140
145
  'error': str,
141
146
  }
@@ -148,6 +153,7 @@ class MetricWriter(pg.Object, base.EventHandler):
148
153
  parameters={
149
154
  'app': str,
150
155
  'environment_id': str,
156
+ 'image_id': str,
151
157
  'error': str,
152
158
  }
153
159
  )
@@ -157,6 +163,7 @@ class MetricWriter(pg.Object, base.EventHandler):
157
163
  parameters={
158
164
  'app': str,
159
165
  'environment_id': str,
166
+ 'image_id': str,
160
167
  'error': str,
161
168
  }
162
169
  )
@@ -166,6 +173,7 @@ class MetricWriter(pg.Object, base.EventHandler):
166
173
  parameters={
167
174
  'app': str,
168
175
  'environment_id': str,
176
+ 'image_id': str,
169
177
  'error': str,
170
178
  }
171
179
  )
@@ -175,6 +183,7 @@ class MetricWriter(pg.Object, base.EventHandler):
175
183
  parameters={
176
184
  'app': str,
177
185
  'environment_id': str,
186
+ 'image_id': str,
178
187
  'error': str,
179
188
  }
180
189
  )
@@ -184,6 +193,7 @@ class MetricWriter(pg.Object, base.EventHandler):
184
193
  parameters={
185
194
  'app': str,
186
195
  'environment_id': str,
196
+ 'image_id': str,
187
197
  'status': str,
188
198
  }
189
199
  )
@@ -193,11 +203,47 @@ class MetricWriter(pg.Object, base.EventHandler):
193
203
  parameters={
194
204
  'app': str,
195
205
  'environment_id': str,
206
+ 'image_id': str,
196
207
  'activity': str,
197
208
  'error': str,
198
209
  }
199
210
  )
200
211
 
212
+ #
213
+ # Sandbox session metrics.
214
+ #
215
+
216
+ self._sandbox_session_start_duration_ms = self._get_distribution(
217
+ 'sandbox_session_start_duration_ms',
218
+ description='Sandbox session start duration in milliseconds',
219
+ parameters={
220
+ 'app': str,
221
+ 'environment_id': str,
222
+ 'image_id': str,
223
+ 'error': str,
224
+ }
225
+ )
226
+ self._sandbox_session_end_duration_ms = self._get_distribution(
227
+ 'sandbox_session_end_duration_ms',
228
+ description='Sandbox session end duration in milliseconds',
229
+ parameters={
230
+ 'app': str,
231
+ 'environment_id': str,
232
+ 'image_id': str,
233
+ 'error': str,
234
+ }
235
+ )
236
+ self._sandbox_session_lifetime_ms = self._get_distribution(
237
+ 'sandbox_session_lifetime_ms',
238
+ description='Sandbox session lifetime in milliseconds',
239
+ parameters={
240
+ 'app': str,
241
+ 'environment_id': str,
242
+ 'image_id': str,
243
+ 'error': str,
244
+ }
245
+ )
246
+
201
247
  #
202
248
  # Feature metrics.
203
249
  #
@@ -209,6 +255,7 @@ class MetricWriter(pg.Object, base.EventHandler):
209
255
  parameters={
210
256
  'app': str,
211
257
  'environment_id': str,
258
+ 'image_id': str,
212
259
  'feature_name': str,
213
260
  'error': str,
214
261
  }
@@ -219,6 +266,7 @@ class MetricWriter(pg.Object, base.EventHandler):
219
266
  parameters={
220
267
  'app': str,
221
268
  'environment_id': str,
269
+ 'image_id': str,
222
270
  'feature_name': str,
223
271
  'error': str,
224
272
  }
@@ -229,6 +277,7 @@ class MetricWriter(pg.Object, base.EventHandler):
229
277
  parameters={
230
278
  'app': str,
231
279
  'environment_id': str,
280
+ 'image_id': str,
232
281
  'feature_name': str,
233
282
  'error': str,
234
283
  }
@@ -239,16 +288,29 @@ class MetricWriter(pg.Object, base.EventHandler):
239
288
  parameters={
240
289
  'app': str,
241
290
  'environment_id': str,
291
+ 'image_id': str,
242
292
  'feature_name': str,
243
293
  'error': str,
244
294
  }
245
295
  )
296
+ self._feature_activity = self._get_counter(
297
+ 'feature_activity',
298
+ description='Feature activity counter',
299
+ parameters={
300
+ 'app': str,
301
+ 'environment_id': str,
302
+ 'image_id': str,
303
+ 'activity': str,
304
+ 'error': str,
305
+ }
306
+ )
246
307
  self._feature_housekeep = self._get_counter(
247
308
  'feature_housekeep',
248
309
  description='Feature housekeeping counter',
249
310
  parameters={
250
311
  'app': str,
251
312
  'environment_id': str,
313
+ 'image_id': str,
252
314
  'feature_name': str,
253
315
  'error': str,
254
316
  }
@@ -261,6 +323,7 @@ class MetricWriter(pg.Object, base.EventHandler):
261
323
  parameters={
262
324
  'app': str,
263
325
  'environment_id': str,
326
+ 'image_id': str,
264
327
  'feature_name': str,
265
328
  'error': str,
266
329
  }
@@ -271,6 +334,7 @@ class MetricWriter(pg.Object, base.EventHandler):
271
334
  parameters={
272
335
  'app': str,
273
336
  'environment_id': str,
337
+ 'image_id': str,
274
338
  'feature_name': str,
275
339
  'error': str,
276
340
  }
@@ -281,6 +345,7 @@ class MetricWriter(pg.Object, base.EventHandler):
281
345
  parameters={
282
346
  'app': str,
283
347
  'environment_id': str,
348
+ 'image_id': str,
284
349
  'feature_name': str,
285
350
  'error': str,
286
351
  }
@@ -291,63 +356,44 @@ class MetricWriter(pg.Object, base.EventHandler):
291
356
  parameters={
292
357
  'app': str,
293
358
  'environment_id': str,
359
+ 'image_id': str,
294
360
  'feature_name': str,
295
361
  'error': str,
296
362
  }
297
363
  )
298
- self._feature_housekeep_duration_ms = self._get_distribution(
299
- 'feature_housekeep_duration_ms',
300
- description='Feature housekeeping duration in milliseconds',
301
- parameters={
302
- 'app': str,
303
- 'environment_id': str,
304
- 'feature_name': str,
305
- 'error': str,
306
- }
307
- )
308
-
309
- #
310
- # Session metrics.
311
- #
312
-
313
- self._session_start_duration_ms = self._get_distribution(
314
- 'session_start_duration_ms',
315
- description='Session start duration in milliseconds',
316
- parameters={
317
- 'app': str,
318
- 'environment_id': str,
319
- 'error': str,
320
- }
321
- )
322
- self._session_end_duration_ms = self._get_distribution(
323
- 'session_end_duration_ms',
324
- description='Session end duration in milliseconds',
364
+ self._feature_activity_duration_ms = self._get_distribution(
365
+ 'feature_activity_duration_ms',
366
+ description='Feature activity duration in milliseconds',
325
367
  parameters={
326
368
  'app': str,
327
369
  'environment_id': str,
370
+ 'image_id': str,
371
+ 'activity': str,
328
372
  'error': str,
329
373
  }
330
374
  )
331
- self._session_lifetime_ms = self._get_distribution(
332
- 'session_lifetime_ms',
333
- description='Session lifetime in milliseconds',
375
+ self._feature_housekeep_duration_ms = self._get_distribution(
376
+ 'feature_housekeep_duration_ms',
377
+ description='Feature housekeeping duration in milliseconds',
334
378
  parameters={
335
379
  'app': str,
336
380
  'environment_id': str,
381
+ 'image_id': str,
382
+ 'feature_name': str,
337
383
  'error': str,
338
384
  }
339
385
  )
340
386
 
341
387
  def on_environment_starting(
342
388
  self,
343
- environment: base.Environment
389
+ environment: interface.Environment
344
390
  ) -> None:
345
391
  """Called when the environment is starting."""
346
392
  self._initialize_metrics()
347
393
 
348
394
  def on_environment_housekeep(
349
395
  self,
350
- environment: base.Environment,
396
+ environment: interface.Environment,
351
397
  counter: int,
352
398
  duration: float,
353
399
  error: BaseException | None,
@@ -363,81 +409,151 @@ class MetricWriter(pg.Object, base.EventHandler):
363
409
 
364
410
  def on_sandbox_start(
365
411
  self,
366
- environment: base.Environment,
367
- sandbox: base.Sandbox,
412
+ sandbox: interface.Sandbox,
368
413
  duration: float,
369
414
  error: BaseException | None
370
415
  ) -> None:
371
416
  self._sandbox_start.increment(
372
417
  app=self.app,
373
- environment_id=str(environment.id),
418
+ environment_id=str(sandbox.environment.id),
419
+ image_id=sandbox.image_id,
374
420
  error=self._error_tag(error)
375
421
  )
376
422
  self._sandbox_start_duration_ms.record(
377
423
  int(duration * 1000),
378
424
  app=self.app,
379
- environment_id=str(environment.id),
425
+ environment_id=str(sandbox.environment.id),
426
+ image_id=sandbox.image_id,
380
427
  error=self._error_tag(error)
381
428
  )
382
429
 
383
430
  def on_sandbox_status_change(
384
431
  self,
385
- environment: base.Environment,
386
- sandbox: base.Sandbox,
387
- old_status: base.Sandbox.Status,
388
- new_status: base.Sandbox.Status,
432
+ sandbox: interface.Sandbox,
433
+ old_status: interface.Sandbox.Status,
434
+ new_status: interface.Sandbox.Status,
389
435
  span: float
390
436
  ) -> None:
391
437
  self._sandbox_status_duration_ms.record(
392
438
  int(span * 1000),
393
439
  app=self.app,
394
- environment_id=str(environment.id),
440
+ environment_id=str(sandbox.environment.id),
441
+ image_id=sandbox.image_id,
395
442
  status=old_status.value
396
443
  )
397
- if old_status != base.Sandbox.Status.CREATED:
444
+ if old_status != interface.Sandbox.Status.CREATED:
398
445
  self._sandbox_count.increment(
399
446
  delta=-1,
400
447
  app=self.app,
401
- environment_id=str(environment.id),
448
+ environment_id=str(sandbox.environment.id),
449
+ image_id=sandbox.image_id,
402
450
  status=old_status.value
403
451
  )
404
- if new_status != base.Sandbox.Status.OFFLINE:
452
+ if new_status != interface.Sandbox.Status.OFFLINE:
405
453
  self._sandbox_count.increment(
406
454
  app=self.app,
407
- environment_id=str(environment.id),
455
+ environment_id=str(sandbox.environment.id),
456
+ image_id=sandbox.image_id,
408
457
  status=new_status.value
409
458
  )
410
459
 
411
460
  def on_sandbox_shutdown(
412
461
  self,
413
- environment: base.Environment,
414
- sandbox: base.Sandbox,
462
+ sandbox: interface.Sandbox,
415
463
  duration: float,
416
464
  lifetime: float,
417
465
  error: BaseException | None
418
466
  ) -> None:
419
467
  self._sandbox_shutdown.increment(
420
468
  app=self.app,
421
- environment_id=str(environment.id),
469
+ environment_id=str(sandbox.environment.id),
470
+ image_id=sandbox.image_id,
422
471
  error=self._error_tag(error)
423
472
  )
424
473
  self._sandbox_shutdown_duration_ms.record(
425
474
  int(duration * 1000),
426
475
  app=self.app,
427
- environment_id=str(environment.id),
476
+ environment_id=str(sandbox.environment.id),
477
+ image_id=sandbox.image_id,
428
478
  error=self._error_tag(error)
429
479
  )
430
480
  self._sandbox_lifetime_ms.record(
431
481
  int(lifetime * 1000),
432
482
  app=self.app,
433
- environment_id=str(environment.id),
483
+ environment_id=str(sandbox.environment.id),
484
+ image_id=sandbox.image_id,
485
+ error=self._error_tag(error)
486
+ )
487
+
488
+ def on_sandbox_session_start(
489
+ self,
490
+ sandbox: interface.Sandbox,
491
+ session_id: str,
492
+ duration: float,
493
+ error: BaseException | None
494
+ ) -> None:
495
+ """Called when a sandbox session starts."""
496
+ self._sandbox_session_start_duration_ms.record(
497
+ int(duration * 1000),
498
+ app=self.app,
499
+ environment_id=str(sandbox.environment.id),
500
+ image_id=sandbox.image_id,
501
+ error=self._error_tag(error)
502
+ )
503
+
504
+ def on_sandbox_session_end(
505
+ self,
506
+ sandbox: interface.Sandbox,
507
+ session_id: str,
508
+ duration: float,
509
+ lifetime: float,
510
+ error: BaseException | None
511
+ ) -> None:
512
+ """Called when a sandbox session ends."""
513
+ self._sandbox_session_end_duration_ms.record(
514
+ int(duration * 1000),
515
+ app=self.app,
516
+ environment_id=str(sandbox.environment.id),
517
+ image_id=sandbox.image_id,
518
+ error=self._error_tag(error)
519
+ )
520
+ self._sandbox_session_lifetime_ms.record(
521
+ int(lifetime * 1000),
522
+ app=self.app,
523
+ environment_id=str(sandbox.environment.id),
524
+ image_id=sandbox.image_id,
525
+ error=self._error_tag(error)
526
+ )
527
+
528
+ def on_sandbox_activity(
529
+ self,
530
+ name: str,
531
+ sandbox: interface.Sandbox,
532
+ session_id: str | None,
533
+ duration: float,
534
+ error: BaseException | None,
535
+ **kwargs
536
+ ) -> None:
537
+ """Called when a sandbox activity is performed."""
538
+ self._sandbox_activity.increment(
539
+ app=self.app,
540
+ environment_id=str(sandbox.environment.id),
541
+ image_id=sandbox.image_id,
542
+ activity=name,
543
+ error=self._error_tag(error)
544
+ )
545
+ self._sandbox_activity_duration_ms.record(
546
+ int(duration * 1000),
547
+ app=self.app,
548
+ environment_id=str(sandbox.environment.id),
549
+ image_id=sandbox.image_id,
550
+ activity=name,
434
551
  error=self._error_tag(error)
435
552
  )
436
553
 
437
554
  def on_sandbox_housekeep(
438
555
  self,
439
- environment: base.Environment,
440
- sandbox: base.Sandbox,
556
+ sandbox: interface.Sandbox,
441
557
  counter: int,
442
558
  duration: float,
443
559
  error: BaseException | None,
@@ -446,196 +562,165 @@ class MetricWriter(pg.Object, base.EventHandler):
446
562
  """Called when a sandbox feature is housekeeping."""
447
563
  self._sandbox_housekeep.increment(
448
564
  app=self.app,
449
- environment_id=str(environment.id),
565
+ environment_id=str(sandbox.environment.id),
566
+ image_id=sandbox.image_id,
450
567
  error=self._error_tag(error)
451
568
  )
452
569
  self._sandbox_housekeep_duration_ms.record(
453
570
  int(duration * 1000),
454
571
  app=self.app,
455
- environment_id=str(environment.id),
572
+ environment_id=str(sandbox.environment.id),
573
+ image_id=sandbox.image_id,
456
574
  error=self._error_tag(error)
457
575
  )
458
576
 
459
577
  def on_feature_setup(
460
578
  self,
461
- environment: base.Environment,
462
- sandbox: base.Sandbox,
463
- feature: base.Feature,
579
+ feature: interface.Feature,
464
580
  duration: float,
465
581
  error: BaseException | None
466
582
  ) -> None:
467
583
  """Called when a sandbox feature is setup."""
584
+ image_id = feature.sandbox.image_id if feature.sandbox else ''
468
585
  self._feature_setup.increment(
469
586
  app=self.app,
470
- environment_id=str(environment.id),
587
+ environment_id=str(feature.environment.id),
588
+ image_id=image_id,
471
589
  feature_name=feature.name,
472
590
  error=self._error_tag(error)
473
591
  )
474
592
  self._feature_setup_duration_ms.record(
475
593
  int(duration * 1000),
476
594
  app=self.app,
477
- environment_id=str(environment.id),
595
+ environment_id=str(feature.environment.id),
596
+ image_id=image_id,
478
597
  feature_name=feature.name,
479
598
  error=self._error_tag(error)
480
599
  )
481
600
 
482
601
  def on_feature_teardown(
483
602
  self,
484
- environment: base.Environment,
485
- sandbox: base.Sandbox,
486
- feature: base.Feature,
603
+ feature: interface.Feature,
487
604
  duration: float,
488
605
  error: BaseException | None
489
606
  ) -> None:
490
607
  """Called when a sandbox feature is teardown."""
608
+ image_id = feature.sandbox.image_id if feature.sandbox else ''
491
609
  self._feature_teardown.increment(
492
610
  app=self.app,
493
- environment_id=str(environment.id),
611
+ environment_id=str(feature.environment.id),
612
+ image_id=image_id,
494
613
  feature_name=feature.name,
495
614
  error=self._error_tag(error)
496
615
  )
497
616
  self._feature_teardown_duration_ms.record(
498
617
  int(duration * 1000),
499
618
  app=self.app,
500
- environment_id=str(environment.id),
619
+ environment_id=str(feature.environment.id),
620
+ image_id=image_id,
501
621
  feature_name=feature.name,
502
622
  error=self._error_tag(error)
503
623
  )
504
624
 
505
625
  def on_feature_setup_session(
506
626
  self,
507
- environment: base.Environment,
508
- sandbox: base.Sandbox,
509
- feature: base.Feature,
627
+ feature: interface.Feature,
510
628
  session_id: str | None,
511
629
  duration: float,
512
630
  error: BaseException | None
513
631
  ) -> None:
514
632
  """Called when a sandbox feature is setup."""
633
+ image_id = feature.sandbox.image_id if feature.sandbox else ''
515
634
  self._feature_setup_session.increment(
516
635
  app=self.app,
517
- environment_id=str(environment.id),
636
+ environment_id=str(feature.environment.id),
637
+ image_id=image_id,
518
638
  feature_name=feature.name,
519
639
  error=self._error_tag(error)
520
640
  )
521
641
  self._feature_setup_session_duration_ms.record(
522
642
  int(duration * 1000),
523
643
  app=self.app,
524
- environment_id=str(environment.id),
644
+ environment_id=str(feature.environment.id),
645
+ image_id=image_id,
525
646
  feature_name=feature.name,
526
647
  error=self._error_tag(error)
527
648
  )
528
649
 
529
650
  def on_feature_teardown_session(
530
651
  self,
531
- environment: base.Environment,
532
- sandbox: base.Sandbox,
533
- feature: base.Feature,
652
+ feature: interface.Feature,
534
653
  session_id: str,
535
654
  duration: float,
536
655
  error: BaseException | None
537
656
  ) -> None:
538
657
  """Called when a sandbox feature is teardown."""
658
+ image_id = feature.sandbox.image_id if feature.sandbox else ''
539
659
  self._feature_teardown_session.increment(
540
660
  app=self.app,
541
- environment_id=str(environment.id),
661
+ environment_id=str(feature.environment.id),
662
+ image_id=image_id,
542
663
  feature_name=feature.name,
543
664
  error=self._error_tag(error)
544
665
  )
545
666
  self._feature_teardown_session_duration_ms.record(
546
667
  int(duration * 1000),
547
668
  app=self.app,
548
- environment_id=str(environment.id),
669
+ environment_id=str(feature.environment.id),
670
+ image_id=image_id,
549
671
  feature_name=feature.name,
550
672
  error=self._error_tag(error)
551
673
  )
552
674
 
553
- def on_feature_housekeep(
675
+ def on_feature_activity(
554
676
  self,
555
- environment: base.Environment,
556
- sandbox: base.Sandbox,
557
- feature: base.Feature,
558
- counter: int,
677
+ name: str,
678
+ feature: interface.Feature,
679
+ session_id: str | None,
559
680
  duration: float,
560
681
  error: BaseException | None,
561
682
  **kwargs
562
683
  ) -> None:
563
- """Called when a sandbox feature is housekeeping."""
564
- self._feature_housekeep.increment(
684
+ """Called when a feature activity is performed."""
685
+ image_id = feature.sandbox.image_id if feature.sandbox else ''
686
+ self._feature_activity.increment(
565
687
  app=self.app,
566
- environment_id=str(environment.id),
567
- feature_name=feature.name,
568
- error=self._error_tag(error)
569
- )
570
- self._feature_housekeep_duration_ms.record(
571
- int(duration * 1000),
572
- app=self.app,
573
- environment_id=str(environment.id),
574
- feature_name=feature.name,
575
- error=self._error_tag(error)
576
- )
577
-
578
- def on_session_start(
579
- self,
580
- environment: base.Environment,
581
- sandbox: base.Sandbox,
582
- session_id: str,
583
- duration: float,
584
- error: BaseException | None
585
- ) -> None:
586
- """Called when a sandbox session starts."""
587
- self._session_start_duration_ms.record(
588
- int(duration * 1000),
589
- app=self.app,
590
- environment_id=str(environment.id),
688
+ environment_id=str(feature.environment.id),
689
+ image_id=image_id,
690
+ activity=name,
591
691
  error=self._error_tag(error)
592
692
  )
593
-
594
- def on_session_end(
595
- self,
596
- environment: base.Environment,
597
- sandbox: base.Sandbox,
598
- session_id: str,
599
- duration: float,
600
- lifetime: float,
601
- error: BaseException | None
602
- ) -> None:
603
- """Called when a sandbox session ends."""
604
- self._session_end_duration_ms.record(
693
+ self._feature_activity_duration_ms.record(
605
694
  int(duration * 1000),
606
695
  app=self.app,
607
- environment_id=str(environment.id),
608
- error=self._error_tag(error)
609
- )
610
- self._session_lifetime_ms.record(
611
- int(lifetime * 1000),
612
- app=self.app,
613
- environment_id=str(environment.id),
696
+ environment_id=str(feature.environment.id),
697
+ image_id=image_id,
698
+ activity=name,
614
699
  error=self._error_tag(error)
615
700
  )
616
701
 
617
- def on_sandbox_activity(
702
+ def on_feature_housekeep(
618
703
  self,
619
- name: str,
620
- environment: base.Environment,
621
- sandbox: base.Sandbox,
622
- feature: base.Feature | None,
623
- session_id: str | None,
704
+ feature: interface.Feature,
705
+ counter: int,
624
706
  duration: float,
625
707
  error: BaseException | None,
626
708
  **kwargs
627
709
  ) -> None:
628
- """Called when a sandbox activity is performed."""
629
- self._sandbox_activity.increment(
710
+ """Called when a sandbox feature is housekeeping."""
711
+ image_id = feature.sandbox.image_id if feature.sandbox else ''
712
+ self._feature_housekeep.increment(
630
713
  app=self.app,
631
- environment_id=str(environment.id),
632
- activity=name,
714
+ environment_id=str(feature.environment.id),
715
+ image_id=image_id,
716
+ feature_name=feature.name,
633
717
  error=self._error_tag(error)
634
718
  )
635
- self._sandbox_activity_duration_ms.record(
719
+ self._feature_housekeep_duration_ms.record(
636
720
  int(duration * 1000),
637
721
  app=self.app,
638
- environment_id=str(environment.id),
639
- activity=name,
722
+ environment_id=str(feature.environment.id),
723
+ image_id=image_id,
724
+ feature_name=feature.name,
640
725
  error=self._error_tag(error)
641
726
  )