Skip to content

Commit f17cd18

Browse files
committed
WIP
1 parent b10c238 commit f17cd18

File tree

7 files changed

+84
-8
lines changed

7 files changed

+84
-8
lines changed

demo/fixtures/diagram.bpmn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@
156156
<zeebe:input source="" target="provider.openai.authentication.apiKey" />
157157
<zeebe:input source="gpt-4o" target="provider.openai.model.model" />
158158
<zeebe:input source="=&#34;You are **TaskAgent**, a helpful, generic chat agent that can handle a wide variety of customer requests using your own domain knowledge **and** any tools explicitly provided to you at runtime.&#10;&#10;If tools are provided, you should prefer them instead of guessing an answer. You can call the same tool multiple times by providing different input values. Don&#39;t guess any tools which were not explicitly configured. If no tool matches the request, try to generate an answer. If you&#39;re not able to find a good answer, return with a message stating why you&#39;re not able to.&#10;&#10;Wrap minimal, inspectable reasoning in *exactly* this XML template:&#10;&#10;&#60;thinking&#62;&#10;&#60;context&#62;…briefly state the customer’s need and current state…&#60;/context&#62;&#10;&#60;reflection&#62;…list candidate tools, justify which you will call next and why…&#60;/reflection&#62;&#10;&#60;/thinking&#62;&#10;&#10;Reveal **no** additional private reasoning outside these tags.&#34;" target="data.systemPrompt.prompt" />
159-
<zeebe:input source="=&#34;Answer the question: What is the meaning of life? and create a haiku based on the answer. I&#39;m only interested in the haiku!&#34;" target="data.userPrompt.prompt" />
159+
<zeebe:input source="=&#34;Answer the question: What is the meaning of life? and create 3 different haikus based on the answer. Then rank them and show me the ranking&#34;" target="data.userPrompt.prompt" />
160160
<zeebe:input target="agentContext" />
161161
<zeebe:input source="in-process" target="data.memory.storage.type" />
162162
<zeebe:input source="=20" target="data.memory.contextWindowSize" />

lib/TaskExecution.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,14 @@ export default class TaskExecution extends EventEmitter {
340340
clearInterval(this._interval);
341341
}
342342

343+
if (isExecuting && reason === TASK_EXECUTION_REASON.USER_CANCEL) {
344+
this.emit('taskExecution.log', {
345+
type: 'status',
346+
status: 'canceled',
347+
timestamp: Date.now()
348+
});
349+
}
350+
343351
this._changeStatus('idle');
344352

345353
if (isExecuting && reason) {

lib/components/Output/ExecutionLog.jsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ const STATUS_LABELS = {
1717
'starting-instance': 'Process instance created',
1818
executing: null,
1919
completed: 'Process instance completed',
20-
incident: 'Incident'
20+
incident: 'Incident',
21+
canceled: 'Test canceled'
2122
};
2223

2324
const WAITING_ITEM_LABELS = {
@@ -231,9 +232,9 @@ export function ExecutionLog({ entries, tasklistBaseUrl, currentOperateUrl, onSe
231232

232233
const lastEntry = entries[entries.length - 1];
233234

234-
// Check if execution has finished (completed or incident)
235+
// Check if execution has finished (completed, incident, or canceled)
235236
const isFinished = entries.some(
236-
e => e.type === 'status' && (e.status === 'completed' || e.status === 'incident')
237+
e => e.type === 'status' && (e.status === 'completed' || e.status === 'incident' || e.status === 'canceled')
237238
);
238239

239240
// Filter out 'executing' status once finished - it's just a temporary placeholder
@@ -286,10 +287,13 @@ function StatusEntry({ entry, isLast }) {
286287
}
287288

288289
const isIncident = entry.status === 'incident';
290+
const isCanceled = entry.status === 'canceled';
289291

290292
let dotClass = 'execution-log__dot';
291293
if (isIncident) {
292294
dotClass += ' execution-log__dot--error';
295+
} else if (isCanceled) {
296+
dotClass += ' execution-log__dot--canceled';
293297
}
294298

295299
return (

lib/components/Output/Output.jsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
CheckmarkFilled,
1212
ChevronDown,
1313
ChevronRight,
14-
Launch
14+
Launch,
15+
StopFilledAlt
1516
} from '@carbon/icons-react';
1617

1718
import { isFunction } from 'min-dash';
@@ -60,12 +61,14 @@ export default function Output({
6061

6162
const isError = output?.error || output?.incident;
6263
const isSuccess = output?.success && !isError;
64+
const isCanceled = output?.canceled;
6365

6466
const bannerVariant = useMemo(() => {
6567
if (isError) return 'error';
6668
if (isSuccess) return 'success';
69+
if (isCanceled) return 'warning';
6770
return null;
68-
}, [ isError, isSuccess ]);
71+
}, [ isError, isSuccess, isCanceled ]);
6972

7073
const statusIcon = useMemo(() => {
7174
if (isError) {
@@ -76,8 +79,12 @@ export default function Output({
7679
return <CheckmarkFilled />;
7780
}
7881

82+
if (isCanceled) {
83+
return <StopFilledAlt />;
84+
}
85+
7986
return null;
80-
}, [ isError, isSuccess ]);
87+
}, [ isError, isSuccess, isCanceled ]);
8188

8289
const headerText = useMemo(() => {
8390
if (output) {
@@ -92,6 +99,10 @@ export default function Output({
9299
if (output.success) {
93100
return 'Success';
94101
}
102+
103+
if (output.canceled) {
104+
return 'Test canceled';
105+
}
95106
}
96107

97108
return null;
@@ -446,6 +457,11 @@ function VariablesSection({ title, scope, output, liveVariables, isTaskExecuting
446457
return pickVariables(output.variables, scope);
447458
}
448459

460+
// After cancellation, show unscoped variables (best-effort snapshot)
461+
if (output && output.canceled && output.variables) {
462+
return output.variables;
463+
}
464+
449465
return null;
450466
}, [ isTaskExecuting, liveVariables, output, scope ]);
451467

lib/components/TaskTesting/TaskTesting.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ export default function TaskTesting({
149149
const executionStartTimeRef = useRef(null);
150150

151151
const [ liveVariables, setLiveVariables ] = useState(null);
152+
const liveVariablesRef = useRef(null);
152153

153154
const [ executionCompleted, setExecutionCompleted ] = useState(false);
154155

@@ -285,7 +286,18 @@ export default function TaskTesting({
285286
startedAt: executionStartTimeRef.current,
286287
finishedAt: Date.now()
287288
});
289+
} else if (result.reason === TASK_EXECUTION_REASON.USER_CANCEL) {
290+
elementConfigRef?.current?.setOutputConfigForElement(element, {
291+
success: false,
292+
canceled: true,
293+
variables: liveVariablesRef.current,
294+
operateUrl: currentOperateUrl,
295+
executionLog: log,
296+
startedAt: executionStartTimeRef.current,
297+
finishedAt: Date.now()
298+
});
288299
}
300+
289301
setExecutionCompleted(true);
290302
onTaskExecutionFinished(element, result);
291303
};
@@ -319,6 +331,7 @@ export default function TaskTesting({
319331

320332
/** @param {Object} variables */
321333
const handleVariables = (variables) => {
334+
liveVariablesRef.current = variables;
322335
setLiveVariables(variables);
323336
};
324337

@@ -384,6 +397,7 @@ export default function TaskTesting({
384397
setExecutionLog([]);
385398
executionLogRef.current = [];
386399
setLiveVariables(null);
400+
liveVariablesRef.current = null;
387401
executionStartTimeRef.current = Date.now();
388402

389403
const inputConfig = elementConfigRef.current.getInputConfigForElement(element);
@@ -599,6 +613,7 @@ function getHeaderStateClass({ isTaskExecuting, isConnectionConfigured, output }
599613
if (isTaskExecuting) return 'task-testing__container--header-executing';
600614
if (output?.error || output?.incident || !isConnectionConfigured) return 'task-testing__container--header-error';
601615
if (output?.success) return 'task-testing__container--header-success';
616+
if (output?.canceled) return 'task-testing__container--header-canceled';
602617
return '';
603618
}
604619

@@ -611,6 +626,10 @@ function HeaderStatusIcon({ isTaskExecuting, isConnectionConfigured, output }) {
611626
return <CheckmarkFilled size={ 16 } className="task-testing__status-icon--success" />;
612627
}
613628

629+
if (output?.canceled) {
630+
return <StopFilledAlt size={ 16 } className="task-testing__status-icon--canceled" />;
631+
}
632+
614633
return null;
615634
}
616635

@@ -631,6 +650,10 @@ function HeaderStatusText({ isTaskExecuting, isConnectionConfigured, taskExecuti
631650
if (output.success) {
632651
return 'Success';
633652
}
653+
654+
if (output.canceled) {
655+
return 'Test canceled';
656+
}
634657
}
635658

636659
return null;

lib/style/style.scss

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@
9898
background: #defbe6;
9999
}
100100

101+
&.task-testing__container--header-canceled {
102+
background: #fdf6dd;
103+
}
104+
101105
.task-testing__header-status {
102106
display: flex;
103107
align-items: center;
@@ -125,6 +129,11 @@
125129
flex-shrink: 0;
126130
}
127131

132+
.task-testing__status-icon--canceled {
133+
fill: #f1c21b;
134+
flex-shrink: 0;
135+
}
136+
128137
.task-testing__header-status-text {
129138
font-size: 14px;
130139
font-weight: 600;
@@ -240,6 +249,16 @@
240249
}
241250
}
242251

252+
&.output__banner--warning {
253+
background-color: #fdf6dd;
254+
border: 1px solid #f1c21b;
255+
color: #8a6d00;
256+
257+
.output__banner-icon svg {
258+
fill: #f1c21b;
259+
}
260+
}
261+
243262
.output__banner-header {
244263
display: flex;
245264
align-items: center;
@@ -594,6 +613,10 @@
594613
background-color: #da1e28;
595614
}
596615

616+
.execution-log__dot--canceled {
617+
background-color: #f1c21b;
618+
}
619+
597620
.execution-log__entry {
598621
display: flex;
599622
align-items: center;

lib/types.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ export type TaskExecutionStatus =
137137
'deploying' |
138138
'starting-instance' |
139139
'executing' |
140-
'completed';
140+
'completed' |
141+
'canceled';
142+
'canceled';
141143

142144
export type TaskExecutionEvents =
143145
'taskExecution.status.changed' |

0 commit comments

Comments
 (0)