WIP tool approval flow frontend

This commit is contained in:
Nemo Godebski-Pedersen 2025-04-09 17:50:48 +01:00
parent e95a172235
commit 649c68a455
3 changed files with 38 additions and 7 deletions

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { ArrowDown, ArrowUp, RefreshRight, Check, DocumentCopy } from '@element-plus/icons-vue'
import { ArrowDown, ArrowUp, RefreshRight, Check, DocumentCopy, User } from '@element-plus/icons-vue'
import VueJsonPretty from 'vue-json-pretty';
import { ElMessage } from 'element-plus';
import 'vue-json-pretty/lib/styles.css';
@ -32,6 +32,11 @@ export default {
expanded: false,
}
},
mounted() {
if (this.status === 'awaiting_approval') {
this.expanded = true;
}
},
methods: {
toggleExpanded() {
this.expanded = !this.expanded;
@ -64,15 +69,21 @@ export default {
<template>
<div class="tool-message-container" v-bind:class="expanded? 'expanded':''">
<div class="tool-message-container" v-bind:class="(expanded || status === 'awaiting_approval' )? 'expanded':''">
<div class="tool-message-header">
<div class="tool-name">Tool Call: {{ name }}</div>
<div class="right-aligned">
<div v-if="status === 'awaiting_approval'" style="margin-right: 10px;">
<p style="color: #ffb400; font-size: small;">Awaiting Approval</p>
</div>
<div class="status" v-bind:class="status">
<div v-if="status === 'pending'">
<el-icon class="is-loading" color="#20cbeb"><RefreshRight /></el-icon>
</div>
<div v-else-if="status === 'awaiting_approval'">
<el-icon color="#ffb400"><User /></el-icon>
</div>
<div v-else-if="status === 'success'">
<el-icon color="#00ff18"><Check /></el-icon>
</div>
@ -96,7 +107,14 @@ export default {
<vue-json-pretty :data="args" :expand-depth="2" />
</el-scrollbar>
</div>
<h4>Result:</h4>
<div v-if="status === 'awaiting_approval'" class="tool-approval-container">
<h4>Approve this tool call?</h4>
<el-button type="primary">Approve</el-button>
<el-button type="danger">Deny</el-button>
</div>
<div v-else>
<h4>Result:</h4>
</div>
<div v-if="result" class="tool-result-container">
<div class="copy-to-clipboard">
<el-button size="small" circle @click="copyToClipboard(JSON.stringify(result, null, 2))" :dark="true"><el-icon><DocumentCopy /></el-icon></el-button>

View File

@ -43,6 +43,11 @@ export interface RawOpeyMessage {
* Original LangChain message in serialized form.
*/
original?: Record<string, any>;
/**
* Whether the tool call was successful.
*/
tool_status?: "success" | "error"
}
export interface OpeyMessage {

View File

@ -97,7 +97,7 @@ export const useChat = defineStore('chat', {
},
getToolCallById: (store) => {
return (toolCallId: string): OpeyToolCall | undefined => {
return (toolCallId: string): OpeyToolCall | undefined=> {
const allMessages = store.messages.concat(store.currentAssistantMessage) // Include the current assistant message in the search
for (const message of allMessages) {
if (message.role === 'assistant') {
@ -266,8 +266,16 @@ export const useChat = defineStore('chat', {
// Process pending tool calls
if (data.type === 'message') {
// 'message' type contains the tool calls from the assistant
if (content.tool_calls && content.tool_calls.length > 0) {
if (content.tool_approval_request) {
if (!content.tool_call_id) {
throw new Error('Tool call ID not found for approval request');
}
const awaitingApproval = this.getToolCallById(content.tool_call_id)
awaitingApproval.status = "awaiting_approval"
} else if (content.tool_calls && content.tool_calls.length > 0) {
console.log("Tool Calls: ", content)
for (const toolCall of content.tool_calls) {
@ -297,7 +305,7 @@ export const useChat = defineStore('chat', {
}
// Update the tool message with the content
if (content.original?.data && content.original.data.status === 'error') {
if (content.tool_status && content.tool_status === 'error') {
toolMessage.status = "error";
toolMessage.output = content.content;
} else {