diff --git a/AGENTS.md b/AGENTS.md index a31642ad09..5b2c944533 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1224,9 +1224,10 @@ detects process completion and triggers a new agent turn. Control verbosity of b messages with `display.background_process_notifications` in config.yaml (or `HERMES_BACKGROUND_NOTIFICATIONS` env var): -- `all` — running-output updates + final message (default) -- `result` — only the final completion message -- `error` — only the final message when exit code != 0 +- `concise` — one-line status message on completion; failures append a short output tail (default) +- `all` — running-output updates + final raw-output message +- `result` — only the final raw-output completion message +- `error` — only the final raw-output message when exit code != 0 - `off` — no watcher messages at all --- diff --git a/cli-config.yaml.example b/cli-config.yaml.example index 4ec0a24a40..ade82e57b9 100644 --- a/cli-config.yaml.example +++ b/cli-config.yaml.example @@ -1480,11 +1480,13 @@ display: # Background process notifications (gateway/messaging only). # Controls how chatty the process watcher is when you use # terminal(background=true, notify_on_complete=true) from Telegram/Discord/etc. + # concise: One-line status message on completion; failures include a short + # output tail (default) # off: No watcher messages at all - # result: Only the final completion message - # error: Only the final message when exit code != 0 - # all: Running output updates + final message (default) - background_process_notifications: all + # result: Only the final raw-output completion message + # error: Only the final raw-output message when exit code != 0 + # all: Running output updates + final raw-output message + background_process_notifications: concise # Play terminal bell when agent finishes a response. diff --git a/gateway/run.py b/gateway/run.py index 1c6573e5b0..f3f8602c90 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -3483,6 +3483,54 @@ def _parse_session_key(session_key: str) -> "dict | None": return None +def _shorten_command_for_display(command: str, limit: int = 80) -> str: + """Collapse a shell command onto one line and cap its length for display.""" + one_line = " ".join((command or "").split()) + if len(one_line) > limit: + one_line = one_line[: limit - 1] + "…" + return one_line + + +def _format_concise_process_notification( + session_id: str, + command: str, + exit_code, + output: str, + duration_seconds=None, +) -> str: + """One-line "pretty" completion message for the ``concise`` display mode. + + Success is a single status line; failure appends a short tail of output so + the user can see what went wrong without the full raw dump. The full + output always remains available to the agent via process(log/wait). + """ + ok = exit_code in {0, None} + icon = "✅" if ok else "❌" + verb = "finished" if ok else f"failed (exit {exit_code})" + parts = [f"{icon} Background task {verb}"] + short_cmd = _shorten_command_for_display(command) + if short_cmd: + parts.append(f"— `{short_cmd}`") + if isinstance(duration_seconds, (int, float)) and duration_seconds >= 0: + secs = int(duration_seconds) + if secs >= 3600: + dur = f"{secs // 3600}h {(secs % 3600) // 60}m" + elif secs >= 60: + dur = f"{secs // 60}m {secs % 60}s" + else: + dur = f"{secs}s" + parts.append(f"({dur})") + text = " ".join(parts) + if not ok and output: + tail_lines = [ln for ln in output.strip().splitlines() if ln.strip()][-5:] + tail = "\n".join(tail_lines) + if len(tail) > 500: + tail = tail[-500:] + if tail: + text += f"\n```\n{tail}\n```" + return text + + def _format_gateway_process_notification(evt: dict) -> "str | None": """Format a watch pattern event from completion_queue into a [IMPORTANT:] message.""" evt_type = evt.get("type", "completion") @@ -9052,9 +9100,11 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew """Load background process notification mode from config or env var. Modes: - - ``all`` — push running-output updates *and* the final message (default) - - ``result`` — only the final completion message (regardless of exit code) - - ``error`` — only the final message when exit code is non-zero + - ``concise`` — one-line status message on completion (default); + failures append a short output tail + - ``all`` — running-output updates *and* the final raw-output message + - ``result`` — only the final raw-output completion message + - ``error`` — only the final raw-output message when exit code is non-zero - ``off`` — no watcher messages at all """ mode = os.getenv("HERMES_BACKGROUND_NOTIFICATIONS", "") @@ -9065,14 +9115,14 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew mode = "off" elif raw not in {None, ""}: mode = str(raw) - mode = (mode or "all").strip().lower() - valid = {"all", "result", "error", "off"} + mode = (mode or "concise").strip().lower() + valid = {"concise", "all", "result", "error", "off"} if mode not in valid: logger.warning( - "Unknown background_process_notifications '%s', defaulting to 'all'", + "Unknown background_process_notifications '%s', defaulting to 'concise'", mode, ) - return "all" + return "concise" return mode @staticmethod @@ -23951,9 +24001,11 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew Auto-removes when the process exits or is killed. Notification mode (from ``display.background_process_notifications``): - - ``all`` — running-output updates + final message - - ``result`` — final completion message only - - ``error`` — final message only when exit code != 0 + - ``concise`` — one-line status message on completion (default); + failures append a short output tail + - ``all`` — running-output updates + final raw-output message + - ``result`` — final raw-output completion message only + - ``error`` — final raw-output message only when exit code != 0 - ``off`` — no messages at all """ from tools.process_registry import process_registry @@ -24071,7 +24123,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew break # Decide whether to notify based on mode should_notify = ( - notify_mode in {"all", "result"} + notify_mode in {"concise", "all", "result"} or (notify_mode == "error" and session.exit_code not in {0, None}) ) if should_notify: @@ -24081,10 +24133,26 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew new_output = redact_terminal_output( new_output, getattr(session, "command", "") or "" ) - message_text = ( - f"[Background process {session_id} finished with exit code {session.exit_code}~ " - f"Here's the final output:\n{new_output}]" - ) + if notify_mode == "concise": + _cmd_disp = _redact_gateway_user_facing_secrets( + getattr(session, "command", "") or "" + ) + _started = getattr(session, "started_at", None) + _dur = None + if isinstance(_started, (int, float)): + _dur = max(0.0, time.time() - _started) + message_text = _format_concise_process_notification( + session_id, + _cmd_disp, + session.exit_code, + new_output, + duration_seconds=_dur, + ) + else: + message_text = ( + f"[Background process {session_id} finished with exit code {session.exit_code}~ " + f"Here's the final output:\n{new_output}]" + ) adapter = None for p, a in self.adapters.items(): if p.value == platform_name: diff --git a/hermes_cli/config_defaults.py b/hermes_cli/config_defaults.py index 56936f1b61..278e026120 100644 --- a/hermes_cli/config_defaults.py +++ b/hermes_cli/config_defaults.py @@ -1193,6 +1193,15 @@ DEFAULT_CONFIG = { # "verbose" — include a compact content preview of what changed # Per-platform overrides via display.platforms..memory_notifications. "memory_notifications": "on", + # Gateway notifications when a terminal(background=true) process + # finishes: + # "concise" — one-line status message; failures append a short + # output tail (default) + # "all" — running-output updates + final raw-output message + # "result" — final raw-output message only + # "error" — final raw-output message only on non-zero exit + # "off" — no watcher messages at all + "background_process_notifications": "concise", "streaming": False, "timestamps": False, # Show timestamp on user and assistant labels "timestamp_format": "%H:%M", # strftime format for timestamps (e.g. "%b-%d %H:%M") @@ -3357,7 +3366,7 @@ DEFAULT_CONFIG = { }, # Config schema version - bump this when adding new required fields - "_config_version": 34, + "_config_version": 35, } # Optional environment variables that enhance functionality diff --git a/hermes_cli/config_migrations.py b/hermes_cli/config_migrations.py index ed79dd456d..beddf550ea 100644 --- a/hermes_cli/config_migrations.py +++ b/hermes_cli/config_migrations.py @@ -718,6 +718,42 @@ def _migrate_to_34(results: Dict[str, Any], quiet: bool) -> None: ) +def _migrate_to_35(results: Dict[str, Any], quiet: bool) -> None: + # ── Version 34 → 35: background process notifications → concise ── + # The old default mode 'all' pushed the raw output tail of every finished + # background process into the chat ("[Background process proc_x finished + # with exit code 0~ Here's the final output: ...]" walls). The new + # 'concise' mode renders a one-line status message instead (with a short + # output tail on failures) and is the new default. Move users still on + # 'all' — the old implicit default, almost never chosen on purpose — to + # 'concise'. Explicit non-default choices (result / error / off) are the + # user's own and are preserved. Users with the key unset inherit the new + # default automatically at read time (no write needed). + _c = _cfg() + read_raw_config = _c.read_raw_config + _persist_migration = _c._persist_migration + + config = read_raw_config() + raw_display = config.get("display") + if isinstance(raw_display, dict): + raw_val = raw_display.get("background_process_notifications") + if isinstance(raw_val, str) and raw_val.strip().lower() == "all": + raw_display["background_process_notifications"] = "concise" + config["display"] = raw_display + _persist_migration(config) + results["config_added"].append( + "display.background_process_notifications=concise (was: all)" + ) + if not quiet: + print( + " ✓ Background process notifications switched from 'all' to " + "'concise' — completions now show a one-line status message " + "instead of the raw output dump. Set " + "display.background_process_notifications: all to restore " + "the old behavior." + ) + + #: Registry of (target_version, migration_fn), strictly ascending. The driver #: applies every entry whose target version is greater than the on-disk #: version captured before the ladder started. Order matters: later steps may @@ -740,6 +776,7 @@ MIGRATIONS: Tuple[Tuple[int, Callable[[Dict[str, Any], bool], None]], ...] = ( (32, _migrate_to_32), (33, _migrate_to_33), (34, _migrate_to_34), + (35, _migrate_to_35), ) diff --git a/hermes_cli/tips.py b/hermes_cli/tips.py index 504f29115f..1729444fd4 100644 --- a/hermes_cli/tips.py +++ b/hermes_cli/tips.py @@ -388,7 +388,7 @@ TIPS = [ # --- Env Vars & Config Gates --- "display.tool_progress_command: true exposes /verbose on messaging platforms; it's CLI-only by default.", - 'HERMES_BACKGROUND_NOTIFICATIONS=result only pings when background tasks finish (vs all/error/off).', + 'HERMES_BACKGROUND_NOTIFICATIONS=result only pings when background tasks finish (vs concise/all/error/off).', 'HERMES_WRITE_SAFE_ROOT restricts write_file/patch to directory prefixes; multiple paths via os.pathsep (: or ;).', 'HERMES_IGNORE_RULES skips auto-injection of AGENTS.md, SOUL.md, .cursorrules, memory, and preloaded skills.', 'HERMES_ACCEPT_HOOKS auto-approves unseen shell hooks declared in config.yaml without a TTY prompt.', diff --git a/tests/gateway/test_background_process_notifications.py b/tests/gateway/test_background_process_notifications.py index f55c92dedd..87f42abaa0 100644 --- a/tests/gateway/test_background_process_notifications.py +++ b/tests/gateway/test_background_process_notifications.py @@ -72,11 +72,20 @@ def _watcher_dict(session_id="proc_test", thread_id=""): class TestLoadBackgroundNotificationsMode: - def test_defaults_to_all(self, monkeypatch, tmp_path): + def test_defaults_to_concise(self, monkeypatch, tmp_path): import gateway.run as gw monkeypatch.setattr(gw, "_hermes_home", tmp_path) monkeypatch.delenv("HERMES_BACKGROUND_NOTIFICATIONS", raising=False) - assert GatewayRunner._load_background_notifications_mode() == "all" + assert GatewayRunner._load_background_notifications_mode() == "concise" + + def test_unknown_mode_falls_back_to_concise(self, monkeypatch, tmp_path): + (tmp_path / "config.yaml").write_text( + "display:\n background_process_notifications: bogus\n" + ) + import gateway.run as gw + monkeypatch.setattr(gw, "_hermes_home", tmp_path) + monkeypatch.delenv("HERMES_BACKGROUND_NOTIFICATIONS", raising=False) + assert GatewayRunner._load_background_notifications_mode() == "concise" def test_reads_config_yaml(self, monkeypatch, tmp_path): (tmp_path / "config.yaml").write_text( @@ -258,6 +267,138 @@ async def test_inject_watch_notification_ignores_foreground_event_source(monkeyp assert synth_event.source.user_id == "proc_owner" +# --------------------------------------------------------------------------- +# concise mode — pretty one-liner instead of the raw output dump +# --------------------------------------------------------------------------- + + +class TestConciseFormatter: + + def test_success_is_one_line_without_output(self): + from gateway.run import _format_concise_process_notification + text = _format_concise_process_notification( + "proc_abc", "python3 scan_fleet.py --all", 0, + "1300\n1400\n1500\n{...huge json...}", + duration_seconds=754, + ) + assert text.startswith("✅ Background task finished") + assert "scan_fleet.py" in text + assert "12m 34s" in text + # The raw output must NOT appear on success + assert "1300" not in text + assert "\n" not in text + + def test_failure_appends_short_tail(self): + from gateway.run import _format_concise_process_notification + out = "\n".join(f"line{i}" for i in range(50)) + "\nTraceback: boom" + text = _format_concise_process_notification( + "proc_abc", "make build", 2, out, + ) + assert text.startswith("❌ Background task failed (exit 2)") + assert "Traceback: boom" in text + # Only a short tail, not the whole output + assert "line0" not in text + + def test_long_command_is_truncated(self): + from gateway.run import _format_concise_process_notification + text = _format_concise_process_notification( + "proc_abc", "x" * 300, 0, "", + ) + assert "…" in text + assert len(text) < 200 + + +@pytest.mark.asyncio +async def test_concise_mode_sends_pretty_message_not_raw_dump(monkeypatch, tmp_path): + """Default mode: a finished process produces the one-line status message, + never the '[Background process ... Here's the final output: ...]' wall.""" + import tools.process_registry as pr_module + + big_output = "\n".join(str(i * 100) for i in range(60)) + sessions = [SimpleNamespace( + output_buffer=big_output, exited=True, exit_code=0, + command="python3 scan.py", started_at=None, + )] + monkeypatch.setattr( + pr_module, "process_registry", _FakeRegistry(sessions, consumed=False) + ) + + async def _instant_sleep(*_a, **_kw): + pass + monkeypatch.setattr(asyncio, "sleep", _instant_sleep) + + runner = _build_runner(monkeypatch, tmp_path, "concise") + adapter = runner.adapters[Platform.TELEGRAM] + + await runner._run_process_watcher(_watcher_dict()) + + adapter.send.assert_awaited_once() + sent_text = adapter.send.await_args.args[1] + assert sent_text.startswith("✅ Background task finished") + assert "Here's the final output" not in sent_text + assert "5000" not in sent_text + + +@pytest.mark.asyncio +async def test_concise_mode_failure_includes_tail(monkeypatch, tmp_path): + import tools.process_registry as pr_module + + sessions = [SimpleNamespace( + output_buffer="starting\nfatal: repo not found\n", exited=True, + exit_code=128, command="git clone x", started_at=None, + )] + monkeypatch.setattr( + pr_module, "process_registry", _FakeRegistry(sessions, consumed=False) + ) + + async def _instant_sleep(*_a, **_kw): + pass + monkeypatch.setattr(asyncio, "sleep", _instant_sleep) + + runner = _build_runner(monkeypatch, tmp_path, "concise") + adapter = runner.adapters[Platform.TELEGRAM] + + await runner._run_process_watcher(_watcher_dict()) + + adapter.send.assert_awaited_once() + sent_text = adapter.send.await_args.args[1] + assert sent_text.startswith("❌ Background task failed (exit 128)") + assert "fatal: repo not found" in sent_text + + +@pytest.mark.asyncio +async def test_concise_mode_no_interim_output_updates(monkeypatch, tmp_path): + """concise never pushes 'is still running~ New output' interim updates.""" + import tools.process_registry as pr_module + + running = SimpleNamespace( + output_buffer="chunk one\n", exited=False, exit_code=None, + command="sleep 100", started_at=None, + ) + done = SimpleNamespace( + output_buffer="chunk one\nchunk two\n", exited=True, exit_code=0, + command="sleep 100", started_at=None, + ) + monkeypatch.setattr( + pr_module, "process_registry", _FakeRegistry([running, done], consumed=False) + ) + + async def _instant_sleep(*_a, **_kw): + pass + monkeypatch.setattr(asyncio, "sleep", _instant_sleep) + + runner = _build_runner(monkeypatch, tmp_path, "concise") + adapter = runner.adapters[Platform.TELEGRAM] + + await runner._run_process_watcher(_watcher_dict()) + + # Exactly one send: the final concise message; no interim updates. + adapter.send.assert_awaited_once() + sent_text = adapter.send.await_args.args[1] + assert "is still running" not in sent_text + assert sent_text.startswith("✅ Background task finished") + + # --------------------------------------------------------------------------- # _parse_session_key helper # --------------------------------------------------------------------------- diff --git a/tests/hermes_cli/test_config.py b/tests/hermes_cli/test_config.py index 9f43755c1c..54910db472 100644 --- a/tests/hermes_cli/test_config.py +++ b/tests/hermes_cli/test_config.py @@ -1313,6 +1313,54 @@ class TestDelegationCapUnificationMigration: assert "delegation" not in raw +class TestBackgroundNotificationsConciseMigration: + """v34 → v35: move users on the old implicit default 'all' to 'concise'.""" + + def _write(self, tmp_path, body): + (tmp_path / "config.yaml").write_text(body, encoding="utf-8") + + def test_all_becomes_concise(self, tmp_path): + with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}): + self._write( + tmp_path, + "_config_version: 34\n" + "display:\n" + " background_process_notifications: all\n", + ) + migrate_config(interactive=False, quiet=True) + raw = yaml.safe_load((tmp_path / "config.yaml").read_text()) + assert raw["display"]["background_process_notifications"] == "concise" + + def test_explicit_choices_preserved(self, tmp_path): + # NOTE: bare `off` in YAML parses as boolean False — the gateway mode + # loader maps False → "off", and the migration must leave it alone. + for written, expected in ( + ("off", False), ("result", "result"), + ("error", "error"), ("concise", "concise"), + ): + with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}): + self._write( + tmp_path, + "_config_version: 34\n" + "display:\n" + f" background_process_notifications: {written}\n", + ) + migrate_config(interactive=False, quiet=True) + raw = yaml.safe_load((tmp_path / "config.yaml").read_text()) + assert raw["display"]["background_process_notifications"] == expected + + def test_unset_key_is_not_materialized(self, tmp_path): + with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}): + self._write(tmp_path, "_config_version: 34\nmodel:\n provider: openrouter\n") + migrate_config(interactive=False, quiet=True) + raw = yaml.safe_load((tmp_path / "config.yaml").read_text()) + # Unset users inherit the new default at read time; no write needed. + assert "display" not in raw or "background_process_notifications" not in raw.get("display", {}) + + def test_default_config_is_concise(self): + assert DEFAULT_CONFIG["display"]["background_process_notifications"] == "concise" + + class TestConfigNormalizationDoesNotOverwriteUserValues: """Regression tests for #27354.""" diff --git a/website/docs/reference/environment-variables.md b/website/docs/reference/environment-variables.md index 7aa44c6eaf..8bdeb8b736 100644 --- a/website/docs/reference/environment-variables.md +++ b/website/docs/reference/environment-variables.md @@ -813,7 +813,7 @@ Advanced per-platform knobs for throttling the outbound message batcher. Most us | `HERMES_EXEC_ASK` | Enable execution approval prompts in gateway mode (`true`/`false`) | | `HERMES_ENABLE_PROJECT_PLUGINS` | Enable auto-discovery of repo-local plugins from `./.hermes/plugins/` for both the agent loader and the dashboard web server. Accepts the standard truthy set: `1` / `true` / `yes` / `on` (case-insensitive). Everything else — including `0`, `false`, `no`, `off`, and the empty string — is treated as **disabled** (default). Note: as of GHSA-5qr3-c538-wm9j (#29156) the dashboard web server refuses to auto-import a project plugin's Python `api` file even when this var is enabled — project plugins may extend the UI via static JS/CSS but their backend routes are only loaded when moved under `~/.hermes/plugins/`. | | `HERMES_PLUGINS_DEBUG` | `1`/`true` to surface verbose plugin-discovery logs on stderr — directories scanned, manifests parsed, skip reasons, and full tracebacks on parse or `register()` failure. Aimed at plugin authors. | -| `HERMES_BACKGROUND_NOTIFICATIONS` | Background process notification mode in gateway: `all` (default), `result`, `error`, `off` | +| `HERMES_BACKGROUND_NOTIFICATIONS` | Background process notification mode in gateway: `concise` (default), `all`, `result`, `error`, `off` | | `HERMES_EPHEMERAL_SYSTEM_PROMPT` | Ephemeral system prompt injected at API-call time (never persisted to sessions) | | `HERMES_PREFILL_MESSAGES_FILE` | Path to a JSON file of ephemeral prefill messages injected at API-call time. | | `HERMES_ALLOW_PRIVATE_URLS` | `true`/`false` — allow tools to fetch localhost/private-network URLs. Off by default in gateway mode. | diff --git a/website/docs/user-guide/messaging/index.md b/website/docs/user-guide/messaging/index.md index 61c47d5a42..fb6098e003 100644 --- a/website/docs/user-guide/messaging/index.md +++ b/website/docs/user-guide/messaging/index.md @@ -520,14 +520,15 @@ When the agent running a background session uses `terminal(background=true)` to ```yaml display: - background_process_notifications: all # all | result | error | off + background_process_notifications: concise # concise | all | result | error | off ``` | Mode | What you receive | |------|-----------------| -| `all` | Running-output updates **and** the final completion message (default) | -| `result` | Only the final completion message (regardless of exit code) | -| `error` | Only the final message when the exit code is non-zero | +| `concise` | One-line status message on completion; failures append a short output tail (default) | +| `all` | Running-output updates **and** the final raw-output message | +| `result` | Only the final raw-output completion message (regardless of exit code) | +| `error` | Only the final raw-output message when the exit code is non-zero | | `off` | No process watcher messages at all | You can also set this via environment variable: diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/environment-variables.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/environment-variables.md index 4b7f8fb1eb..69c7871a2a 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/environment-variables.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/environment-variables.md @@ -561,7 +561,7 @@ Graph 事件(Teams 会议、日历、聊天等)的入站变更通知监听 | `HERMES_EXEC_ASK` | 在 gateway 模式下启用执行审批提示(`true`/`false`) | | `HERMES_ENABLE_PROJECT_PLUGINS` | 为 agent 加载器和仪表板 Web 服务器启用从 `./.hermes/plugins/` 自动发现仓库本地插件。接受标准真值集:`1`/`true`/`yes`/`on`(不区分大小写)。其他所有值——包括 `0`、`false`、`no`、`off` 和空字符串——均视为**禁用**(默认)。注意:自 GHSA-5qr3-c538-wm9j(#29156)起,即使启用此变量,仪表板 Web 服务器也拒绝自动导入项目插件的 Python `api` 文件——项目插件可通过静态 JS/CSS 扩展 UI,但其后端路由仅在移至 `~/.hermes/plugins/` 后才会加载。 | | `HERMES_PLUGINS_DEBUG` | `1`/`true` 可在 stderr 上输出详细的插件发现日志——扫描的目录、解析的 manifest、跳过原因以及解析或 `register()` 失败时的完整回溯。面向插件作者。 | -| `HERMES_BACKGROUND_NOTIFICATIONS` | gateway 中后台进程通知模式:`all`(默认)、`result`、`error`、`off` | +| `HERMES_BACKGROUND_NOTIFICATIONS` | gateway 中后台进程通知模式:`concise`(默认)、`all`、`result`、`error`、`off` | | `HERMES_EPHEMERAL_SYSTEM_PROMPT` | 在 API 调用时注入的临时系统 prompt(永不持久化到会话) | | `HERMES_PREFILL_MESSAGES_FILE` | 包含在 API 调用时注入的临时预填消息的 JSON 文件路径。 | | `HERMES_ALLOW_PRIVATE_URLS` | `true`/`false`——允许工具获取 localhost/私有网络 URL。gateway 模式下默认关闭。 | diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/index.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/index.md index 446d42e92a..db2fdc6dfb 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/index.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/index.md @@ -342,14 +342,15 @@ Hermes 立即确认: ```yaml display: - background_process_notifications: all # all | result | error | off + background_process_notifications: concise # concise | all | result | error | off ``` | 模式 | 你收到的内容 | |------|-----------------| -| `all` | 运行输出更新**以及**最终完成消息(默认) | -| `result` | 仅最终完成消息(无论退出码) | -| `error` | 仅在退出码非零时的最终消息 | +| `concise` | 完成时的单行状态消息;失败时附加简短的输出尾部(默认) | +| `all` | 运行输出更新**以及**最终原始输出消息 | +| `result` | 仅最终原始输出完成消息(无论退出码) | +| `error` | 仅在退出码非零时的最终原始输出消息 | | `off` | 不接收任何进程监控消息 | 也可通过环境变量设置: