Repository navigation
fix: [AI-Generated Earnings] The AI-generated earnings feature modifies earnings directly, without first presenting the proposed adjustments to the user for their review and confirmation. - #7743
Closed
shaohuzhang1 wants to merge 2 commits into
Conversation
… added structural content is empty.
…es earnings directly, without first presenting the proposed adjustments to the user for their review and confirmation.
shaohuzhang1
commented
Nov 9, 2026
| if (!canvasChanged) return | ||
| await layoutCanvas(lf) | ||
| lf.fitView() | ||
| MsgSuccess('工作流已生成,请检查后保存') |
Contributor
Author
There was a problem hiding this comment.
Summary of Issues and Suggestions:
-
Syntax/Formatting Error in Diff (Critical)
- Line 2:
ref, useTemplateRef ,provide}has an extra space before the comma:useTemplateRef ,provide. While valid JS, it violates standard formatting rules (e.g., ESLint/Prettier). - Line 23:
import { VIEW_KEY,VIEW_TYPE } from ...lacks a space after the comment and before the import statement (import type AgentEvent...on line 22 vs line 23). It also misses a blank line separator often expected by linters.
- Line 2:
-
Unused Variable / Dead Code Risk
provide(VIEW_KEY, VIEW_TYPE.DEBUG)is called at the top level of<script setup>. Ensure that thisprovideis necessary for this component. IfWorkflowAiGeneratePanelis not a parent of the components relying onVIEW_KEY, this will have no effect or be misleading. If it is intended, ensureVIEW_KEYandVIEW_TYPEare correctly exported from@/conversation-panel/view.
-
Logic Flaw in
onEventCondition!event.position.length: Ifpositionis not an array (e.g.,undefinedornull), this will throwTypeError: Cannot read properties of undefined (reading 'length').- Fix: Use optional chaining:
!event.position?.lengthor check truthiness if empty array should trigger it differently. However, based on context, you likely want to detect ifpositionis empty/missing indicating it's not a sub-tool event. Ifpositionis always supposed to be an array, initialize it. If it can beundefined, use!event.position || !event.position.length.
-
State Management Issue (
canvasChanged)let canvasChanged = false;inside<script setup>works because module-level variables in<script setup>are isolated per component instance. However, ifrun()is called multiple times concurrently (race condition), they share the samecanvasChangedflag. This could lead to incorrect state if two runs overlap.- Suggestion: Make
canvasChangedlocal to therunfunction scope by passing it via closure or resetting it properly and ensuring sequential execution, or move it intoactiveIdsMapor similar state tracking if concurrent runs are possible.
-
Optimization/Readability: Set Declaration
const CANVAS_MUTATING_TOOLS = new Set([...])is declared inside the script but outside any function. This is fine and efficient (created once per component setup). No issue, just good practice confirmed.
-
Missing Error Handling Edge Case
- In
run(), ifresult.status !== 'done'(e.g., error/cancelled),status.valueremains'running'until manually reset elsewhere? Check how errors are handled. The current code only updates status on'done'. Ensure failure states resetstatus.valueappropriately in other branches not shown.
- In
-
Import Sorting/Linter
provideis added but placed incorrectly relative to alphabet/standard order (ref, useTemplateRef ,provide→ should beprovide, ref, useTemplateRef). Some linters enforce alphabetical order.
✅ Recommended Fixed Code Snippet (Diff Style)
@@ -1,5 +1,5 @@
<script setup lang="ts">
-import { computed, inject, nextTick, onBeforeUnmount, ref, useTemplateRef } from 'vue'
+import { computed, inject, provide, nextTick, onBeforeUnmount, ref, useTemplateRef } from 'vue' // Alphabetical order
import { useRoute } from 'vue-router'
import { cloneDeep } from 'lodash'
import type LogicFlow from '@logicflow/core'
@@ -18,8 +18,9 @@ import { clearDebugLog } from '../common'
import { createAgent } from '../create-agent'
import type { AgentEvent, AgentHandle } from '../type'
import { createActivity } from './activity'
-
+// Add blank line if required by linter, fix spacing
+import { VIEW_KEY, VIEW_TYPE } from '@/conversation-panel/view'
// Provide view key for debugging context (ensure parent-child relationship exists)
provide(VIEW_KEY, VIEW_TYPE.DEBUG)
defineOptions({ name: 'WorkflowAiGeneratePanel' })
const props = withDefaults(
defineProps<{
@@ -90,9 +91,9 @@ function scrollToBottom() {
nextTick(() => scrollbarRef.value?.setScrollTop(Number.MAX_SAFE_INTEGER))
}
-/** 会改动画布的顶层工具;本轮未调用时视为仅规划 / 答复(如等待用户确认方案),不提示生成完成 */
+/** Tools that mutate canvas. If none are called, skip layout/fitView (e.g., planning-only mode) */
const CANVAS_MUTATING_TOOLS = new Set(['add_node', 'add_edge', 'delete_node', 'delete_edge', 'configure_node', 'layout'])
let canvasChanged = false
/** Top-level agent summary flows into activity as text; failures shown as FAILURE items */
function onEvent(event: AgentEvent) {
- if (event.type === 'tool_start' && !event.position.length && CANVAS_MUTATING_TOOLS.has(event.name)) canvasChanged = true
+ // Safe check: handle if position is undefined/null
+ const isTopLevel = !event.position || event.position.length === 0
+ if (event.type === 'tool_start' && isTopLevel && CANVAS_MUTATING_TOOLS.has(event.name)) {
+ canvasChanged = true
+ }
activity.pushEvent(event)
scrollToBottom()
}
@@ -117,12 +123,14 @@ async function run(text: string) {
)
}
status.value = 'running'
canvasChanged = false
const result = await agent.run(text)
if (result.status === 'done') {
status.value = 'done'
// Only fit view and show success if canvas actually changed
- if (!canvasChanged) return
+ if (!canvasChanged) {
+ // Optional: Show a different message or do nothing silently if only planning occurred
+ return
+ }
await layoutCanvas(lf)
lf.fitView()
MsgSuccess('工作流已生成,请检查后保存')
shaohuzhang1
commented
Nov 9, 2026
| problem, _ = Problem.objects.get_or_create(content=problem_text, knowledge_id=knowledge_id) | ||
| problem_paragraph_mapping = ProblemParagraphMapping( | ||
| id=uuid.uuid7(), | ||
| knowledge_id=knowledge_id, |
Contributor
Author
There was a problem hiding this comment.
Review of the diff
1. Potential None / empty-string issues
chat_record.question.get("content")— ifquestionisNone, or the dict has no"content"key, this raisesAttributeError/KeyError. Use defensive access:problem_text = (chat_record.question or {}).get("content") or ""
"".join([r.get("content") for r in chat_record.messages if r.get("type") == "TEXT"])—r.get("content")can returnNone, which will raiseTypeError: sequence item N: expected str instance, NoneType found. Filter or coerce:answer_text = "".join( r["content"] for r in chat_record.messages if r.get("type") == "TEXT" and r.get("content") )
2. Behavior change worth confirming
- The previous code used
chat_record.answer_text/chat_record.problem_text(presumably denormalized fields or properties on the model). The new code recomputes them frommessages/question. Make sure:chat_record.messagesis always populated and ordered correctly.- Concatenating multiple
TEXTmessages without a separator ("") is intentional — otherwise use"\n". - Any whitespace/None values are trimmed before chunking/storing.
3. Performance
- Two list comprehensions iterate over
messagestwice per chat record. Minor, but could be collapsed if both fields are needed. Not critical here. Problem.objects.get_or_create(content=problem_text, ...)will now run with potentially differentproblem_textthan before. Ifproblem_textcomputation differs from what's stored inchat_record.problem_text, deduplication behavior changes. Ensure DB uniqueness constraints includeknowledge_id.- Inside a loop,
get_or_createandParagraphconstruction mean N+1 writes; considerbulk_createforParagraph/ProblemParagraphMappingbatches and pre-fetching existingProblemrows withcontent__in=[...]to avoid repeated queries.
4. Empty data handling
- If
answer_textorproblem_textends up as"", you'll create emptyParagraph/Problemrows. Consider skipping records whereanswer_text.strip() == ""(or raising) to avoid polluting DB.
5. Style / type safety
- The double iteration with a generator expression is fine, but typing could catch these issues earlier. Consider annotating
chat_record.messagesasList[Dict[str, str]]and letting mypy flagOptional[str]joins. uuid.uuid7()— confirm your Python/dependency version actually providesuuid7(not in stdlib until recently); otherwise this is a latent runtime error unrelated to this diff.
6. Recommend refactor
for chat_record in chat_record_list:
messages = chat_record.messages or []
answer_text = "\n".join(
m["content"] for m in messages
if m.get("type") == "TEXT" and isinstance(m.get("content"), str)
)
problem_text = ((chat_record.question or {}).get("content") or "").strip()
if not answer_text or not problem_text:
continue # or log/skip
...Summary: Main risks are None propagation into "".join, possible unintended semantics change (concatenation without separator), and DB-level empty rows / dedup regressions from recomputed problem_text. The core logic is sound; harden input handling and verify uniqueness assumptions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix: [Agent] When adding conversation logs to the knowledge base, the added structural content is empty.
fix: [AI-Generated Earnings] The AI-generated earnings feature modifies earnings directly, without first presenting the proposed adjustments to the user for their review and confirmation.