Skip to content
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
cd625e8
feat(frontend): add AI workflow fixer with LLM-powered diff panel
Sep 11, 2026
a79eebf
fix(demo-workflows): add required defaultEnv to Python UDF operators
Sep 12, 2026
c286bcc
fix(frontend): register the AI fix tab for Python UDF console errors
Sep 12, 2026
0eb0a3f
fix(frontend): guard property fixes against a stale suggestion
Sep 23, 2026
19d21b6
fix(frontend): don't report a re-run the deployment will refuse
Sep 24, 2026
2f8bbb7
fix(frontend): show the AI fix tab when the traceback arrives
Sep 24, 2026
b8926d2
fix(frontend): tear down the AI fix tab when the error clears
Sep 24, 2026
56889cc
docs(demo-workflows): add the pipeline demo and document the TextInpu…
Sep 24, 2026
e749a0c
docs(examples): move the AI fix demo workflows out of the repo root
Sep 28, 2026
931a977
fix(frontend): scope the AI fix frame to its own operator
Sep 28, 2026
c6157cb
fix(frontend): address the second review round
Oct 7, 2026
39185db
fix(frontend): drop a stale analysis and fix a lint error
Oct 7, 2026
81e7d26
fix(frontend): keep operator credentials out of the AI fix prompt
Oct 8, 2026
383d3a0
fix(frontend): stop the console stream rerendering the whole panel
Oct 8, 2026
587b7b4
fix(frontend): guard the apply path and classify on the real exception
Oct 8, 2026
45f3f6e
fix(frontend): close the four remaining panel-state findings
Oct 8, 2026
a251a87
fix(frontend): send every input port's schema, not just port 0
Oct 9, 2026
b784df2
fix(frontend): make applying a fix honest about what it does
Oct 9, 2026
8fc6575
refactor(frontend): drop three write-only fields from the panel state
Oct 9, 2026
8844081
Merge remote-tracking branch 'origin/main' into feat/ai-workflow-fixer
Oct 9, 2026
f48df00
refactor(frontend): ask ExecuteWorkflowService whether the run started
Oct 9, 2026
bd5a964
fix(frontend): stop the panel naming a refusal reason it no longer knows
Oct 9, 2026
e7c0d7b
fix(frontend): stop a late analysis repainting a cleared panel
Oct 9, 2026
05772fa
Merge remote-tracking branch 'origin/main' into feat/ai-workflow-fixer
Oct 11, 2026
b622cb6
Merge remote-tracking branch 'origin/main' into feat/ai-workflow-fixer
Oct 15, 2026
55f5ccd
fix(frontend): bind a suggestion to its workflow, and make retry work
Oct 15, 2026
88b22d9
fix(frontend): scope the frame by workflow, and stop an apply reporti…
Oct 15, 2026
a465fe5
Merge remote-tracking branch 'origin/main' into feat/ai-workflow-fixer
Oct 22, 2026
7ee6339
fix(frontend): keep credentials out of the diff, read JVM errors, dro…
Oct 22, 2026
e8798c9
fix(frontend): refuse what cannot be applied, stop guessing indentation
Oct 22, 2026
e4e474f
fix(frontend): refuse a bad field name before it reaches the diff
Oct 22, 2026
2057c03
docs(frontend): put the execution-state comments back on their own sets
Oct 23, 2026
711b328
fix(frontend): count the snippet at Apply, not just find it
Oct 23, 2026
68c65b1
fix(frontend): key the frame tabs by their config, not by their name
Oct 23, 2026
03cd234
fix(frontend): validate the fix before the kill, not only after it
Oct 23, 2026
114b582
fix(frontend): classify on the exception the source already separated
Oct 23, 2026
e35d097
fix(frontend): ask for whole indented lines instead of guessing inden…
Oct 23, 2026
b3f3606
fix(frontend): decide the AI Fix tab from the map, not a remembered key
Oct 23, 2026
26462fa
Merge remote-tracking branch 'origin/main' into feat/ai-workflow-fixer
Oct 27, 2026
10d3775
fix(frontend): require the snippet to end a line, and drop a check th…
Oct 27, 2026
0935e66
refactor(frontend): keep only the fixes this panel can actually write
Oct 27, 2026
7873a6b
refactor(frontend): drop a parameter the deleted branch was the only …
Oct 27, 2026
d4b8068
fix(frontend): stop sending operator configuration, and stop refusing…
Oct 27, 2026
bec7f92
Merge remote-tracking branch 'origin/main' into feat/ai-workflow-fixer
Oct 27, 2026
7d3ccda
feat(config): read the AI fix model from configuration
Oct 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ describe("MenuComponent", () => {
component.currentExecutionName = "exec-1";
const executeSpy = vi
.spyOn(executeWorkflowService, "executeWorkflowWithEmailNotification")
.mockImplementation(() => {});
.mockImplementation(() => true);

component.runWorkflow();

Expand All @@ -927,7 +927,7 @@ describe("MenuComponent", () => {
component.currentExecutionName = "";
const executeSpy = vi
.spyOn(executeWorkflowService, "executeWorkflowWithEmailNotification")
.mockImplementation(() => {});
.mockImplementation(() => true);

component.runWorkflow();

Expand Down Expand Up @@ -971,7 +971,7 @@ describe("MenuComponent", () => {
} as unknown as Mocked<ComputingUnitSelectionComponent>;
const executeSpy = vi
.spyOn(executeWorkflowService, "executeWorkflowWithEmailNotification")
.mockImplementation(() => {});
.mockImplementation(() => true);

component.runWorkflow();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

<ng-container *ngIf="state$ | async as state">
<div
class="ai-fix-status"
*ngIf="state.status === 'analyzing' || state.status === 'applying'">
<nz-spin nzSize="small"></nz-spin>
<span>{{ state.status === "analyzing" ? "Analyzing error with AI..." : "Applying fix..." }}</span>
</div>

<!-- Nothing has been analysed yet (or the user discarded the last suggestion). -->
<div
class="ai-fix-start"
*ngIf="
state.status === 'idle' ||
state.status === 'applied' ||
state.status === 'applied_without_run' ||
state.status === 'error' ||
(state.status === 'ready' && state.errorType === 'unsupported')
">
<button
nz-button
nzType="primary"
class="ai-fix-analyze"
[disabled]="!operatorId"
(click)="onAnalyze()">
<span
nz-icon
nzType="robot"></span>
Analyze with AI
</button>
</div>

<nz-alert
*ngIf="state.status === 'ready' && state.errorType === 'unsupported'"
Comment thread
kunwp1 marked this conversation as resolved.
Outdated
nzType="info"
[nzMessage]="unsupportedMessage"></nz-alert>

<nz-alert
*ngIf="state.status === 'applied'"
nzType="success"
nzMessage="Fix applied — workflow re-running..."></nz-alert>

<nz-alert
*ngIf="state.status === 'applied_without_run'"
nzType="warning"
nzMessage="Fix applied, but the re-run was refused. The reason is in the notification; run again once it is resolved."></nz-alert>

<nz-alert
*ngIf="state.status === 'apply_failed'"
nzType="warning"
[nzMessage]="'Could not apply: ' + state.applyError + '. Review the diff and try again.'"></nz-alert>

<nz-alert
*ngIf="state.status === 'error'"
nzType="error"
nzMessage="The AI could not suggest a fix for this error. Check the console for details."></nz-alert>

<ng-container *ngIf="(state.status === 'ready' || state.status === 'apply_failed') && state.suggestedFix as fix">
<div class="ai-fix-section-title">🔍 Root cause</div>
<p class="ai-fix-explanation">{{ fix.explanation }}</p>

<div class="ai-fix-section-title">
📝 Proposed fix
<nz-tag [nzColor]="confidenceColor(fix.confidence)">{{ fix.confidence }} confidence</nz-tag>
<nz-tag
*ngIf="fix.occurrences && fix.occurrences > 1"
nzColor="orange"
>changes {{ fix.occurrences }} places</nz-tag
>
</div>

<div
class="ai-fix-field"
*ngIf="fix.type === 'property_change'">
Configuration field: <code>{{ fix.fieldName }}</code>
</div>

<div class="ai-fix-diff">
<div
class="ai-fix-removed"
*ngFor="let line of splitLines(fix.original)">
- {{ line }}
</div>
<div
class="ai-fix-added"
*ngFor="let line of splitLines(fix.suggested)">
+ {{ line }}
</div>
</div>

<div class="ai-fix-actions">
<button
nz-button
nzType="primary"
class="ai-fix-apply"
(click)="onApply()">
<span
nz-icon
nzType="check"></span>
Apply and re-run
</button>
<button
nz-button
nzType="default"
class="ai-fix-discard"
(click)="onDiscard()">
<span
nz-icon
nzType="close"></span>
Discard
</button>
</div>
</ng-container>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

:host {
display: block;
width: 100%;
padding: 8px;
}

.ai-fix-status {
align-items: center;
display: flex;
gap: 8px;
padding: 8px 0;
}

.ai-fix-section-title {
font-weight: bold;
margin-top: 8px;
}

.ai-fix-explanation {
margin: 4px 0 8px;
user-select: text;
}

.ai-fix-field {
margin-bottom: 4px;
user-select: text;
}

/* Same monospace treatment the other result-panel frames use for code. */
.ai-fix-diff {
border: 1px solid #e8e8e8;
border-radius: 2px;
font-family: monaco, serif;
Comment thread
kunwp1 marked this conversation as resolved.
Outdated
font-size: 11px;
line-height: 16px;
margin: 4px 0 8px;
overflow-x: auto;
white-space: pre;
user-select: text;
}

.ai-fix-removed {
background-color: #ffeef0;
color: #82071e;
padding: 0 6px;
}

.ai-fix-added {
background-color: #e6ffed;
color: #116329;
padding: 0 6px;
}

.ai-fix-actions {
display: flex;
gap: 8px;
margin-top: 8px;
}
Loading
Loading