Feat:Migration of tiny robot version to 0.4.0#1804
Conversation
WalkthroughMigrate the plugin from AIClient to OpenAICompatibleProvider; rebuild conversation adapter with an async response provider and plugin-based finish handling; add STATUS/message-state primitives; coordinate stream/tool-call flows and versioned page-schema updates; update UI renderers and props to consume new shapes. ChangesProvider Migration & Conversation Refactor
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
packages/plugins/robot/src/composables/useChat.ts (3)
95-122:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winGuard against
lastMessagebeing undefined.
messages.at(-1)returnsChatMessage | undefined, but Line 98 (lastMessage.content) and Line 120 (lastMessage.content ?? '') both dereference it directly. Ifmessagesis ever empty when finish handling runs (e.g. an aborted request before any assistant message lands), this throws a TypeError. Add optional chaining or an early return.🛡️ Proposed fix
const lastMessage = messages.at(-1) + if (!lastMessage) return delete abortControllerMap.main await onRequestEnd(finishReason, lastMessage.content, messages) // 本次请求结束🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/composables/useChat.ts` around lines 95 - 122, The code assumes lastMessage = messages.at(-1) is always defined but it can be undefined; update the endRequest/finalization logic to guard against that by early-returning when lastMessage is falsy or using optional chaining when accessing lastMessage.content and lastMessage.tool_calls; specifically adjust the usages in this block (references: lastMessage, messages.at, onRequestEnd, handleToolCall, onMessageProcessed, messageState, chatStatus) so you call onRequestEnd with a safe string (or return early), skip tool handling and state transitions when lastMessage is undefined, and avoid direct dereferences like lastMessage.content or lastMessage.tool_calls without checks.
124-129:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSame
messages.at(-1)undefined risk on Line 127.
messages.at(-1).contentcan throw when the array is empty (e.g. error fired before any message was appended). Mirror the optional-chaining fix fromhandleFinishRequest.🛡️ Proposed fix
- await onRequestEnd('error', messages.at(-1).content, messages, { error }) + await onRequestEnd('error', messages.at(-1)?.content ?? '', messages, { error })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/composables/useChat.ts` around lines 124 - 129, In handleRequestError, avoid directly calling messages.at(-1).content which can throw when messages is empty; mirror the fix from handleFinishRequest by using optional chaining and a safe fallback (e.g., messages.at(-1)?.content ?? '') when calling onRequestEnd so the function won’t throw if there’s no last message; update the call site in handleRequestError accordingly.
1-317:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winRun
pnpm build:pluginto validate the package build.The robot plugin package has no local test script; run the repository-level
pnpm build:plugincommand to ensure the changes compile correctly and published package behavior is unaffected. This is required by coding guidelines when build output or published behavior may change.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/composables/useChat.ts` around lines 1 - 317, Run the repository-level build command `pnpm build:plugin` to reproduce the compilation errors for the robot plugin and fix whatever TypeScript/build problems surface in the package (packages/plugins/robot). Focus on correcting imports/exports and types referenced in useChat.ts—check symbols like initChatClient, beforeRequest, createStreamDataHandler, createToolCallHandler, useConversationAdapter, createConversationWithMode and sendUserMessage for missing/incorrect types or broken imports; iterate until `pnpm build:plugin` completes successfully, then commit the fixes.packages/plugins/robot/src/components/renderers/MarkdownRenderer.vue (1)
30-43:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winFix incorrect prop structure and unsafe default in MarkdownRenderer.
The
messageprop is misnamed and incorrectly typed. This renderer should receive acontentprop (a markdown string to render), not amessageobject, consistent with other renderers likeImgRendererandLoadingRenderer. The current implementation accessesprops.message.content(line 69), which:
- Uses the wrong prop name and type (
Optionsis markdown-it's config type, not a message type)- Has an unsafe default: with
default: () => ({}),props.message.contentisundefined, andmarkdownIt.render(undefined)throws at runtimeChange the
messageprop tocontent(string), make it required or default to an empty string, and access it directly:🛡️ Proposed fix
const props = defineProps({ - message: { - type: Object as () => Options, - default: () => ({}) + content: { + type: String, + required: true }, theme: { type: String as () => 'light' | 'dark', default: 'light' }, options: { type: Object as () => Options, default: () => ({}) } }) const renderContent = computed(() => { - return DOMPurify.sanitize(markdownIt.render(props.message.content)) + return DOMPurify.sanitize(markdownIt.render(props.content)) })Also applies to: line 69
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/components/renderers/MarkdownRenderer.vue` around lines 30 - 43, The prop definition in MarkdownRenderer (defineProps) is wrong: replace the current message prop (typed as Options with default {}) with a content prop of type String that is either required or has a safe default (e.g., empty string), keep theme and options as-is, and update all usages that read props.message.content (e.g., where markdownIt.render is called) to use props.content directly so markdownIt.render never receives undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/plugins/robot/src/components/chat/RobotChat.vue`:
- Around line 153-185: The issue is that the markdown and image matchers in
contentRendererMatches inspect message.content instead of the per-item content
parameter, causing wrong matches; update the Markdown matcher (currently using
MarkdownRenderer) to use the signature find: (message: any, content: any) =>
!message.loading && content && content.type !== 'img' && content.type !==
'image' && content.type !== 'tool' (or similar check that content exists and is
not an image/tool), and update the Img matcher (currently using ImgRenderer) to
use find: (message: any, content: any) => content?.type === 'img' ||
content?.type === 'image' so both follow the same per-item content pattern as
Tools, Reasoning, and custom renderers.
In `@packages/plugins/robot/src/composables/modes/useChatMode.ts`:
- Around line 41-47: The updateToolCallRenderContent function lacks the same
guard as updateToolCallState and may match or create entries with an undefined
tool.id; add an early return at the top of updateToolCallRenderContent when
tool.id is falsy (same behavior as in updateToolCallState) so you never call
renderContent.find(... toolCallId === tool.id) or push a new entry with
toolCallId: undefined; reference the function name updateToolCallRenderContent
and the symbol tool.id/toolCallId when making the change.
In `@packages/plugins/robot/src/composables/useChat.ts`:
- Around line 198-214: abortRequest currently calls the async onRequestEnd
fire-and-forget and coerces message content with "as string", causing race
conditions, possible NPEs, and unhandled rejections; make abortRequest async,
synchronously capture a safe snapshot of the last message content and the
messages array (or await onRequestEnd before allowing conversation switch),
replace the unsafe "as string" cast with a guarded nullable value (e.g., check
existence before passing), and wrap the onRequestEnd invocation in try/catch (or
await it and propagate errors) so interruptActiveRequest can await abortRequest
and avoid appending the "aborted" block to the wrong conversation; reference
abortRequest, interruptActiveRequest, onRequestEnd, and messageManager.messages
when making these changes.
---
Outside diff comments:
In `@packages/plugins/robot/src/components/renderers/MarkdownRenderer.vue`:
- Around line 30-43: The prop definition in MarkdownRenderer (defineProps) is
wrong: replace the current message prop (typed as Options with default {}) with
a content prop of type String that is either required or has a safe default
(e.g., empty string), keep theme and options as-is, and update all usages that
read props.message.content (e.g., where markdownIt.render is called) to use
props.content directly so markdownIt.render never receives undefined.
In `@packages/plugins/robot/src/composables/useChat.ts`:
- Around line 95-122: The code assumes lastMessage = messages.at(-1) is always
defined but it can be undefined; update the endRequest/finalization logic to
guard against that by early-returning when lastMessage is falsy or using
optional chaining when accessing lastMessage.content and lastMessage.tool_calls;
specifically adjust the usages in this block (references: lastMessage,
messages.at, onRequestEnd, handleToolCall, onMessageProcessed, messageState,
chatStatus) so you call onRequestEnd with a safe string (or return early), skip
tool handling and state transitions when lastMessage is undefined, and avoid
direct dereferences like lastMessage.content or lastMessage.tool_calls without
checks.
- Around line 124-129: In handleRequestError, avoid directly calling
messages.at(-1).content which can throw when messages is empty; mirror the fix
from handleFinishRequest by using optional chaining and a safe fallback (e.g.,
messages.at(-1)?.content ?? '') when calling onRequestEnd so the function won’t
throw if there’s no last message; update the call site in handleRequestError
accordingly.
- Around line 1-317: Run the repository-level build command `pnpm build:plugin`
to reproduce the compilation errors for the robot plugin and fix whatever
TypeScript/build problems surface in the package (packages/plugins/robot). Focus
on correcting imports/exports and types referenced in useChat.ts—check symbols
like initChatClient, beforeRequest, createStreamDataHandler,
createToolCallHandler, useConversationAdapter, createConversationWithMode and
sendUserMessage for missing/incorrect types or broken imports; iterate until
`pnpm build:plugin` completes successfully, then commit the fixes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 714a8ea4-34b4-405d-8683-fbea959acc47
📒 Files selected for processing (14)
packages/plugins/robot/package.jsonpackages/plugins/robot/src/Main.vuepackages/plugins/robot/src/components/chat/RobotChat.vuepackages/plugins/robot/src/components/header-extension/History.vuepackages/plugins/robot/src/components/renderers/MarkdownRenderer.vuepackages/plugins/robot/src/composables/core/useConversation.tspackages/plugins/robot/src/composables/core/useMessageStream.tspackages/plugins/robot/src/composables/features/useToolCalls.tspackages/plugins/robot/src/composables/modes/useAgentMode.tspackages/plugins/robot/src/composables/modes/useChatMode.tspackages/plugins/robot/src/composables/useChat.tspackages/plugins/robot/src/constants/index.tspackages/plugins/robot/src/constants/status.tspackages/plugins/robot/src/services/aiClient.ts
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/plugins/robot/src/composables/core/useConversation.ts (2)
46-49:⚠️ Potential issue | 🟠 Major | ⚡ Quick winStop draining buffered chunks after cancel.
handleAbort()only flipsfinished, but the loop on Lines 79-88 still yields untilqueue.lengthreaches 0. Any chunks buffered just before cancel will still be merged into the assistant message after the user aborted, which can leak extra output into a canceled or newly switched conversation.Suggested fix
const handleAbort = () => { + queue.length = 0 finished = true notify() } @@ - yield queue.shift() as ChatCompletion + if (abortSignal.aborted) { + queue.length = 0 + break + } + yield queue.shift() as ChatCompletionAlso applies to: 79-88
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/composables/core/useConversation.ts` around lines 46 - 49, The abort handler currently only sets finished and notifies, but buffered chunks in queue continue to be drained by the consumer loop (the logic that iterates over queue and merges chunks), so update handleAbort to both set finished and immediately discard any buffered data to prevent leaking output: inside handleAbort, clear or reset the shared queue (e.g., queue.length = 0 or queue = []) and any partial buffer/state used to merge assistant chunks, then call notify(); ensure the consumer/merging code (the loop that reads from queue) treats finished and an empty queue as terminal so no further chunks are appended after abort.
126-136:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReset the processing gate when finish hooks fail.
statusManager.setProcessing()is sticky here. IfonFinishRequest()rejects,isProcessing()stays true and lateronAfterRequest()calls return early at Line 127, so subsequent responses never run their finish path.Suggested fix
async onAfterRequest({ messages, lastChoice }) { if (statusManager.isProcessing()) { return } statusManager.setProcessing() const finishReason = lastChoice?.finish_reason || 'stop' const contextMessages = toRaw(messages.slice(0, -1)) - await onFinishRequest(finishReason, messages, contextMessages, messageState) + try { + await onFinishRequest(finishReason, messages, contextMessages, messageState) + } catch (error) { + statusManager.resetProcessing() + messageState.status = STATUS.ERROR + messageState.errorMsg = error + throw error + } },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/composables/core/useConversation.ts` around lines 126 - 136, The processing gate set by statusManager.setProcessing() in onAfterRequest can remain true if onFinishRequest(...) throws; wrap the await onFinishRequest(...) call in a try/finally (or try/catch/finally) and ensure you call the complementary statusManager.clearProcessing() (or reset method) in the finally block so isProcessing() is always cleared; preserve rethrowing the error or handle it after clearing so subsequent onAfterRequest calls are not short-circuited.packages/plugins/robot/src/components/chat/RobotChat.vue (1)
33-35:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winThe aborted footer is wired to a property nothing sets.
The cancel flow in
packages/plugins/robot/src/composables/useChat.tsupdatesmessageState.status = STATUS.ABORTED, but none of the supplied code annotates a message withaborted: true. As written, this condition stays false and the "已中止" footer never renders.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/components/chat/RobotChat.vue` around lines 33 - 35, The template checks messages[0]?.aborted but the cancel flow only sets messageState.status = STATUS.ABORTED in useChat.ts, so either annotate the message object when aborting or change the template to check status. Fix by updating the cancel/abort logic in the composable (where messageState.status is set to STATUS.ABORTED) to also set messageState.aborted = true (or messages[index].aborted = true on the actual message object being rendered), ensuring the UI condition in RobotChat.vue's template `#content-footer` sees aborted:true; reference messageState and STATUS.ABORTED in useChat.ts and the messages array used by RobotChat.vue.
♻️ Duplicate comments (2)
packages/plugins/robot/src/composables/useChat.ts (1)
201-217:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
abortRequest()still races conversation switches.This is still fire-and-forget against live
messageManager.messages.value.createConversation()andswitchConversation()call it synchronously right before swapping conversations, so the async cleanup can append aborted state into the wrong conversation or throw when there is no last message.packages/plugins/robot/src/components/chat/RobotChat.vue (1)
177-180:⚠️ Potential issue | 🟠 Major | ⚡ Quick winImage bubbles still won't match
renderContentitems.The matcher still reads
message.content[0], but the upload path here creates image messages withcontent: ''andrenderContent: [{ type: 'img', ... }]. Those messages never hitImgRenderer, so uploaded images fall through to an empty bubble.Suggested fix
{ priority: BubbleRendererMatchPriority.NORMAL, - find: (message: any) => message?.content?.[0]?.type === 'img' || message?.content?.[0]?.type === 'image', + find: (_message: any, content: any) => content?.type === 'img' || content?.type === 'image', renderer: ImgRenderer }Also applies to: 280-289
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/components/chat/RobotChat.vue` around lines 177 - 180, The matcher for image bubbles (the object with priority: BubbleRendererMatchPriority.NORMAL and renderer: ImgRenderer) only checks message.content[0] so messages that carry images in renderContent (e.g. renderContent: [{ type: 'img' | 'image', ... }]) never match; update the find function used for ImgRenderer (and the similar matcher at lines ~280-289) to also inspect message.renderContent[0] (or prefer renderContent if present) and return true when either content[0] or renderContent[0] has type 'img' or 'image', ensuring uploaded images route to ImgRenderer.
🧹 Nitpick comments (1)
packages/plugins/robot/src/composables/useChat.ts (1)
142-165: Please run the robot package tests and plugin build before merge.This refactor changes published streaming, tool-call, and renderer-facing behavior in
packages/plugins/robot. Please run the package-localtestscript if it exists andpnpm build:pluginso the built package still matches the runtime contracts these files now depend on. As per coding guidelines,packages/**/!(test|expected|output|fixtures)/**/*.{js,ts,jsx,tsx}: For published library packages underpackages/**, run the package-localtestscript if one exists and runpnpm build:pluginwhen build output or published package behavior may be affected.Also applies to: 230-318
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/plugins/robot/src/composables/useChat.ts` around lines 142 - 165, This change affects runtime behavior in useConversationAdapter and its callbacks (notably onMessageProcessed, handleStreamData, handleFinishRequest) and state variables messageManager.messageState, chatStatus, CHAT_STATUS, GeneratingStatus and STATUS; before merging, run the package-local tests for packages/plugins/robot (pnpm --filter ./packages/plugins/robot test or the package's test script) and then build the plugin output (pnpm --filter ./packages/plugins/robot build:plugin or pnpm build:plugin in that package) to ensure streaming, tool-call, and renderer contracts still match the built artifact and update any failing tests or build issues found.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/plugins/robot/src/components/renderers/AgentRenderer.vue`:
- Around line 50-53: The computed resolvedContentType currently reads
contentItem.value.contentType or props.contentType but should use the render
item's type field; update the computed named resolvedContentType to use
contentItem.value.type || props.contentType (and similarly replace any other
computed/readers that reference contentItem.value.contentType in this file,
e.g., the second occurrence around the later computed block) so message-based
render items that provide type are handled correctly and the reasoning/terminal
state is preserved.
In `@packages/plugins/robot/src/composables/core/pageUpdater.ts`:
- Around line 125-127: The code currently calls resetPageSchemaUpdateState()
before applying the final chunk which clears lastSuccessfulSchema too early;
change the logic so that when isFinal is true you call
_updatePageSchema(streamContent, currentPageSchema, isFinal,
schemaUpdateVersion) first and only call resetPageSchemaUpdateState() after that
call succeeds (or in a successful completion path), and ensure any errors from
_updatePageSchema are allowed to propagate without clearing lastSuccessfulSchema
so getLastSuccessfulPageSchema() can still return the previous good schema;
reference functions: resetPageSchemaUpdateState(), _updatePageSchema(),
getLastSuccessfulPageSchema(), and setSchema() when implementing the
try/success/cleanup ordering.
- Around line 29-31: The current non-final update uses
Object.assign(pageState.pageSchema, schema) which never removes top-level keys
that were deleted from incoming schema; modify the update logic in
pageUpdater.ts so it first removes any keys present on pageState.pageSchema that
are not present on the incoming schema (e.g., iterate
Object.keys(pageState.pageSchema) and delete keys absent from schema), then copy
new/updated keys from schema into pageState.pageSchema (or replace the object
safely if references allow), and then call useMessage().publish({ topic:
'schemaChange', data: {} }) as before to notify listeners.
In `@packages/plugins/robot/src/utils/schema.utils.ts`:
- Around line 140-141: The current isValidSchemaChildren function incorrectly
accepts any non-array value; update it so it only returns true for actual arrays
whose elements are valid nodes by changing its logic to require
Array.isArray(children) && children.every(isValidSchemaNode). Locate the
isValidSchemaChildren export in schema.utils.ts and replace the negated
Array.isArray check with a direct Array.isArray(...) conjunction so objects,
strings, and other non-array payloads are rejected.
---
Outside diff comments:
In `@packages/plugins/robot/src/components/chat/RobotChat.vue`:
- Around line 33-35: The template checks messages[0]?.aborted but the cancel
flow only sets messageState.status = STATUS.ABORTED in useChat.ts, so either
annotate the message object when aborting or change the template to check
status. Fix by updating the cancel/abort logic in the composable (where
messageState.status is set to STATUS.ABORTED) to also set messageState.aborted =
true (or messages[index].aborted = true on the actual message object being
rendered), ensuring the UI condition in RobotChat.vue's template `#content-footer`
sees aborted:true; reference messageState and STATUS.ABORTED in useChat.ts and
the messages array used by RobotChat.vue.
In `@packages/plugins/robot/src/composables/core/useConversation.ts`:
- Around line 46-49: The abort handler currently only sets finished and
notifies, but buffered chunks in queue continue to be drained by the consumer
loop (the logic that iterates over queue and merges chunks), so update
handleAbort to both set finished and immediately discard any buffered data to
prevent leaking output: inside handleAbort, clear or reset the shared queue
(e.g., queue.length = 0 or queue = []) and any partial buffer/state used to
merge assistant chunks, then call notify(); ensure the consumer/merging code
(the loop that reads from queue) treats finished and an empty queue as terminal
so no further chunks are appended after abort.
- Around line 126-136: The processing gate set by statusManager.setProcessing()
in onAfterRequest can remain true if onFinishRequest(...) throws; wrap the await
onFinishRequest(...) call in a try/finally (or try/catch/finally) and ensure you
call the complementary statusManager.clearProcessing() (or reset method) in the
finally block so isProcessing() is always cleared; preserve rethrowing the error
or handle it after clearing so subsequent onAfterRequest calls are not
short-circuited.
---
Duplicate comments:
In `@packages/plugins/robot/src/components/chat/RobotChat.vue`:
- Around line 177-180: The matcher for image bubbles (the object with priority:
BubbleRendererMatchPriority.NORMAL and renderer: ImgRenderer) only checks
message.content[0] so messages that carry images in renderContent (e.g.
renderContent: [{ type: 'img' | 'image', ... }]) never match; update the find
function used for ImgRenderer (and the similar matcher at lines ~280-289) to
also inspect message.renderContent[0] (or prefer renderContent if present) and
return true when either content[0] or renderContent[0] has type 'img' or
'image', ensuring uploaded images route to ImgRenderer.
---
Nitpick comments:
In `@packages/plugins/robot/src/composables/useChat.ts`:
- Around line 142-165: This change affects runtime behavior in
useConversationAdapter and its callbacks (notably onMessageProcessed,
handleStreamData, handleFinishRequest) and state variables
messageManager.messageState, chatStatus, CHAT_STATUS, GeneratingStatus and
STATUS; before merging, run the package-local tests for packages/plugins/robot
(pnpm --filter ./packages/plugins/robot test or the package's test script) and
then build the plugin output (pnpm --filter ./packages/plugins/robot
build:plugin or pnpm build:plugin in that package) to ensure streaming,
tool-call, and renderer contracts still match the built artifact and update any
failing tests or build issues found.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 849c87ec-885c-43dd-9361-596685821b0a
📒 Files selected for processing (7)
packages/plugins/robot/src/components/chat/RobotChat.vuepackages/plugins/robot/src/components/renderers/AgentRenderer.vuepackages/plugins/robot/src/composables/core/pageUpdater.tspackages/plugins/robot/src/composables/core/useConversation.tspackages/plugins/robot/src/composables/modes/useAgentMode.tspackages/plugins/robot/src/composables/useChat.tspackages/plugins/robot/src/utils/schema.utils.ts
| const resolvedStatus = computed(() => contentItem.value.status || props.status || 'loading') | ||
| const resolvedContent = computed(() => contentItem.value.content ?? props.content) | ||
| const resolvedContentType = computed(() => contentItem.value.contentType || props.contentType) | ||
|
|
There was a problem hiding this comment.
Use the render item's type field here, not contentType.
contentItem comes from message.renderContent, and the render items built in this PR use type (packages/plugins/robot/src/components/chat/RobotChat.vue, packages/plugins/robot/src/composables/modes/useAgentMode.ts). Reading contentItem.value.contentType leaves resolvedContentType empty for message-based rendering, so reasoning entries miss the reasoning branch and can show the wrong terminal state.
Suggested fix
- const resolvedContentType = computed(() => contentItem.value.contentType || props.contentType)
+ const resolvedContentType = computed(() => contentItem.value.type || props.contentType)Also applies to: 82-89
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/plugins/robot/src/components/renderers/AgentRenderer.vue` around
lines 50 - 53, The computed resolvedContentType currently reads
contentItem.value.contentType or props.contentType but should use the render
item's type field; update the computed named resolvedContentType to use
contentItem.value.type || props.contentType (and similarly replace any other
computed/readers that reference contentItem.value.contentType in this file,
e.g., the second occurrence around the later computed block) so message-based
render items that provide type are handled correctly and the reasoning/terminal
state is preserved.
| } else { | ||
| Object.assign(pageState.pageSchema, schema) | ||
| useMessage().publish({ topic: 'schemaChange', data: {} }) |
There was a problem hiding this comment.
Remove dropped top-level keys during non-final schema updates.
Object.assign(pageState.pageSchema, schema) never deletes keys that disappeared from schema, so streamed remove patches on root fields keep stale data alive until a final import happens. If the stream is interrupted, the canvas can stay in the wrong state.
Proposed fix
} else {
+ Object.keys(pageState.pageSchema).forEach((key) => {
+ if (!(key in (schema as Record<string, unknown>))) {
+ delete (pageState.pageSchema as Record<string, unknown>)[key]
+ }
+ })
Object.assign(pageState.pageSchema, schema)
useMessage().publish({ topic: 'schemaChange', data: {} })
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } else { | |
| Object.assign(pageState.pageSchema, schema) | |
| useMessage().publish({ topic: 'schemaChange', data: {} }) | |
| } else { | |
| Object.keys(pageState.pageSchema).forEach((key) => { | |
| if (!(key in (schema as Record<string, unknown>))) { | |
| delete (pageState.pageSchema as Record<string, unknown>)[key] | |
| } | |
| }) | |
| Object.assign(pageState.pageSchema, schema) | |
| useMessage().publish({ topic: 'schemaChange', data: {} }) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/plugins/robot/src/composables/core/pageUpdater.ts` around lines 29 -
31, The current non-final update uses Object.assign(pageState.pageSchema,
schema) which never removes top-level keys that were deleted from incoming
schema; modify the update logic in pageUpdater.ts so it first removes any keys
present on pageState.pageSchema that are not present on the incoming schema
(e.g., iterate Object.keys(pageState.pageSchema) and delete keys absent from
schema), then copy new/updated keys from schema into pageState.pageSchema (or
replace the object safely if references allow), and then call
useMessage().publish({ topic: 'schemaChange', data: {} }) as before to notify
listeners.
| if (isFinal) { | ||
| resetPageSchemaUpdateState() | ||
| return _updatePageSchema(streamContent, currentPageSchema, isFinal, schemaUpdateVersion) |
There was a problem hiding this comment.
Don't clear the last good schema before the final apply succeeds.
When isFinal is true, this resets lastSuccessfulSchema before parsing and applying the final chunk. If the final chunk is malformed or setSchema() throws, getLastSuccessfulPageSchema() has already lost the last valid streamed schema, so callers cannot fall back to it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/plugins/robot/src/composables/core/pageUpdater.ts` around lines 125
- 127, The code currently calls resetPageSchemaUpdateState() before applying the
final chunk which clears lastSuccessfulSchema too early; change the logic so
that when isFinal is true you call _updatePageSchema(streamContent,
currentPageSchema, isFinal, schemaUpdateVersion) first and only call
resetPageSchemaUpdateState() after that call succeeds (or in a successful
completion path), and ensure any errors from _updatePageSchema are allowed to
propagate without clearing lastSuccessfulSchema so getLastSuccessfulPageSchema()
can still return the previous good schema; reference functions:
resetPageSchemaUpdateState(), _updatePageSchema(),
getLastSuccessfulPageSchema(), and setSchema() when implementing the
try/success/cleanup ordering.
| export const isValidSchemaChildren = (children: unknown): boolean => | ||
| !Array.isArray(children) || children.every(isValidSchemaNode) |
There was a problem hiding this comment.
Reject non-array children payloads here.
isValidSchemaChildren() currently returns true for {}, strings, and any other non-array value. That means the new guard in pageUpdater.ts still accepts malformed children shapes even though the rest of the schema pipeline only handles arrays.
Proposed fix
export const isValidSchemaChildren = (children: unknown): boolean =>
- !Array.isArray(children) || children.every(isValidSchemaNode)
+ children == null || (Array.isArray(children) && children.every(isValidSchemaNode))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/plugins/robot/src/utils/schema.utils.ts` around lines 140 - 141, The
current isValidSchemaChildren function incorrectly accepts any non-array value;
update it so it only returns true for actual arrays whose elements are valid
nodes by changing its logic to require Array.isArray(children) &&
children.every(isValidSchemaNode). Locate the isValidSchemaChildren export in
schema.utils.ts and replace the negated Array.isArray check with a direct
Array.isArray(...) conjunction so objects, strings, and other non-array payloads
are rejected.
English | 简体中文
PR
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Background and solution
What is the current behavior?
Issue Number: N/A
What is the new behavior?
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
New Features
Improvements
Updates