opentui(phase3): launcher integration — HERMES_TUI_ENGINE dual-engine
hermes --tui launches the native OpenTUI engine (Bun) when HERMES_TUI_ENGINE=opentui (env) or display.tui_engine=opentui (config); Ink stays the default and the shipping path is untouched. - _resolve_tui_engine() (env > config > ink); refuses opentui on Windows/Termux (no Bun) -> falls back to ink with a notice. - _make_opentui_argv() -> [bun, src/entry.real.tsx] (no build step). - _bun_bin() with HERMES_BUN override. - Branch at top of _make_tui_argv BEFORE _ensure_tui_node (Bun-only host must not bootstrap Node). - Gate _launch_tui NODE_OPTIONS/--max-old-space-size on engine==ink (Bun is JSC; the V8 flag errors/ignores). Verified end-to-end via tmux: real hermes --tui -> Bun -> OpenTUI -> real Python gateway streamed a real reply. No-flag default still ink.
This commit is contained in:
+5
-7
@@ -1,16 +1,14 @@
|
||||
---
|
||||
sidebar_position: 15
|
||||
title: "Automation Blueprints"
|
||||
description: "Ready-to-use automation blueprints — scheduled tasks, GitHub event triggers, API webhooks, and multi-skill workflows"
|
||||
title: "Automation Templates"
|
||||
description: "Ready-to-use automation recipes — scheduled tasks, GitHub event triggers, API webhooks, and multi-skill workflows"
|
||||
---
|
||||
|
||||
# Automation Blueprints
|
||||
# Automation Templates
|
||||
|
||||
Copy-paste blueprints for common automation patterns. Each blueprint uses Hermes's built-in [cron scheduler](/user-guide/features/cron) for time-based triggers and [webhook platform](/user-guide/messaging/webhooks) for event-driven triggers.
|
||||
Copy-paste recipes for common automation patterns. Each template uses Hermes's built-in [cron scheduler](/user-guide/features/cron) for time-based triggers and [webhook platform](/user-guide/messaging/webhooks) for event-driven triggers.
|
||||
|
||||
Every blueprint works with **any model** — not locked to a single provider.
|
||||
|
||||
For parameterized blueprints with forms instead of cron syntax, see the [Automation Blueprints Catalog](/reference/automation-blueprints-catalog).
|
||||
Every template works with **any model** — not locked to a single provider.
|
||||
|
||||
:::tip Three Trigger Types
|
||||
| Trigger | How | Tool |
|
||||
@@ -488,53 +488,6 @@ When `security.allow_lazy_installs: false` is set globally, `ensure()` raises `F
|
||||
|
||||
|
||||
|
||||
### Thread-safe lazy singletons
|
||||
|
||||
Plugins often cache an expensive object — an SDK client, an HTTP session, a connection pool — in a module-level variable built on first use:
|
||||
|
||||
```python
|
||||
_client = None
|
||||
|
||||
def get_client():
|
||||
global _client
|
||||
if _client is not None:
|
||||
return _client
|
||||
_client = ExpensiveClient(...) # ← TOCTOU race
|
||||
return _client
|
||||
```
|
||||
|
||||
This is a footgun. Hermes runs multiple threads in one process (delegated tool calls, background workers, the self-improvement fork), so two threads can hit `get_client()` before `_client` is set, **both** pass the `is not None` check, **both** run the expensive build, and the second write clobbers the first — leaking whatever resource the loser opened (connection, file handle, background thread).
|
||||
|
||||
Don't hand-roll the lock. Use the helpers in `plugins/plugin_utils.py`:
|
||||
|
||||
```python
|
||||
from plugins.plugin_utils import lazy_singleton, SingletonSlot
|
||||
|
||||
# Zero-arg accessor → decorate it:
|
||||
@lazy_singleton
|
||||
def get_client():
|
||||
return ExpensiveClient(load_config()) # runs exactly once
|
||||
|
||||
client = get_client() # safe across threads
|
||||
get_client.reset() # drop the instance (tests / teardown)
|
||||
|
||||
|
||||
# Accessor that takes a build argument → use a slot:
|
||||
_slot: SingletonSlot = SingletonSlot()
|
||||
|
||||
def get_client(config=None):
|
||||
return _slot.get(lambda: ExpensiveClient(resolve(config)))
|
||||
|
||||
def reset_client():
|
||||
_slot.reset()
|
||||
```
|
||||
|
||||
Both serialize concurrent first calls with double-checked locking and run the factory at most once. If the factory raises, nothing is cached and the next call retries. The honcho memory plugin (`plugins/memory/honcho/client.py`) is the reference consumer.
|
||||
|
||||
> Rule of thumb: any time you write `global _something` followed by a `is None` check and a build, reach for one of these instead.
|
||||
|
||||
|
||||
|
||||
### Conditional tool availability
|
||||
|
||||
For tools that depend on optional libraries:
|
||||
|
||||
Reference in New Issue
Block a user