A terminal panel beside an agent chat
A real shell on the chat's own connection, opened and closed like the inspector and never beside it. The modes govern the model; what a person types is theirs, since they hold the credential and could open the same shell with an ssh client. The model cannot see the panel -- a button copies the output you choose into the composer. The session outlives the socket: closing the panel leaves a build running, and coming back reattaches with the scrollback. Two tabs share one shell and the smaller window decides the size. It ends on an idle timeout, on deleting the chat, on disabling, moving or deleting the connection, and on a restart -- which says why rather than quietly opening a fresh shell that has lost the working directory. The nginx template's `Connection ""` is right for SSE and fails every WebSocket handshake, so `location /` now uses a `map $http_upgrade`; update.sh grows a drift check for it, because the only symptom on a stale vhost is a panel that cannot connect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,9 +97,31 @@ def _agent_context(db: DBSession, user: User, chat: Chat | None) -> dict:
|
||||
(m, agent_policy.MODE_LABELS[m], agent_policy.MODE_HINTS[m])
|
||||
for m in agent_policy.MODES
|
||||
],
|
||||
"terminal_enabled": _terminal_enabled(db, user, chat, current),
|
||||
}
|
||||
|
||||
|
||||
def _terminal_enabled(db: DBSession, user: User, chat: Chat | None, profile) -> bool:
|
||||
"""Whether this chat can offer a shell of its own.
|
||||
|
||||
Every condition, not a subset: the button loads 280KB of terminal and opens
|
||||
a socket, so one that cannot work is worse than none. `ssh.available()` is
|
||||
in here because an instance that installed LLeMbas without the `ssh` extra
|
||||
would otherwise render a button whose only outcome is an error frame.
|
||||
"""
|
||||
from lembas.db.models import KIND_AGENT
|
||||
from lembas.services.agent import ssh as ssh_service
|
||||
|
||||
if chat is None or chat.kind != KIND_AGENT or profile is None:
|
||||
return False
|
||||
if not permissions.has(db, user, "agent.terminal"):
|
||||
return False
|
||||
values = settings_store.agents(db)
|
||||
if not values.get("enabled") or not values.get("terminal_enabled", True):
|
||||
return False
|
||||
return ssh_service.available() == ""
|
||||
|
||||
|
||||
def sidebar_context(db: DBSession, user: User) -> dict:
|
||||
"""Folder tree plus the chats that belong to no folder.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user