langfun 0.1.2.dev202509290805__py3-none-any.whl → 0.1.2.dev202510010805__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.
- langfun/core/llms/gemini.py +5 -0
- langfun/core/llms/rest.py +4 -0
- langfun/env/base_environment.py +99 -53
- langfun/env/base_feature.py +3 -2
- langfun/env/base_sandbox.py +34 -11
- langfun/env/base_test.py +140 -103
- langfun/env/event_handlers/__init__.py +2 -0
- langfun/env/event_handlers/base.py +88 -9
- langfun/env/event_handlers/event_logger.py +75 -15
- langfun/env/event_handlers/event_logger_test.py +15 -0
- langfun/env/event_handlers/metric_writer.py +607 -0
- langfun/env/event_handlers/metric_writer_test.py +170 -0
- langfun/env/test_utils.py +12 -6
- {langfun-0.1.2.dev202509290805.dist-info → langfun-0.1.2.dev202510010805.dist-info}/METADATA +1 -1
- {langfun-0.1.2.dev202509290805.dist-info → langfun-0.1.2.dev202510010805.dist-info}/RECORD +18 -16
- {langfun-0.1.2.dev202509290805.dist-info → langfun-0.1.2.dev202510010805.dist-info}/WHEEL +0 -0
- {langfun-0.1.2.dev202509290805.dist-info → langfun-0.1.2.dev202510010805.dist-info}/licenses/LICENSE +0 -0
- {langfun-0.1.2.dev202509290805.dist-info → langfun-0.1.2.dev202510010805.dist-info}/top_level.txt +0 -0
langfun/core/llms/gemini.py
CHANGED
|
@@ -752,6 +752,11 @@ class Gemini(rest.REST):
|
|
|
752
752
|
prompt.as_format('gemini', chunk_preprocessor=modality_conversion)
|
|
753
753
|
)
|
|
754
754
|
request['contents'] = contents
|
|
755
|
+
# Users could use `metadata_gemini_tools` to pass Gemini tools. For example,
|
|
756
|
+
# for enabling Search Grounding, users could pass:
|
|
757
|
+
# metadata_gemini_tools=[{'google_search': {}}]
|
|
758
|
+
if tools := prompt.metadata.get('gemini_tools'):
|
|
759
|
+
request['tools'] = tools
|
|
755
760
|
return request
|
|
756
761
|
|
|
757
762
|
def _generation_config(
|
langfun/core/llms/rest.py
CHANGED
|
@@ -98,7 +98,9 @@ class REST(lf.LanguageModel):
|
|
|
98
98
|
raise lf.TemporaryLMError(str(e)) from e
|
|
99
99
|
except (
|
|
100
100
|
requests.exceptions.ConnectionError,
|
|
101
|
+
requests.exceptions.ChunkedEncodingError,
|
|
101
102
|
ConnectionError,
|
|
103
|
+
ConnectionResetError,
|
|
102
104
|
) as e:
|
|
103
105
|
error_message = str(e)
|
|
104
106
|
if 'REJECTED_CLIENT_THROTTLED' in error_message:
|
|
@@ -107,6 +109,8 @@ class REST(lf.LanguageModel):
|
|
|
107
109
|
raise lf.TemporaryLMError(error_message) from e
|
|
108
110
|
if 'UNREACHABLE_ERROR' in error_message:
|
|
109
111
|
raise lf.TemporaryLMError(error_message) from e
|
|
112
|
+
if 'Connection reset by peer' in error_message:
|
|
113
|
+
raise lf.TemporaryLMError(error_message) from e
|
|
110
114
|
raise lf.LMError(error_message) from e
|
|
111
115
|
|
|
112
116
|
def _error(self, status_code: int, content: str) -> lf.LMError:
|
langfun/env/base_environment.py
CHANGED
|
@@ -221,7 +221,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
221
221
|
self._sandbox_pool = [None] * self.min_pool_size
|
|
222
222
|
for i, sandbox, _ in lf.concurrent_map(
|
|
223
223
|
lambda i: self._bring_up_sandbox_with_retry(
|
|
224
|
-
sandbox_id=
|
|
224
|
+
sandbox_id=f'{i}:0', shutdown_env_upon_outage=False
|
|
225
225
|
),
|
|
226
226
|
range(self.min_pool_size),
|
|
227
227
|
silence_on_errors=None,
|
|
@@ -335,6 +335,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
335
335
|
f'it is in {self._status.value!r} status.'
|
|
336
336
|
)
|
|
337
337
|
|
|
338
|
+
self.on_starting()
|
|
338
339
|
starting_time = time.time()
|
|
339
340
|
try:
|
|
340
341
|
self._start()
|
|
@@ -358,12 +359,14 @@ class BaseEnvironment(interface.Environment):
|
|
|
358
359
|
return
|
|
359
360
|
|
|
360
361
|
self._set_status(self.Status.SHUTTING_DOWN)
|
|
362
|
+
self.on_shutting_down()
|
|
361
363
|
|
|
364
|
+
shutting_down_time = time.time()
|
|
362
365
|
try:
|
|
363
366
|
self._shutdown()
|
|
364
|
-
self.on_shutdown()
|
|
367
|
+
self.on_shutdown(duration=time.time() - shutting_down_time)
|
|
365
368
|
except BaseException as e: # pylint: disable=broad-except
|
|
366
|
-
self.on_shutdown(error=e)
|
|
369
|
+
self.on_shutdown(duration=time.time() - shutting_down_time, error=e)
|
|
367
370
|
raise e
|
|
368
371
|
|
|
369
372
|
#
|
|
@@ -412,11 +415,11 @@ class BaseEnvironment(interface.Environment):
|
|
|
412
415
|
else:
|
|
413
416
|
try:
|
|
414
417
|
sandbox = self._bring_up_sandbox(
|
|
415
|
-
sandbox_id=
|
|
418
|
+
sandbox_id=f'{self._increment_sandbox_id()}:0',
|
|
419
|
+
set_acquired=True,
|
|
416
420
|
)
|
|
417
421
|
# Append is atomic and does not require locking.
|
|
418
422
|
self._sandbox_pool.append(sandbox)
|
|
419
|
-
self._offline_start_time = None
|
|
420
423
|
return sandbox
|
|
421
424
|
except (
|
|
422
425
|
interface.EnvironmentError, interface.SandboxStateError
|
|
@@ -429,18 +432,28 @@ class BaseEnvironment(interface.Environment):
|
|
|
429
432
|
set_acquired: bool = False,
|
|
430
433
|
) -> base_sandbox.BaseSandbox:
|
|
431
434
|
"""Brings up a new sandbox."""
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
sandbox.
|
|
443
|
-
|
|
435
|
+
env_error = None
|
|
436
|
+
try:
|
|
437
|
+
sandbox = self._create_sandbox(
|
|
438
|
+
sandbox_id=sandbox_id,
|
|
439
|
+
reusable=self.enable_pooling,
|
|
440
|
+
proactive_session_setup=self.proactive_session_setup,
|
|
441
|
+
keepalive_interval=self.sandbox_keepalive_interval,
|
|
442
|
+
)
|
|
443
|
+
for handler in self.event_handlers:
|
|
444
|
+
sandbox.add_event_handler(handler)
|
|
445
|
+
sandbox.start()
|
|
446
|
+
if set_acquired:
|
|
447
|
+
sandbox.set_acquired()
|
|
448
|
+
return sandbox
|
|
449
|
+
except (interface.EnvironmentError, interface.SandboxStateError) as e:
|
|
450
|
+
env_error = e
|
|
451
|
+
raise e
|
|
452
|
+
finally:
|
|
453
|
+
if env_error is None:
|
|
454
|
+
self._offline_start_time = None
|
|
455
|
+
elif self._offline_start_time is None:
|
|
456
|
+
self._offline_start_time = time.time()
|
|
444
457
|
|
|
445
458
|
def _bring_up_sandbox_with_retry(
|
|
446
459
|
self,
|
|
@@ -483,8 +496,6 @@ class BaseEnvironment(interface.Environment):
|
|
|
483
496
|
shutdown_env_upon_outage: bool = True
|
|
484
497
|
):
|
|
485
498
|
"""Raises error if the grace period has passed or wait for retry."""
|
|
486
|
-
if self._offline_start_time is None:
|
|
487
|
-
self._offline_start_time = time.time()
|
|
488
499
|
if self.offline_duration > self.outage_grace_period:
|
|
489
500
|
if shutdown_env_upon_outage:
|
|
490
501
|
self.shutdown()
|
|
@@ -502,39 +513,47 @@ class BaseEnvironment(interface.Environment):
|
|
|
502
513
|
"""Housekeeping loop for the environment."""
|
|
503
514
|
while self._status not in (self.Status.SHUTTING_DOWN, self.Status.OFFLINE):
|
|
504
515
|
housekeep_start_time = time.time()
|
|
516
|
+
|
|
517
|
+
is_online = True
|
|
505
518
|
dead_pool_indices = [
|
|
506
519
|
i for i, s in enumerate(self._sandbox_pool)
|
|
507
520
|
if s.status == interface.Sandbox.Status.OFFLINE
|
|
508
521
|
]
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
522
|
+
replaced_indices = []
|
|
523
|
+
|
|
524
|
+
if dead_pool_indices:
|
|
525
|
+
replaced_indices = self._replace_dead_sandboxes(dead_pool_indices)
|
|
526
|
+
if not replaced_indices:
|
|
527
|
+
is_online = self.offline_duration < self.outage_grace_period
|
|
528
|
+
|
|
529
|
+
self._housekeep_counter += 1
|
|
530
|
+
duration = time.time() - housekeep_start_time
|
|
531
|
+
kwargs = dict(
|
|
532
|
+
dead_pool_indices=dead_pool_indices,
|
|
533
|
+
replaced_indices=replaced_indices,
|
|
534
|
+
offline_duration=self.offline_duration,
|
|
535
|
+
)
|
|
536
|
+
if is_online:
|
|
537
|
+
self.on_housekeep(duration, **kwargs)
|
|
538
|
+
time.sleep(self.housekeep_interval)
|
|
539
|
+
else:
|
|
512
540
|
self.shutdown()
|
|
513
|
-
self._housekeep_counter += 1
|
|
514
541
|
self.on_housekeep(
|
|
515
|
-
|
|
542
|
+
duration,
|
|
516
543
|
interface.EnvironmentOutageError(
|
|
517
|
-
environment=self,
|
|
518
|
-
|
|
519
|
-
|
|
544
|
+
environment=self, offline_duration=self.offline_duration
|
|
545
|
+
),
|
|
546
|
+
**kwargs
|
|
520
547
|
)
|
|
521
|
-
break
|
|
522
|
-
self._housekeep_counter += 1
|
|
523
|
-
self.on_housekeep(time.time() - housekeep_start_time)
|
|
524
|
-
time.sleep(self.housekeep_interval)
|
|
525
548
|
|
|
526
|
-
def _replace_dead_sandboxes(self, dead_pool_indices: list[int]) ->
|
|
549
|
+
def _replace_dead_sandboxes(self, dead_pool_indices: list[int]) -> list[int]:
|
|
527
550
|
"""Replaces a dead sandbox with a new one.
|
|
528
551
|
|
|
529
552
|
Args:
|
|
530
553
|
dead_pool_indices: The indices of the dead sandboxes to replace.
|
|
531
554
|
|
|
532
555
|
Returns:
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
Raises:
|
|
536
|
-
interface.EnvironmentOutageError: If the XBox sandboxes cannot be created
|
|
537
|
-
within the wait time specified by `xbox_outage_grace_period`.
|
|
556
|
+
Successfully replaced indices.
|
|
538
557
|
"""
|
|
539
558
|
pg.logging.warning(
|
|
540
559
|
'[%s]: %s maintenance: '
|
|
@@ -544,26 +563,42 @@ class BaseEnvironment(interface.Environment):
|
|
|
544
563
|
len(dead_pool_indices),
|
|
545
564
|
)
|
|
546
565
|
def _replace(i: int):
|
|
547
|
-
self._sandbox_pool[i]
|
|
548
|
-
|
|
549
|
-
)
|
|
566
|
+
generation = int(self._sandbox_pool[i].id.sandbox_id.split(':')[1])
|
|
567
|
+
self._sandbox_pool[i] = self._bring_up_sandbox(f'{i}:{generation + 1}')
|
|
550
568
|
|
|
551
569
|
# TODO(daiyip): Consider to loose the condition to allow some dead
|
|
552
570
|
# sandboxes to be replaced successfully.
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
571
|
+
replaced_indices = []
|
|
572
|
+
for index, _, error in lf.concurrent_map(
|
|
573
|
+
_replace, dead_pool_indices,
|
|
574
|
+
max_workers=min(
|
|
575
|
+
self.pool_operation_max_parallelism,
|
|
576
|
+
len(dead_pool_indices)
|
|
577
|
+
),
|
|
578
|
+
):
|
|
579
|
+
if error is None:
|
|
580
|
+
replaced_indices.append(index)
|
|
581
|
+
|
|
582
|
+
pg.logging.warning(
|
|
583
|
+
'[%s]: %s maintenance: '
|
|
584
|
+
'%d/%d dead sandbox(es) have been replaced with new ones. (slots=%s)',
|
|
585
|
+
self.id,
|
|
586
|
+
self.__class__.__name__,
|
|
587
|
+
len(replaced_indices),
|
|
588
|
+
len(dead_pool_indices),
|
|
589
|
+
replaced_indices
|
|
590
|
+
)
|
|
591
|
+
return replaced_indices
|
|
562
592
|
|
|
563
593
|
#
|
|
564
594
|
# Event handlers subclasses can override.
|
|
565
595
|
#
|
|
566
596
|
|
|
597
|
+
def on_starting(self) -> None:
|
|
598
|
+
"""Called when the environment is getting started."""
|
|
599
|
+
for handler in self.event_handlers:
|
|
600
|
+
handler.on_environment_starting(self)
|
|
601
|
+
|
|
567
602
|
def on_start(
|
|
568
603
|
self,
|
|
569
604
|
duration: float, error: BaseException | None = None
|
|
@@ -575,15 +610,26 @@ class BaseEnvironment(interface.Environment):
|
|
|
575
610
|
def on_housekeep(
|
|
576
611
|
self,
|
|
577
612
|
duration: float,
|
|
578
|
-
error: BaseException | None = None
|
|
613
|
+
error: BaseException | None = None,
|
|
614
|
+
**kwargs
|
|
579
615
|
) -> None:
|
|
580
616
|
"""Called when the environment finishes a round of housekeeping."""
|
|
581
617
|
housekeep_counter = self.housekeep_counter
|
|
582
618
|
for handler in self.event_handlers:
|
|
583
|
-
handler.on_environment_housekeep(
|
|
619
|
+
handler.on_environment_housekeep(
|
|
620
|
+
self, housekeep_counter, duration, error, **kwargs
|
|
621
|
+
)
|
|
584
622
|
|
|
585
|
-
def
|
|
623
|
+
def on_shutting_down(self) -> None:
|
|
624
|
+
"""Called when the environment is shutting down."""
|
|
625
|
+
for handler in self.event_handlers:
|
|
626
|
+
handler.on_environment_shutting_down(self, self.offline_duration)
|
|
627
|
+
|
|
628
|
+
def on_shutdown(
|
|
629
|
+
self,
|
|
630
|
+
duration: float,
|
|
631
|
+
error: BaseException | None = None) -> None:
|
|
586
632
|
"""Called when the environment is shutdown."""
|
|
587
633
|
lifetime = (time.time() - self.start_time) if self.start_time else 0.0
|
|
588
634
|
for handler in self.event_handlers:
|
|
589
|
-
handler.on_environment_shutdown(self, lifetime, error)
|
|
635
|
+
handler.on_environment_shutdown(self, duration, lifetime, error)
|
langfun/env/base_feature.py
CHANGED
|
@@ -186,11 +186,12 @@ class BaseFeature(interface.Feature):
|
|
|
186
186
|
def on_housekeep(
|
|
187
187
|
self,
|
|
188
188
|
duration: float,
|
|
189
|
-
error: BaseException | None = None
|
|
189
|
+
error: BaseException | None = None,
|
|
190
|
+
**kwargs
|
|
190
191
|
) -> None:
|
|
191
192
|
"""Called when the feature has done housekeeping."""
|
|
192
193
|
self.sandbox.on_feature_housekeep(
|
|
193
|
-
self, self._housekeep_counter, duration, error
|
|
194
|
+
self, self._housekeep_counter, duration, error, **kwargs
|
|
194
195
|
)
|
|
195
196
|
|
|
196
197
|
def on_setup_session(
|
langfun/env/base_sandbox.py
CHANGED
|
@@ -418,6 +418,7 @@ class BaseSandbox(interface.Sandbox):
|
|
|
418
418
|
self.end_session(shutdown_sandbox=True)
|
|
419
419
|
return
|
|
420
420
|
|
|
421
|
+
shutting_down_time = time.time()
|
|
421
422
|
self._set_status(interface.Sandbox.Status.SHUTTING_DOWN)
|
|
422
423
|
|
|
423
424
|
if (self._housekeep_thread is not None
|
|
@@ -429,7 +430,10 @@ class BaseSandbox(interface.Sandbox):
|
|
|
429
430
|
try:
|
|
430
431
|
self._shutdown()
|
|
431
432
|
self._set_status(interface.Sandbox.Status.OFFLINE)
|
|
432
|
-
self.on_shutdown(
|
|
433
|
+
self.on_shutdown(
|
|
434
|
+
duration=time.time() - shutting_down_time,
|
|
435
|
+
error=teardown_error
|
|
436
|
+
)
|
|
433
437
|
shutdown_error = None
|
|
434
438
|
except BaseException as e: # pylint: disable=broad-except
|
|
435
439
|
shutdown_error = e
|
|
@@ -439,7 +443,10 @@ class BaseSandbox(interface.Sandbox):
|
|
|
439
443
|
'[%s]: Sandbox shutdown with error: %s',
|
|
440
444
|
self.id, e
|
|
441
445
|
)
|
|
442
|
-
self.on_shutdown(
|
|
446
|
+
self.on_shutdown(
|
|
447
|
+
duration=time.time() - shutting_down_time,
|
|
448
|
+
error=teardown_error or shutdown_error
|
|
449
|
+
)
|
|
443
450
|
|
|
444
451
|
# We raise non-state errors to the user following timely order, so the user
|
|
445
452
|
# code could be surfaced and handled properly.
|
|
@@ -591,6 +598,7 @@ class BaseSandbox(interface.Sandbox):
|
|
|
591
598
|
# Set sandbox status to EXITING_SESSION to avoid re-entry.
|
|
592
599
|
self._set_status(self.Status.EXITING_SESSION)
|
|
593
600
|
shutdown_sandbox = shutdown_sandbox or not self.reusable
|
|
601
|
+
ending_time = time.time()
|
|
594
602
|
|
|
595
603
|
# Teardown features for the current session.
|
|
596
604
|
end_session_error = self._end_session()
|
|
@@ -617,7 +625,9 @@ class BaseSandbox(interface.Sandbox):
|
|
|
617
625
|
self.shutdown()
|
|
618
626
|
|
|
619
627
|
# End session before setting up the next session.
|
|
620
|
-
self.on_session_end(
|
|
628
|
+
self.on_session_end(
|
|
629
|
+
previous_session_id, duration=time.time() - ending_time
|
|
630
|
+
)
|
|
621
631
|
|
|
622
632
|
# Mark the sandbox as setting up to prevent it from being acquired by
|
|
623
633
|
# other threads.
|
|
@@ -628,7 +638,9 @@ class BaseSandbox(interface.Sandbox):
|
|
|
628
638
|
threading.Thread(target=_setup_next_session).start()
|
|
629
639
|
else:
|
|
630
640
|
# End session before reporting sandbox status change.
|
|
631
|
-
self.on_session_end(
|
|
641
|
+
self.on_session_end(
|
|
642
|
+
previous_session_id, duration=time.time() - ending_time
|
|
643
|
+
)
|
|
632
644
|
|
|
633
645
|
# If shutdown is requested, mark the sandbox as acquired to prevent it
|
|
634
646
|
# from being acquired by other threads.
|
|
@@ -639,7 +651,11 @@ class BaseSandbox(interface.Sandbox):
|
|
|
639
651
|
|
|
640
652
|
# Otherwise, shutdown the sandbox.
|
|
641
653
|
else:
|
|
642
|
-
self.on_session_end(
|
|
654
|
+
self.on_session_end(
|
|
655
|
+
previous_session_id,
|
|
656
|
+
duration=time.time() - ending_time,
|
|
657
|
+
error=self.state_errors[0]
|
|
658
|
+
)
|
|
643
659
|
self._set_status(interface.Sandbox.Status.ACQUIRED)
|
|
644
660
|
shutdown_sandbox = True
|
|
645
661
|
|
|
@@ -690,7 +706,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
690
706
|
while self._status not in (self.Status.SHUTTING_DOWN, self.Status.OFFLINE):
|
|
691
707
|
housekeep_start = time.time()
|
|
692
708
|
if self.keepalive_interval is not None:
|
|
693
|
-
|
|
694
709
|
if time.time() - last_ping > self.keepalive_interval:
|
|
695
710
|
try:
|
|
696
711
|
self.ping()
|
|
@@ -762,25 +777,32 @@ class BaseSandbox(interface.Sandbox):
|
|
|
762
777
|
time.time() - self._status_start_time
|
|
763
778
|
)
|
|
764
779
|
|
|
765
|
-
def on_shutdown(
|
|
780
|
+
def on_shutdown(
|
|
781
|
+
self,
|
|
782
|
+
duration: float,
|
|
783
|
+
error: BaseException | None = None
|
|
784
|
+
) -> None:
|
|
766
785
|
"""Called when the sandbox is shutdown."""
|
|
767
786
|
if self._start_time is None:
|
|
768
787
|
lifetime = 0.0
|
|
769
788
|
else:
|
|
770
789
|
lifetime = time.time() - self._start_time
|
|
771
790
|
for handler in self._event_handlers:
|
|
772
|
-
handler.on_sandbox_shutdown(
|
|
791
|
+
handler.on_sandbox_shutdown(
|
|
792
|
+
self.environment, self, duration, lifetime, error
|
|
793
|
+
)
|
|
773
794
|
|
|
774
795
|
def on_housekeep(
|
|
775
796
|
self,
|
|
776
797
|
duration: float,
|
|
777
|
-
error: BaseException | None = None
|
|
798
|
+
error: BaseException | None = None,
|
|
799
|
+
**kwargs
|
|
778
800
|
) -> None:
|
|
779
801
|
"""Called when the sandbox finishes a round of housekeeping."""
|
|
780
802
|
counter = self._housekeep_counter
|
|
781
803
|
for handler in self._event_handlers:
|
|
782
804
|
handler.on_sandbox_housekeep(
|
|
783
|
-
self.environment, self, counter, duration, error
|
|
805
|
+
self.environment, self, counter, duration, error, **kwargs
|
|
784
806
|
)
|
|
785
807
|
|
|
786
808
|
def on_feature_setup(
|
|
@@ -880,13 +902,14 @@ class BaseSandbox(interface.Sandbox):
|
|
|
880
902
|
def on_session_end(
|
|
881
903
|
self,
|
|
882
904
|
session_id: str,
|
|
905
|
+
duration: float,
|
|
883
906
|
error: BaseException | None = None
|
|
884
907
|
) -> None:
|
|
885
908
|
"""Called when the user session ends."""
|
|
886
909
|
lifetime = time.time() - self._session_start_time
|
|
887
910
|
for handler in self._event_handlers:
|
|
888
911
|
handler.on_session_end(
|
|
889
|
-
self.environment, self, session_id, lifetime, error
|
|
912
|
+
self.environment, self, session_id, duration, lifetime, error
|
|
890
913
|
)
|
|
891
914
|
|
|
892
915
|
|