Adds an input field for the DingTalk AI Card template ID under
Platform Settings, plus the matching DINGTALK_CARD_TEMPLATE_ID
env mapping so the value is persisted to the active profile and
forwarded to the hermes agent (which already supports AI Cards
via extra.card_template_id).
Closes#1035
The authStatus() controller previously returned the first users
username to unauthenticated clients. The frontend never used this
value — `fetchAuthStatus()` in LoginView.vue discards the return
value entirely. Remove the field to prevent username enumeration.
Changes:
- server: drop `username` from authStatus response body
- server: remove unused `findFirstUser` import
- client: remove `username` from AuthStatus interface
The hermes-agent CLI KawaiiSpinner sends decorative kaomoji text
like "(◕‿◕✿) pondering..." through thinking_callback for its TUI
widget. The bridge forwarded this as thinking.delta events, which
the frontend stored in the message reasoning field.
Over long conversations this contaminated the model's context:
_copy_reasoning_content_for_api promoted the kaomoji text to
reasoning_content, causing the LLM to reproduce kaomoji patterns
in a self-reinforcing degradation loop.
Fix: _make_thinking_callback unconditionally sends empty text.
thinking_callback is purely CLI spinner status — it has no place in
conversation history. Actual model reasoning (reasoning.delta) is
unaffected.
* fix(bridge): refresh terminal env from profile config on profile switch
Profile switching changes HERMES_HOME but the TERMINAL_* environment
variables (TERMINAL_ENV, TERMINAL_SSH_HOST, etc.) still point to the
root config's terminal settings set at gateway startup.
Add _refresh_terminal_env() that re-reads terminal config from the
active profile's config.yaml and sets the corresponding TERMINAL_* env
vars. Call it in:
- AgentPool.get_or_create(): when creating a session for a profile
- AgentPool._run_chat(): before agent execution, inside _profile_env
Errors are handled gracefully: YAML parse failures log to stderr,
terminal_tool cache invalidation failures are silently ignored, and
missing config files are skipped without error.
* fix(bridge): refresh terminal env in worker profile setup
_set_worker_profile_env() handles broker-spawned worker subprocesses
that are isolated per profile. The worker inherits TERMINAL_* env vars
from the broker (root config), and _profile_env() is a no-op in worker
mode, so terminal config was never refreshed for non-default profiles.
Adding _refresh_terminal_env() here means each worker subprocess reads
its own profile's config.yaml terminal section on startup, solving
profile-isolated terminal backends (e.g. SSH per profile).
* fix bridge terminal env refresh scope
* refresh worker profile env for new agents
* avoid bridge worker restart for channel config
* align config controller bridge restart tests
---------
Co-authored-by: GoldenFish123321 <goldfishx@gmail.com>
Co-authored-by: GoldenFishX <golden_fish@foxmail.com>
* fix: don't drop pending tool-call-marker prefix on tool.started/run.done
The `filterBridgeToolCallMarkupDelta` filter holds back any text that
ends in a partial prefix of `[Calling tool:` (i.e. `[`, `[C`, `[Ca`,
..., `[Calling tool`) so it can decide whether the buffered chars are
the start of a tool-call markup block to be hidden, or just regular
text to be released by the next delta.
The bug: that "release on next delta" assumption breaks at TWO points:
1. **On `tool.started`**: the next chunk for this assistant message is
the tool call itself, NOT a follow-up text delta. Buffered chars
sit there forever and nothing flushes them — they vanish silently
from the user-visible stream.
2. **On run completion**: the code did
`state.bridgePendingToolCallMarkup = undefined` directly, dropping
any pending chars without forwarding them.
Both cases produce the user-visible symptom of "abrupt cuts in text
right before/after tool calls (terminal, read_file, write_file...)" —
1 to 13 characters disappear at exactly the boundary where the model
was emitting natural prose that happened to end with `[`.
The fix introduces `flushPendingToolCallMarkup(state)` and calls it:
- In the `tool.started` branch BEFORE recording the tool call, so the
buffered chars are appended to the open assistant message and emitted
as a normal `message.delta` to the client.
- At run-done BEFORE clearing the buffer, same flush path.
This is a pure recovery patch — no change to the marker detection
logic itself. If the buffer turns out to actually be a real
`[Calling tool: ...]` marker that just hasn't completed yet, that
case is still caught by the existing `markerIdx >= 0` branch in the
filter on the next delta. The only behavioral change is that the
"orphan" cases (text that ends with `[` but never becomes a marker)
are no longer dropped.
* fix bridge marker flush persistence
---------
Co-authored-by: Paulo Cavallari <paulocavallari@users.noreply.github.com>
* feat: add session deep links for chats
* feat: add deep links for history and group chat
* Fix profile-aware session deep links
---------
Co-authored-by: Maxim Kirilyuk <werserk@inbox.ru>