fix tool approval flow (#773)
This commit is contained in:
@@ -210,6 +210,7 @@ const activeSessionSource = computed(() =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
const activeApproval = computed(() => chatStore.activePendingApproval);
|
const activeApproval = computed(() => chatStore.activePendingApproval);
|
||||||
|
const visibleApproval = computed(() => activeApproval.value);
|
||||||
|
|
||||||
function handleNewChat() {
|
function handleNewChat() {
|
||||||
chatStore.newChat();
|
chatStore.newChat();
|
||||||
@@ -835,44 +836,64 @@ async function handleWorkspaceConfirm() {
|
|||||||
|
|
||||||
<template v-if="currentMode === 'chat'">
|
<template v-if="currentMode === 'chat'">
|
||||||
<MessageList />
|
<MessageList />
|
||||||
<div v-if="activeApproval" class="approval-bar">
|
<div v-if="visibleApproval" class="approval-bar">
|
||||||
<div class="approval-main">
|
<div class="approval-icon" aria-hidden="true">
|
||||||
<div class="approval-title">Tool approval required</div>
|
<svg
|
||||||
<div class="approval-desc">{{ activeApproval.description }}</div>
|
width="18"
|
||||||
<code class="approval-command">{{ activeApproval.command }}</code>
|
height="18"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10" />
|
||||||
|
<path d="m9 12 2 2 4-4" />
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="approval-actions">
|
<div class="approval-content">
|
||||||
<NButton
|
<div class="approval-main">
|
||||||
v-if="activeApproval.choices.includes('once')"
|
<div class="approval-kicker">{{ t("chat.approvalKicker") }}</div>
|
||||||
size="small"
|
<div class="approval-title">{{ t("chat.approvalTitle") }}</div>
|
||||||
type="primary"
|
<div class="approval-desc">{{ visibleApproval.description }}</div>
|
||||||
@click="handleApproval('once')"
|
<code class="approval-command">{{ visibleApproval.command }}</code>
|
||||||
>
|
</div>
|
||||||
Allow once
|
<div class="approval-actions">
|
||||||
</NButton>
|
<NButton
|
||||||
<NButton
|
v-if="visibleApproval.choices.includes('once')"
|
||||||
v-if="activeApproval.choices.includes('session')"
|
size="small"
|
||||||
size="small"
|
type="primary"
|
||||||
@click="handleApproval('session')"
|
@click="handleApproval('once')"
|
||||||
>
|
>
|
||||||
Allow session
|
{{ t("chat.approvalAllowOnce") }}
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton
|
<NButton
|
||||||
v-if="activeApproval.choices.includes('always')"
|
v-if="visibleApproval.choices.includes('session')"
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleApproval('always')"
|
secondary
|
||||||
>
|
@click="handleApproval('session')"
|
||||||
Always
|
>
|
||||||
</NButton>
|
{{ t("chat.approvalAllowSession") }}
|
||||||
<NButton
|
</NButton>
|
||||||
v-if="activeApproval.choices.includes('deny')"
|
<NButton
|
||||||
size="small"
|
v-if="visibleApproval.choices.includes('always')"
|
||||||
type="error"
|
size="small"
|
||||||
ghost
|
secondary
|
||||||
@click="handleApproval('deny')"
|
@click="handleApproval('always')"
|
||||||
>
|
>
|
||||||
Deny
|
{{ t("chat.approvalAlways") }}
|
||||||
</NButton>
|
</NButton>
|
||||||
|
<NButton
|
||||||
|
v-if="visibleApproval.choices.includes('deny')"
|
||||||
|
size="small"
|
||||||
|
type="error"
|
||||||
|
secondary
|
||||||
|
@click="handleApproval('deny')"
|
||||||
|
>
|
||||||
|
{{ t("chat.approvalDeny") }}
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ChatInput />
|
<ChatInput />
|
||||||
@@ -1348,50 +1369,118 @@ async function handleWorkspaceConfirm() {
|
|||||||
|
|
||||||
.approval-bar {
|
.approval-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 12px;
|
gap: 10px;
|
||||||
padding: 10px 16px;
|
margin: 0 16px 12px;
|
||||||
border-top: 1px solid $border-color;
|
padding: 12px;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
border-radius: 8px;
|
||||||
background: $bg-card;
|
background: $bg-card;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.approval-main {
|
.approval-icon {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
flex: 0 0 32px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
background: rgba(var(--accent-primary-rgb), 0.12);
|
||||||
|
border: 1px solid rgba(var(--accent-primary-rgb), 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.approval-main {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-kicker {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.2;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
.approval-title {
|
.approval-title {
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
|
line-height: 1.3;
|
||||||
color: $text-primary;
|
color: $text-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.approval-desc {
|
.approval-desc {
|
||||||
margin-top: 2px;
|
margin-top: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
line-height: 1.45;
|
||||||
color: $text-secondary;
|
color: $text-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.approval-command {
|
.approval-command {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 6px;
|
margin-top: 8px;
|
||||||
max-height: 56px;
|
max-height: 96px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
font-size: 12px;
|
font-family: "SFMono-Regular", "Cascadia Code", "Roboto Mono", Consolas, monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.45;
|
||||||
color: $text-primary;
|
color: $text-primary;
|
||||||
background: $bg-secondary;
|
background: $bg-secondary;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid $border-color;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 6px 8px;
|
padding: 8px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.approval-actions {
|
.approval-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 6px;
|
gap: 8px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid $border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.approval-bar {
|
||||||
|
margin: 0 10px 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-icon {
|
||||||
|
flex-basis: 28px;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-actions :deep(.n-button) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.approval-bar {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-actions {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes rainbow-glow {
|
@keyframes rainbow-glow {
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ export default {
|
|||||||
historyScopeHint: 'Schreibgeschützte Hermes-Verlaufssitzungen, nach Quelle gruppiert.',
|
historyScopeHint: 'Schreibgeschützte Hermes-Verlaufssitzungen, nach Quelle gruppiert.',
|
||||||
noSessions: 'Keine Sitzungen',
|
noSessions: 'Keine Sitzungen',
|
||||||
newChat: 'Neuer Chat',
|
newChat: 'Neuer Chat',
|
||||||
|
approvalKicker: 'Terminal-Berechtigung',
|
||||||
|
approvalTitle: 'Befehl vor dem Ausführen prüfen',
|
||||||
|
approvalAllowOnce: 'Einmal erlauben',
|
||||||
|
approvalAllowSession: 'Sitzung erlauben',
|
||||||
|
approvalAlways: 'Immer',
|
||||||
|
approvalDeny: 'Ablehnen',
|
||||||
deleteSession: 'Diese Sitzung loschen?',
|
deleteSession: 'Diese Sitzung loschen?',
|
||||||
toggleBatchMode: 'Batch-Auswahl',
|
toggleBatchMode: 'Batch-Auswahl',
|
||||||
selectAll: 'Alle auswählen',
|
selectAll: 'Alle auswählen',
|
||||||
|
|||||||
@@ -178,6 +178,12 @@ export default {
|
|||||||
searchEnterHint: 'Enter to open · Esc to close',
|
searchEnterHint: 'Enter to open · Esc to close',
|
||||||
searchFailed: 'Failed to search sessions',
|
searchFailed: 'Failed to search sessions',
|
||||||
newChat: 'New Chat',
|
newChat: 'New Chat',
|
||||||
|
approvalKicker: 'Terminal permission',
|
||||||
|
approvalTitle: 'Review command before running',
|
||||||
|
approvalAllowOnce: 'Allow once',
|
||||||
|
approvalAllowSession: 'Allow session',
|
||||||
|
approvalAlways: 'Always',
|
||||||
|
approvalDeny: 'Deny',
|
||||||
newCliChat: 'New CLI',
|
newCliChat: 'New CLI',
|
||||||
deleteSession: 'Delete this session?',
|
deleteSession: 'Delete this session?',
|
||||||
sessionDeleted: 'Session deleted',
|
sessionDeleted: 'Session deleted',
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ export default {
|
|||||||
historyScopeHint: 'Sesiones del historial de Hermes, de solo lectura y agrupadas por origen.',
|
historyScopeHint: 'Sesiones del historial de Hermes, de solo lectura y agrupadas por origen.',
|
||||||
noSessions: 'Sin sesiones',
|
noSessions: 'Sin sesiones',
|
||||||
newChat: 'Nuevo chat',
|
newChat: 'Nuevo chat',
|
||||||
|
approvalKicker: 'Permiso de terminal',
|
||||||
|
approvalTitle: 'Revisar comando antes de ejecutar',
|
||||||
|
approvalAllowOnce: 'Permitir una vez',
|
||||||
|
approvalAllowSession: 'Permitir sesión',
|
||||||
|
approvalAlways: 'Siempre',
|
||||||
|
approvalDeny: 'Denegar',
|
||||||
deleteSession: 'Eliminar esta sesion?',
|
deleteSession: 'Eliminar esta sesion?',
|
||||||
toggleBatchMode: 'Selección por lotes',
|
toggleBatchMode: 'Selección por lotes',
|
||||||
selectAll: 'Seleccionar todo',
|
selectAll: 'Seleccionar todo',
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ export default {
|
|||||||
historyScopeHint: 'Sessions d’historique Hermes en lecture seule, regroupées par source.',
|
historyScopeHint: 'Sessions d’historique Hermes en lecture seule, regroupées par source.',
|
||||||
noSessions: 'Aucune session',
|
noSessions: 'Aucune session',
|
||||||
newChat: 'Nouvelle discussion',
|
newChat: 'Nouvelle discussion',
|
||||||
|
approvalKicker: 'Permission terminal',
|
||||||
|
approvalTitle: 'Vérifier la commande avant exécution',
|
||||||
|
approvalAllowOnce: 'Autoriser une fois',
|
||||||
|
approvalAllowSession: 'Autoriser la session',
|
||||||
|
approvalAlways: 'Toujours',
|
||||||
|
approvalDeny: 'Refuser',
|
||||||
deleteSession: 'Supprimer cette session ?',
|
deleteSession: 'Supprimer cette session ?',
|
||||||
toggleBatchMode: 'Sélection par lot',
|
toggleBatchMode: 'Sélection par lot',
|
||||||
selectAll: 'Tout sélectionner',
|
selectAll: 'Tout sélectionner',
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ export default {
|
|||||||
historyScopeHint: 'ソース別にグループ化された Hermes 履歴セッションを読み取り専用で表示します。',
|
historyScopeHint: 'ソース別にグループ化された Hermes 履歴セッションを読み取り専用で表示します。',
|
||||||
noSessions: 'セッションがありません',
|
noSessions: 'セッションがありません',
|
||||||
newChat: '新しいチャット',
|
newChat: '新しいチャット',
|
||||||
|
approvalKicker: 'ターミナル権限',
|
||||||
|
approvalTitle: '実行前にコマンドを確認',
|
||||||
|
approvalAllowOnce: '一度だけ許可',
|
||||||
|
approvalAllowSession: 'セッション中は許可',
|
||||||
|
approvalAlways: '常に許可',
|
||||||
|
approvalDeny: '拒否',
|
||||||
deleteSession: 'このセッションを削除しますか?',
|
deleteSession: 'このセッションを削除しますか?',
|
||||||
toggleBatchMode: '一括選択',
|
toggleBatchMode: '一括選択',
|
||||||
selectAll: 'すべて選択',
|
selectAll: 'すべて選択',
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ export default {
|
|||||||
historyScopeHint: '소스별로 그룹화된 Hermes 기록 세션을 읽기 전용으로 봅니다.',
|
historyScopeHint: '소스별로 그룹화된 Hermes 기록 세션을 읽기 전용으로 봅니다.',
|
||||||
noSessions: '세션 없음',
|
noSessions: '세션 없음',
|
||||||
newChat: '새 채팅',
|
newChat: '새 채팅',
|
||||||
|
approvalKicker: '터미널 권한',
|
||||||
|
approvalTitle: '실행 전에 명령 확인',
|
||||||
|
approvalAllowOnce: '한 번만 허용',
|
||||||
|
approvalAllowSession: '이 세션에서 허용',
|
||||||
|
approvalAlways: '항상 허용',
|
||||||
|
approvalDeny: '거부',
|
||||||
deleteSession: '이 세션을 삭제하시겠습니까?',
|
deleteSession: '이 세션을 삭제하시겠습니까?',
|
||||||
toggleBatchMode: '일괄 선택',
|
toggleBatchMode: '일괄 선택',
|
||||||
selectAll: '모두 선택',
|
selectAll: '모두 선택',
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ export default {
|
|||||||
historyScopeHint: 'Sessões do histórico Hermes somente leitura, agrupadas por origem.',
|
historyScopeHint: 'Sessões do histórico Hermes somente leitura, agrupadas por origem.',
|
||||||
noSessions: 'Sem sessoes',
|
noSessions: 'Sem sessoes',
|
||||||
newChat: 'Novo chat',
|
newChat: 'Novo chat',
|
||||||
|
approvalKicker: 'Permissão do terminal',
|
||||||
|
approvalTitle: 'Revisar comando antes de executar',
|
||||||
|
approvalAllowOnce: 'Permitir uma vez',
|
||||||
|
approvalAllowSession: 'Permitir sessão',
|
||||||
|
approvalAlways: 'Sempre',
|
||||||
|
approvalDeny: 'Negar',
|
||||||
deleteSession: 'Excluir esta sessao?',
|
deleteSession: 'Excluir esta sessao?',
|
||||||
toggleBatchMode: 'Seleção em lote',
|
toggleBatchMode: 'Seleção em lote',
|
||||||
selectAll: 'Selecionar tudo',
|
selectAll: 'Selecionar tudo',
|
||||||
|
|||||||
@@ -177,6 +177,12 @@ export default {
|
|||||||
searchEnterHint: 'Enter 開啟 · Esc 關閉',
|
searchEnterHint: 'Enter 開啟 · Esc 關閉',
|
||||||
searchFailed: '搜尋工作階段失敗',
|
searchFailed: '搜尋工作階段失敗',
|
||||||
newChat: '新增對話',
|
newChat: '新增對話',
|
||||||
|
approvalKicker: '終端授權',
|
||||||
|
approvalTitle: '執行前請確認命令',
|
||||||
|
approvalAllowOnce: '僅本次允許',
|
||||||
|
approvalAllowSession: '本工作階段允許',
|
||||||
|
approvalAlways: '永遠允許',
|
||||||
|
approvalDeny: '拒絕',
|
||||||
deleteSession: '確定刪除此工作階段?',
|
deleteSession: '確定刪除此工作階段?',
|
||||||
sessionDeleted: '工作階段已刪除',
|
sessionDeleted: '工作階段已刪除',
|
||||||
toggleBatchMode: '批次選取',
|
toggleBatchMode: '批次選取',
|
||||||
|
|||||||
@@ -178,6 +178,12 @@ export default {
|
|||||||
searchEnterHint: 'Enter 打开 · Esc 关闭',
|
searchEnterHint: 'Enter 打开 · Esc 关闭',
|
||||||
searchFailed: '搜索会话失败',
|
searchFailed: '搜索会话失败',
|
||||||
newChat: '新建对话',
|
newChat: '新建对话',
|
||||||
|
approvalKicker: '终端授权',
|
||||||
|
approvalTitle: '运行前请确认命令',
|
||||||
|
approvalAllowOnce: '仅本次允许',
|
||||||
|
approvalAllowSession: '本会话允许',
|
||||||
|
approvalAlways: '始终允许',
|
||||||
|
approvalDeny: '拒绝',
|
||||||
newCliChat: '新建 CLI',
|
newCliChat: '新建 CLI',
|
||||||
deleteSession: '确定删除此会话?',
|
deleteSession: '确定删除此会话?',
|
||||||
sessionDeleted: '会话已删除',
|
sessionDeleted: '会话已删除',
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ class AgentPool:
|
|||||||
self._run_lock = threading.Lock()
|
self._run_lock = threading.Lock()
|
||||||
self._db = SessionDbHolder()
|
self._db = SessionDbHolder()
|
||||||
self._approval_requests: dict[str, queue.Queue[str]] = {}
|
self._approval_requests: dict[str, queue.Queue[str]] = {}
|
||||||
|
self._gateway_approval_requests: dict[str, str] = {}
|
||||||
self._compression_requests: dict[str, queue.Queue[dict[str, Any]]] = {}
|
self._compression_requests: dict[str, queue.Queue[dict[str, Any]]] = {}
|
||||||
|
|
||||||
def get_or_create(
|
def get_or_create(
|
||||||
@@ -673,6 +674,24 @@ class AgentPool:
|
|||||||
|
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
|
def _gateway_approval_notify(self, session_id: str):
|
||||||
|
def callback(approval_data: dict[str, Any]) -> None:
|
||||||
|
approval_id = uuid.uuid4().hex
|
||||||
|
choices = ["once", "session", "always", "deny"]
|
||||||
|
with self._lock:
|
||||||
|
self._gateway_approval_requests[approval_id] = session_id
|
||||||
|
self._append_event(session_id, {
|
||||||
|
"event": "approval.requested",
|
||||||
|
"approval_id": approval_id,
|
||||||
|
"command": str(approval_data.get("command") or ""),
|
||||||
|
"description": str(approval_data.get("description") or ""),
|
||||||
|
"choices": choices,
|
||||||
|
"allow_permanent": True,
|
||||||
|
"timeout_ms": 300_000,
|
||||||
|
})
|
||||||
|
|
||||||
|
return callback
|
||||||
|
|
||||||
def _prepersist_user_message(
|
def _prepersist_user_message(
|
||||||
self,
|
self,
|
||||||
session: AgentSession,
|
session: AgentSession,
|
||||||
@@ -833,13 +852,16 @@ class AgentPool:
|
|||||||
previous_approval_callback = None
|
previous_approval_callback = None
|
||||||
previous_exec_ask = os.environ.get("HERMES_EXEC_ASK")
|
previous_exec_ask = os.environ.get("HERMES_EXEC_ASK")
|
||||||
approval_session_token = None
|
approval_session_token = None
|
||||||
|
registered_gateway_approval_session = None
|
||||||
try:
|
try:
|
||||||
from tools.terminal_tool import _get_approval_callback, set_approval_callback
|
from tools.terminal_tool import _get_approval_callback, set_approval_callback
|
||||||
from tools.approval import set_current_session_key
|
from tools.approval import register_gateway_notify, set_current_session_key
|
||||||
|
|
||||||
previous_approval_callback = _get_approval_callback()
|
previous_approval_callback = _get_approval_callback()
|
||||||
set_approval_callback(self._approval_callback(session.session_id))
|
set_approval_callback(self._approval_callback(session.session_id))
|
||||||
approval_session_token = set_current_session_key(session.session_id)
|
approval_session_token = set_current_session_key(session.session_id)
|
||||||
|
register_gateway_notify(session.session_id, self._gateway_approval_notify(session.session_id))
|
||||||
|
registered_gateway_approval_session = session.session_id
|
||||||
os.environ["HERMES_EXEC_ASK"] = "1"
|
os.environ["HERMES_EXEC_ASK"] = "1"
|
||||||
except Exception:
|
except Exception:
|
||||||
previous_approval_callback = None
|
previous_approval_callback = None
|
||||||
@@ -905,8 +927,10 @@ class AgentPool:
|
|||||||
pass
|
pass
|
||||||
if approval_session_token is not None:
|
if approval_session_token is not None:
|
||||||
try:
|
try:
|
||||||
from tools.approval import reset_current_session_key
|
from tools.approval import reset_current_session_key, unregister_gateway_notify
|
||||||
|
|
||||||
|
if registered_gateway_approval_session is not None:
|
||||||
|
unregister_gateway_notify(registered_gateway_approval_session)
|
||||||
reset_current_session_key(approval_session_token)
|
reset_current_session_key(approval_session_token)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -950,7 +974,22 @@ class AgentPool:
|
|||||||
with self._lock:
|
with self._lock:
|
||||||
response_queue = self._approval_requests.get(approval_id)
|
response_queue = self._approval_requests.get(approval_id)
|
||||||
if response_queue is None:
|
if response_queue is None:
|
||||||
return {"approval_id": approval_id, "resolved": False, "choice": cleaned}
|
with self._lock:
|
||||||
|
gateway_session_id = self._gateway_approval_requests.pop(approval_id, None)
|
||||||
|
if gateway_session_id is None:
|
||||||
|
return {"approval_id": approval_id, "resolved": False, "choice": cleaned}
|
||||||
|
try:
|
||||||
|
from tools.approval import resolve_gateway_approval
|
||||||
|
|
||||||
|
resolved = resolve_gateway_approval(gateway_session_id, cleaned) > 0
|
||||||
|
except Exception:
|
||||||
|
resolved = False
|
||||||
|
self._append_event(gateway_session_id, {
|
||||||
|
"event": "approval.resolved",
|
||||||
|
"approval_id": approval_id,
|
||||||
|
"choice": cleaned,
|
||||||
|
})
|
||||||
|
return {"approval_id": approval_id, "resolved": resolved, "choice": cleaned}
|
||||||
try:
|
try:
|
||||||
response_queue.put_nowait(cleaned)
|
response_queue.put_nowait(cleaned)
|
||||||
except queue.Full:
|
except queue.Full:
|
||||||
|
|||||||
Reference in New Issue
Block a user