Skip to content

Comments

AP-25051: Add cancel button to Agent Chat Widget#19

Merged
ya-hn merged 3 commits intomasterfrom
enh/AP-25051-agent-chat-widget-cancel-button
Feb 4, 2026
Merged

AP-25051: Add cancel button to Agent Chat Widget#19
ya-hn merged 3 commits intomasterfrom
enh/AP-25051-agent-chat-widget-cancel-button

Conversation

@ya-hn
Copy link
Contributor

@ya-hn ya-hn commented Jan 16, 2026

Adds a cancel functionality to the send button in the Agent Chat Widget node.

@ya-hn ya-hn requested a review from a team as a code owner January 16, 2026 15:36
aria-hidden="true"
focusable="false"
/>
</FunctionButton>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also separate this into two buttons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, it's ok


function finishLoading(shallApplyViewData: boolean) {
isLoading.value = false;
isInterrupted.value = false;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My strategy was to check where we reset isLoading and to also reset isInterrupted there. But we should double-check if this covers all cases.

@AtR1an AtR1an force-pushed the bug/AP-25110-implement-error-handling-option branch 2 times, most recently from ad00fad to 0ffb5c6 Compare January 27, 2026 18:32
Base automatically changed from bug/AP-25110-implement-error-handling-option to master January 27, 2026 19:23
@iusethemouse iusethemouse requested review from iusethemouse and removed request for a team February 4, 2026 08:27
@ya-hn ya-hn force-pushed the enh/AP-25051-agent-chat-widget-cancel-button branch from a815361 to 1398cd2 Compare February 4, 2026 09:01
Copilot AI review requested due to automatic review settings February 4, 2026 09:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds cancel functionality to the Agent Chat Widget, allowing users to interrupt agent responses in progress. The implementation introduces a new isInterrupted state to track cancellation and updates the UI to show an abort button when the agent is processing.

Changes:

  • Added cancelAgent() method and isInterrupted state management to the chat store
  • Updated MessageInput component to toggle between send and abort buttons based on processing state
  • Implemented backend cancel_agent() method to handle cancellation requests

Reviewed changes

Copilot reviewed 3 out of 7 changed files in this pull request and generated 3 comments.

File Description
src/agents/chat_app/src/stores/chat.ts Added isInterrupted state, cancelAgent() method, and reset logic for cancellation tracking
src/agents/chat_app/src/components/chat/MessageInput.vue Updated UI to conditionally show abort/send button and handle cancellation in submit logic
src/agents/_data_service.py Implemented cancel_agent() method and reset _is_canceled flag in appropriate lifecycle points

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

stroke: var(--knime-dove-gray);

&.send-icon {
& .send-icon .abort-icon {
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid CSS selector syntax. The selector should use a comma to target both classes independently: &.send-icon, &.abort-icon

Suggested change
& .send-icon .abort-icon {
& .send-icon,
& .abort-icon {

Copilot uses AI. Check for mistakes.
await jsonDataService.value?.data({
method: "cancel_agent",
});
return;
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary explicit return statement in async function. The function already returns implicitly.

Suggested change
return;

Copilot uses AI. Check for mistakes.

const isInputValid = computed(() => input.value?.trim().length > 0);
const isDisabled = computed(() => !isInputValid.value || chatStore.isLoading);
const isDisabled = computed(() => (!isInputValid.value && !chatStore.isLoading) || chatStore.isInterrupted);
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for isDisabled is complex and could be clearer. When isLoading is true, the button should be enabled (to allow cancellation), but when isInterrupted is true, it should be disabled. Consider refactoring to: (chatStore.isInterrupted) || (!chatStore.isLoading && !isInputValid.value)

Suggested change
const isDisabled = computed(() => (!isInputValid.value && !chatStore.isLoading) || chatStore.isInterrupted);
const isDisabled = computed(
() => chatStore.isInterrupted || (!chatStore.isLoading && !isInputValid.value),
);

Copilot uses AI. Check for mistakes.
Copy link
Member

@iusethemouse iusethemouse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice 👍 Besides that one code structure comment in the MessageInput component, looks good.

We also have unit tests, which you can run with pnpm run test:unit (yeah, you have to run them manually 😬 , they're not part of the build process yet). Could you please expand test suites for MessageInput.vue and chat.ts? Opus should be very helpful there

const isInputValid = computed(() => input.value?.trim().length > 0);
const isDisabled = computed(() => !isInputValid.value || chatStore.isLoading);
const isDisabled = computed(() => (!isInputValid.value && !chatStore.isLoading) || chatStore.isInterrupted);
const isProcessing = computed(() => chatStore.isLoading);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to tidy things up a bit: we generally use computed when we want to combine a few reactive properties (properties that can have their inner .value change during runtime) into a new singular reactive property. So we want a new Prop A which changes whenever either Prop B or Prop C change - then Prop A is our computed prop.

Here, we basically say const myVar = otherVar 😃 Nothing wrong with that, it will work just fine (and I'm pretty sure Vue would cleverly optimise this), but isLoading is already a reactive property (see that it's a ref inside chat.ts), so we don't need to wrap it with a computed unless we want to combine its reactivity with some other reactive property.

There's a nice function in Pinia called storeToRefs, which allows extracting reactive properties from stores and retain their reactivity, and we could use it here, e.g.:

import { storeToRefs } from "pinia"

const { isLoading, isInterrupted } = storeToRefs(chatStore)

and then use those nice reactive properties elsewhere in this component

aria-hidden="true"
focusable="false"
/>
</FunctionButton>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, it's ok

Copy link
Member

@iusethemouse iusethemouse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, merge at will 👍 (if you have merge permissions...)

@ya-hn ya-hn merged commit 3159a02 into master Feb 4, 2026
1 check passed
@ya-hn ya-hn deleted the enh/AP-25051-agent-chat-widget-cancel-button branch February 4, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants