Shared response buffer backend
This commit is contained in:
@@ -1,183 +1,183 @@
|
||||
from threading import Thread, Event
|
||||
from typing import Callable, TypeAlias, TypedDict
|
||||
from .web_agent import WebAgent, LlmState
|
||||
|
||||
class AutoApproverConfig(TypedDict):
|
||||
context_enabled: bool
|
||||
response_enabled: bool
|
||||
context_timeout: float
|
||||
response_timeout: float
|
||||
llm_name: str
|
||||
|
||||
ConfigChangeHandler: TypeAlias = Callable[[AutoApproverConfig], None]
|
||||
|
||||
class AutoApprover:
|
||||
"""
|
||||
Handles automatic approvals for WebAgent states after configurable timeouts.
|
||||
"""
|
||||
|
||||
def __init__(self, agent: WebAgent):
|
||||
"""
|
||||
Initialize auto approver with a WebAgent instance.
|
||||
"""
|
||||
self.agent = agent
|
||||
self._llm_name = next(iter(agent.llms.keys()))
|
||||
self._context_timeout = 5.0
|
||||
self._response_timeout = 10.0
|
||||
self._context_enabled = False
|
||||
self._response_enabled = False
|
||||
self._stop_event = Event()
|
||||
self._context_thread: Thread | None = None
|
||||
self._response_thread: Thread | None = None
|
||||
self._config_change_handlers: list[ConfigChangeHandler] = []
|
||||
|
||||
self.agent.add_llm_change_handler(self._handle_llm_state_change)
|
||||
self.agent.add_context_change_handler(self._handle_context_change)
|
||||
|
||||
@property
|
||||
def config(self) -> AutoApproverConfig:
|
||||
return AutoApproverConfig(
|
||||
context_enabled=self._context_enabled,
|
||||
response_enabled=self._response_enabled,
|
||||
context_timeout=self._context_timeout,
|
||||
response_timeout=self._response_timeout,
|
||||
llm_name=self._llm_name
|
||||
)
|
||||
|
||||
def set_config(self, config: AutoApproverConfig) -> None:
|
||||
if config['llm_name'] not in self.agent.llms:
|
||||
raise ValueError(f"Unknown LLM: {config['llm_name']}")
|
||||
|
||||
notify_config_change = self._notify_config_change
|
||||
self._notify_config_change = lambda: None
|
||||
|
||||
try:
|
||||
self.context_enabled = False
|
||||
self.response_enabled = False
|
||||
|
||||
self.context_timeout = config['context_timeout']
|
||||
self.response_timeout = config['response_timeout']
|
||||
self.llm_name = config['llm_name']
|
||||
|
||||
self.context_enabled = config['context_enabled']
|
||||
self.response_enabled = config['response_enabled']
|
||||
finally:
|
||||
self._notify_config_change = notify_config_change
|
||||
self._notify_config_change()
|
||||
|
||||
def add_config_change_handler(self, handler: ConfigChangeHandler) -> None:
|
||||
self._config_change_handlers.append(handler)
|
||||
|
||||
def _notify_config_change(self) -> None:
|
||||
current_config = self.config
|
||||
for handler in self._config_change_handlers:
|
||||
handler(current_config)
|
||||
|
||||
@property
|
||||
def context_timeout(self) -> float:
|
||||
return self._context_timeout
|
||||
|
||||
@context_timeout.setter
|
||||
def context_timeout(self, timeout: float) -> None:
|
||||
if self._context_enabled:
|
||||
raise ValueError("Cannot change timeout while auto-approval is enabled")
|
||||
self._context_timeout = timeout
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def response_timeout(self) -> float:
|
||||
return self._response_timeout
|
||||
|
||||
@response_timeout.setter
|
||||
def response_timeout(self, timeout: float) -> None:
|
||||
if self._response_enabled:
|
||||
raise ValueError("Cannot change timeout while auto-approval is enabled")
|
||||
self._response_timeout = timeout
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def context_enabled(self) -> bool:
|
||||
return self._context_enabled
|
||||
|
||||
@context_enabled.setter
|
||||
def context_enabled(self, enabled: bool) -> None:
|
||||
if enabled == self._context_enabled:
|
||||
return
|
||||
self._context_enabled = enabled
|
||||
self._stop_context_thread()
|
||||
if enabled and self.agent.llms[self._llm_name] == LlmState.NO_OUTPUT:
|
||||
self._start_context_thread()
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def response_enabled(self) -> bool:
|
||||
return self._response_enabled
|
||||
|
||||
@response_enabled.setter
|
||||
def response_enabled(self, enabled: bool) -> None:
|
||||
if enabled == self._response_enabled:
|
||||
return
|
||||
self._response_enabled = enabled
|
||||
self._stop_response_thread()
|
||||
if enabled and self.agent.llms[self._llm_name] == LlmState.OUTPUT:
|
||||
self._start_response_thread()
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def llm_name(self) -> str:
|
||||
return self._llm_name
|
||||
|
||||
@llm_name.setter
|
||||
def llm_name(self, name: str) -> None:
|
||||
if name not in self.agent.llms:
|
||||
raise ValueError(f"Unknown LLM: {name}")
|
||||
self._llm_name = name
|
||||
self._notify_config_change()
|
||||
|
||||
def _handle_llm_state_change(self, llm_name: str, state: LlmState) -> None:
|
||||
if llm_name != self._llm_name:
|
||||
return
|
||||
|
||||
if state == LlmState.OUTPUT and self._response_enabled:
|
||||
self._start_response_thread()
|
||||
else:
|
||||
self._stop_response_thread()
|
||||
|
||||
def _handle_context_change(self, context: str, generated: bool) -> None:
|
||||
if generated and self._context_enabled:
|
||||
self._start_context_thread()
|
||||
else:
|
||||
self._stop_context_thread()
|
||||
|
||||
def _stop_context_thread(self) -> None:
|
||||
if self._context_thread:
|
||||
self._stop_event.set()
|
||||
self._context_thread = None
|
||||
self._stop_event.clear()
|
||||
|
||||
def _stop_response_thread(self) -> None:
|
||||
if self._response_thread:
|
||||
self._stop_event.set()
|
||||
self._response_thread = None
|
||||
self._stop_event.clear()
|
||||
|
||||
def _start_context_thread(self) -> None:
|
||||
self._context_thread = Thread(target=self._context_approval_thread)
|
||||
self._context_thread.start()
|
||||
|
||||
def _start_response_thread(self) -> None:
|
||||
self._response_thread = Thread(target=self._response_approval_thread)
|
||||
self._response_thread.start()
|
||||
|
||||
def _context_approval_thread(self) -> None:
|
||||
if self._stop_event.wait(self._context_timeout):
|
||||
return
|
||||
if self._context_enabled:
|
||||
self.agent.run_inference(self._llm_name)
|
||||
|
||||
def _response_approval_thread(self) -> None:
|
||||
if self._stop_event.wait(self._response_timeout):
|
||||
return
|
||||
if (self._response_enabled and
|
||||
self.agent.llms[self._llm_name] == LlmState.OUTPUT):
|
||||
self.agent.approve_response(self._llm_name, self.agent.get_output(self._llm_name))
|
||||
from threading import Thread, Event
|
||||
from typing import Callable, TypeAlias, TypedDict
|
||||
from .web_agent import WebAgent, LlmState
|
||||
|
||||
class AutoApproverConfig(TypedDict):
|
||||
context_enabled: bool
|
||||
response_enabled: bool
|
||||
context_timeout: float
|
||||
response_timeout: float
|
||||
llm_name: str
|
||||
|
||||
ConfigChangeHandler: TypeAlias = Callable[[AutoApproverConfig], None]
|
||||
|
||||
class AutoApprover:
|
||||
"""
|
||||
Handles automatic approvals for WebAgent states after configurable timeouts.
|
||||
"""
|
||||
|
||||
def __init__(self, agent: WebAgent):
|
||||
"""
|
||||
Initialize auto approver with a WebAgent instance.
|
||||
"""
|
||||
self.agent = agent
|
||||
self._llm_name = next(iter(agent.llms.keys()))
|
||||
self._context_timeout = 5.0
|
||||
self._response_timeout = 10.0
|
||||
self._context_enabled = False
|
||||
self._response_enabled = False
|
||||
self._stop_event = Event()
|
||||
self._context_thread: Thread | None = None
|
||||
self._response_thread: Thread | None = None
|
||||
self._config_change_handlers: list[ConfigChangeHandler] = []
|
||||
|
||||
self.agent.add_llm_change_handler(self._handle_llm_state_change)
|
||||
self.agent.add_context_change_handler(self._handle_context_change)
|
||||
|
||||
@property
|
||||
def config(self) -> AutoApproverConfig:
|
||||
return AutoApproverConfig(
|
||||
context_enabled=self._context_enabled,
|
||||
response_enabled=self._response_enabled,
|
||||
context_timeout=self._context_timeout,
|
||||
response_timeout=self._response_timeout,
|
||||
llm_name=self._llm_name
|
||||
)
|
||||
|
||||
def set_config(self, config: AutoApproverConfig) -> None:
|
||||
if config['llm_name'] not in self.agent.llms:
|
||||
raise ValueError(f"Unknown LLM: {config['llm_name']}")
|
||||
|
||||
notify_config_change = self._notify_config_change
|
||||
self._notify_config_change = lambda: None
|
||||
|
||||
try:
|
||||
self.context_enabled = False
|
||||
self.response_enabled = False
|
||||
|
||||
self.context_timeout = config['context_timeout']
|
||||
self.response_timeout = config['response_timeout']
|
||||
self.llm_name = config['llm_name']
|
||||
|
||||
self.context_enabled = config['context_enabled']
|
||||
self.response_enabled = config['response_enabled']
|
||||
finally:
|
||||
self._notify_config_change = notify_config_change
|
||||
self._notify_config_change()
|
||||
|
||||
def add_config_change_handler(self, handler: ConfigChangeHandler) -> None:
|
||||
self._config_change_handlers.append(handler)
|
||||
|
||||
def _notify_config_change(self) -> None:
|
||||
current_config = self.config
|
||||
for handler in self._config_change_handlers:
|
||||
handler(current_config)
|
||||
|
||||
@property
|
||||
def context_timeout(self) -> float:
|
||||
return self._context_timeout
|
||||
|
||||
@context_timeout.setter
|
||||
def context_timeout(self, timeout: float) -> None:
|
||||
if self._context_enabled:
|
||||
raise ValueError("Cannot change timeout while auto-approval is enabled")
|
||||
self._context_timeout = timeout
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def response_timeout(self) -> float:
|
||||
return self._response_timeout
|
||||
|
||||
@response_timeout.setter
|
||||
def response_timeout(self, timeout: float) -> None:
|
||||
if self._response_enabled:
|
||||
raise ValueError("Cannot change timeout while auto-approval is enabled")
|
||||
self._response_timeout = timeout
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def context_enabled(self) -> bool:
|
||||
return self._context_enabled
|
||||
|
||||
@context_enabled.setter
|
||||
def context_enabled(self, enabled: bool) -> None:
|
||||
if enabled == self._context_enabled:
|
||||
return
|
||||
self._context_enabled = enabled
|
||||
self._stop_context_thread()
|
||||
if enabled and self.agent.llms[self._llm_name] == LlmState.IDLE:
|
||||
self._start_context_thread()
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def response_enabled(self) -> bool:
|
||||
return self._response_enabled
|
||||
|
||||
@response_enabled.setter
|
||||
def response_enabled(self, enabled: bool) -> None:
|
||||
if enabled == self._response_enabled:
|
||||
return
|
||||
self._response_enabled = enabled
|
||||
self._stop_response_thread()
|
||||
if enabled and self.agent.llms[self._llm_name] == LlmState.IDLE:
|
||||
self._start_response_thread()
|
||||
self._notify_config_change()
|
||||
|
||||
@property
|
||||
def llm_name(self) -> str:
|
||||
return self._llm_name
|
||||
|
||||
@llm_name.setter
|
||||
def llm_name(self, name: str) -> None:
|
||||
if name not in self.agent.llms:
|
||||
raise ValueError(f"Unknown LLM: {name}")
|
||||
self._llm_name = name
|
||||
self._notify_config_change()
|
||||
|
||||
def _handle_llm_state_change(self, llm_name: str, state: LlmState) -> None:
|
||||
if llm_name != self._llm_name:
|
||||
return
|
||||
|
||||
if state == LlmState.IDLE and self._response_enabled:
|
||||
self._start_response_thread()
|
||||
else:
|
||||
self._stop_response_thread()
|
||||
|
||||
def _handle_context_change(self, context: str, generated: bool) -> None:
|
||||
if generated and self._context_enabled:
|
||||
self._start_context_thread()
|
||||
else:
|
||||
self._stop_context_thread()
|
||||
|
||||
def _stop_context_thread(self) -> None:
|
||||
if self._context_thread:
|
||||
self._stop_event.set()
|
||||
self._context_thread = None
|
||||
self._stop_event.clear()
|
||||
|
||||
def _stop_response_thread(self) -> None:
|
||||
if self._response_thread:
|
||||
self._stop_event.set()
|
||||
self._response_thread = None
|
||||
self._stop_event.clear()
|
||||
|
||||
def _start_context_thread(self) -> None:
|
||||
self._context_thread = Thread(target=self._context_approval_thread)
|
||||
self._context_thread.start()
|
||||
|
||||
def _start_response_thread(self) -> None:
|
||||
self._response_thread = Thread(target=self._response_approval_thread)
|
||||
self._response_thread.start()
|
||||
|
||||
def _context_approval_thread(self) -> None:
|
||||
if self._stop_event.wait(self._context_timeout):
|
||||
return
|
||||
if self._context_enabled:
|
||||
self.agent.run_inference(self._llm_name)
|
||||
|
||||
def _response_approval_thread(self) -> None:
|
||||
if self._stop_event.wait(self._response_timeout):
|
||||
return
|
||||
if (self._response_enabled and
|
||||
self.agent.llms[self._llm_name] == LlmState.IDLE):
|
||||
self.agent.approve_response(self._llm_name, self.agent.get_output(self._llm_name))
|
||||
|
||||
Reference in New Issue
Block a user