feat(editor): Add Info Note to NDV Output Panel if no existing Tools were used during Execution (#11672)

This commit is contained in:
Charlie Kolb 2024-11-19 13:11:12 +01:00 committed by GitHub
parent e298ebe90d
commit de0e86150f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 145 additions and 1 deletions

View file

@ -72,6 +72,10 @@ export function getOutputPanelTable() {
return getOutputPanelDataContainer().get('table');
}
export function getRunDataInfoCallout() {
return cy.getByTestId('run-data-callout');
}
export function getOutputPanelItemsCount() {
return getOutputPanel().getByTestId('ndv-items-count');
}

View file

@ -26,6 +26,8 @@ import {
clickCreateNewCredential,
clickExecuteNode,
clickGetBackToCanvas,
getRunDataInfoCallout,
getOutputPanelTable,
toggleParameterCheckboxInputByName,
} from '../composables/ndv';
import {
@ -418,4 +420,102 @@ describe('Langchain Integration', () => {
assertInputOutputText('Berlin', 'not.exist');
assertInputOutputText('Kyiv', 'not.exist');
});
it('should show tool info notice if no existing tools were used during execution', () => {
addNodeToCanvas(MANUAL_CHAT_TRIGGER_NODE_NAME, true);
addNodeToCanvas(AGENT_NODE_NAME, true);
addLanguageModelNodeToParent(
AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME,
AGENT_NODE_NAME,
true,
);
clickCreateNewCredential();
setCredentialValues({
apiKey: 'sk_test_123',
});
clickGetBackToCanvas();
addToolNodeToParent(AI_TOOL_CALCULATOR_NODE_NAME, AGENT_NODE_NAME);
clickGetBackToCanvas();
openNode(AGENT_NODE_NAME);
const inputMessage = 'Hello!';
const outputMessage = 'Hi there! How can I assist you today?';
clickExecuteNode();
runMockWorkflowExecution({
trigger: () => sendManualChatMessage(inputMessage),
runData: [
createMockNodeExecutionData(AGENT_NODE_NAME, {
jsonData: {
main: { output: outputMessage },
},
metadata: {
subRun: [{ node: AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME, runIndex: 0 }],
},
}),
],
lastNodeExecuted: AGENT_NODE_NAME,
});
closeManualChatModal();
openNode(AGENT_NODE_NAME);
getRunDataInfoCallout().should('exist');
});
it('should not show tool info notice if tools were used during execution', () => {
addNodeToCanvas(MANUAL_CHAT_TRIGGER_NODE_NAME, true);
addNodeToCanvas(AGENT_NODE_NAME, true, true);
getRunDataInfoCallout().should('not.exist');
clickGetBackToCanvas();
addLanguageModelNodeToParent(
AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME,
AGENT_NODE_NAME,
true,
);
clickCreateNewCredential();
setCredentialValues({
apiKey: 'sk_test_123',
});
clickGetBackToCanvas();
addToolNodeToParent(AI_TOOL_CALCULATOR_NODE_NAME, AGENT_NODE_NAME);
clickGetBackToCanvas();
openNode(AGENT_NODE_NAME);
getRunDataInfoCallout().should('not.exist');
const inputMessage = 'Hello!';
const outputMessage = 'Hi there! How can I assist you today?';
clickExecuteNode();
runMockWorkflowExecution({
trigger: () => sendManualChatMessage(inputMessage),
runData: [
createMockNodeExecutionData(AGENT_NODE_NAME, {
jsonData: {
main: { output: outputMessage },
},
metadata: {
subRun: [{ node: AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME, runIndex: 0 }],
},
}),
createMockNodeExecutionData(AI_TOOL_CALCULATOR_NODE_NAME, {}),
],
lastNodeExecuted: AGENT_NODE_NAME,
});
closeManualChatModal();
openNode(AGENT_NODE_NAME);
// This waits to ensure the output panel is rendered
getOutputPanelTable();
getRunDataInfoCallout().should('not.exist');
});
});

View file

@ -1,6 +1,12 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import type { IRunData, IRunExecutionData, NodeError, Workflow } from 'n8n-workflow';
import {
NodeConnectionType,
type IRunData,
type IRunExecutionData,
type NodeError,
type Workflow,
} from 'n8n-workflow';
import RunData from './RunData.vue';
import RunInfo from './RunInfo.vue';
import { storeToRefs } from 'pinia';
@ -209,6 +215,29 @@ const canPinData = computed(() => {
return pinnedData.isValidNodeType.value && !props.isReadOnly;
});
const allToolsWereUnusedNotice = computed(() => {
if (!node.value || runsCount.value === 0) return undefined;
// With pinned data there's no clear correct answer for whether
// we should use historic or current parents, so we don't show the notice,
// as it likely ends up unactionable noise to the user
if (pinnedData.hasData.value) return undefined;
const toolsAvailable = props.workflow.getParentNodes(
node.value.name,
NodeConnectionType.AiTool,
1,
);
const toolsUsedInLatestRun = toolsAvailable.filter(
(tool) => !!workflowRunData.value?.[tool]?.[props.runIndex],
);
if (toolsAvailable.length > 0 && toolsUsedInLatestRun.length === 0) {
return i18n.baseText('ndv.output.noToolUsedInfo');
} else {
return undefined;
}
});
// Methods
const insertTestData = () => {
@ -298,6 +327,7 @@ const activatePane = () => {
:hide-pagination="outputMode === 'logs'"
pane-type="output"
:data-output-type="outputMode"
:callout-message="allToolsWereUnusedNotice"
@activate-pane="activatePane"
@run-change="onRunIndexChange"
@link-run="onLinkRun"

View file

@ -120,6 +120,7 @@ type Props = {
isProductionExecutionPreview?: boolean;
isPaneActive?: boolean;
hidePagination?: boolean;
calloutMessage?: string;
};
const props = withDefaults(defineProps<Props>(), {
@ -133,6 +134,7 @@ const props = withDefaults(defineProps<Props>(), {
mappingEnabled: false,
isExecuting: false,
hidePagination: false,
calloutMessage: undefined,
});
const emit = defineEmits<{
search: [search: string];
@ -1426,6 +1428,12 @@ defineExpose({ enterEditMode });
<slot v-if="!displaysMultipleNodes" name="before-data" />
<div v-if="props.calloutMessage" :class="$style.hintCallout">
<N8nCallout theme="secondary" data-test-id="run-data-callout">
<N8nText v-n8n-html="props.calloutMessage" size="small"></N8nText>
</N8nCallout>
</div>
<N8nCallout
v-for="hint in getNodeHints()"
:key="hint.message"

View file

@ -247,6 +247,7 @@ exports[`InputPanel > should render 1`] = `
<!--v-if-->
<!--v-if-->
<!--v-if-->
<!--v-if-->
<!--v-if-->

View file

@ -988,6 +988,7 @@
"ndv.output.tooMuchData.showDataAnyway": "Show data",
"ndv.output.tooMuchData.title": "Display data?",
"ndv.output.waitingToRun": "Waiting to execute...",
"ndv.output.noToolUsedInfo": "None of your tools were used in this run. Try giving your tools clearer names and descriptions to help the AI",
"ndv.title.cancel": "Cancel",
"ndv.title.rename": "Rename",
"ndv.title.renameNode": "Rename node",