TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))bug:
Opened this issue · 6 comments
Provide environment information
System: OS: macOS 12.7.4 CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz Memory: 18.83 MB / 8.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 20.12.0 - /usr/local/bin/node npm: 10.5.0 - /usr/local/bin/npm pnpm: 8.15.6 - /usr/local/bin/pnpm
Describe the bug
Whenever i highlight a text and click on the ask AI
option, i get an error that says - TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator).
I can't exactly pinpoint the error because there isn't enough information about it. i did some debugging and i think the error might be coming from the ai-selector-commands
component. I noticed that when i comment the code in the return block inside the ai-selector-commands
component, i don't get the error but only the input with the ask AI to edit or generate
option is displayed in the ui. however when i start typing in the input i get the error again. I have been trying hard to find the issue but i can't seem to figure it out.
here's the "ai-selector" component for reference -
"use client";
import { Command, CommandInput } from "../ui/command";
import { useCompletion } from "ai/react";
import { toast } from "sonner";
import { useEditor } from "novel";
import { useState } from "react";
import Markdown from "react-markdown";
import AISelectorCommands from "./ai-selector-commands";
import AICompletionCommands from "./ai-completion-command";
import { ScrollArea } from "../ui/scroll-area";
import { Button } from "../ui/button";
import { ArrowUp } from "lucide-react";
import Magic from "../ui/Icons/magic";
import CrazySpinner from "../ui/Icons/crazy-spinner";
import { addAIHighlight } from "novel/extensions";
type AISelectorProps = {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function AISelector({ open, onOpenChange }: AISelectorProps) {
const { editor } = useEditor();
const [inputValue, setInputValue] = useState("");
const { completion, complete, isLoading } = useCompletion({
api: "/api/generate",
onResponse: (response) => {
if (response.status === 429) {
toast.error("You have reached your request limit for the day.");
return;
}
},
onError: (e) => {
toast.error(e.message);
console.log(e)
},
});
const hasCompletion = completion.length > 0;
return (
<Command className="w-[350px]">
{hasCompletion && (
<div className="flex max-h-[400px]">
<ScrollArea>
<div className="prose p-2 px-4 prose-sm">
<Markdown>{completion}</Markdown>
</div>
</ScrollArea>
</div>
)}
{isLoading && (
<div className="flex h-12 w-full items-center px-4 text-sm font-medium text-muted-foreground text-purple-500">
<Magic className="mr-2 h-4 w-4 shrink-0 " />
AI is thinking
<div className="ml-2 mt-1">
<CrazySpinner />
</div>
</div>
)}
{!isLoading && (
<>
<div className="relative">
<CommandInput
value={inputValue}
onValueChange={setInputValue}
autoFocus
placeholder={
hasCompletion
? "Tell AI what to do next"
: "Ask AI to edit or generate..."
}
onFocus={() => editor && addAIHighlight(editor)}
/>
<Button
size="icon"
className="absolute right-2 top-1/2 h-6 w-6 -translate-y-1/2 rounded-full bg-purple-500 hover:bg-purple-900"
onClick={() => {
if (completion)
return complete(completion, {
body: { option: "zap", command: inputValue },
}).then(() => setInputValue(""));
const slice = editor && editor.state.selection.content();
const text = editor && slice && editor.storage.markdown.serializer.serialize(
slice.content,
);
complete(text, {
body: { option: "zap", command: inputValue },
}).then(() => setInputValue(""));
}}
>
<ArrowUp className="h-4 w-4" />
</Button>
</div>
{hasCompletion ? (
<AICompletionCommands
onDiscard={() => {
editor && editor.chain().unsetHighlight().focus().run();
onOpenChange(false);
}}
completion={completion}
/>
) : (
<AISelectorCommands
onSelect={(value, option) =>
complete(value, { body: { option } })
}
/>
)}
</>
)}
</Command>
);
}
here is the "ai-selector-commands" component for reference -
import React from "react";
import { CommandGroup, CommandItem, CommandSeparator } from "../ui/command";
import {
ArrowDownWideNarrow,
CheckCheck,
RefreshCcwDot,
StepForward,
WrapText,
} from "lucide-react";
import { useEditor } from "novel";
import { getPrevText } from "novel/extensions";
const options = [
{
value: "improve",
label: "Improve writing",
icon: RefreshCcwDot,
},
{
value: "fix",
label: "Fix grammar",
icon: CheckCheck,
},
{
value: "shorter",
label: "Make shorter",
icon: ArrowDownWideNarrow,
},
{
value: "longer",
label: "Make longer",
icon: WrapText,
},
];
type AISelectorCommandsProps = {
onSelect: (value: string, option: string) => void;
}
const AISelectorCommands = ({ onSelect }: AISelectorCommandsProps) => {
const { editor } = useEditor();
return (
<>
<CommandGroup heading="Edit or review selection">
{options.map((option) => (
<CommandItem
onSelect={(value) => {
const slice = editor && editor.state.selection.content();
const text = editor && editor.storage.markdown.serializer.serialize(
slice && slice.content,
);
onSelect(text, value);
}}
className="flex gap-2 px-4"
key={option.value}
value={option.value}
>
<option.icon className="h-4 w-4 text-purple-500" />
{option.label}
</CommandItem>
))}
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Use AI to do more">
<CommandItem
onSelect={() => {
const text = editor && getPrevText(editor, { chars: 5000 });
onSelect(text, "continue");
}}
value="continue"
className="gap-2 px-4"
>
<StepForward className="h-4 w-4 text-purple-500" />
Continue writing
</CommandItem>
</CommandGroup>
</>
);
};
export default AISelectorCommands;
here is the "ai-completion-command" for reference -
import React from "react";
import { CommandGroup, CommandItem, CommandSeparator } from "../ui/command";
import { useEditor } from "novel";
import { Check, TextQuote, TrashIcon } from "lucide-react";
type AICompletionCommandsType = {
completion: string,
onDiscard: () => void,
};
const AICompletionCommands = ({ completion, onDiscard }: AICompletionCommandsType) => {
const { editor } = useEditor();
return (
<>
<CommandGroup>
<CommandItem
className="gap-2 px-4"
value="replace"
onSelect={() => {
const selection = editor && editor.view.state.selection;
editor && selection && editor
.chain()
.focus()
.insertContentAt(
{
from: selection.from,
to: selection.to,
},
completion,
)
.run();
}}
>
<Check className="h-4 w-4 text-muted-foreground" />
Replace selection
</CommandItem>
<CommandItem
className="gap-2 px-4"
value="insert"
onSelect={() => {
const selection = editor && editor.view.state.selection;
editor && selection && editor
.chain()
.focus()
.insertContentAt(selection.to + 1, completion)
.run();
}}
>
<TextQuote className="h-4 w-4 text-muted-foreground" />
Insert below
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup>
<CommandItem onSelect={onDiscard} value="thrash" className="gap-2 px-4">
<TrashIcon className="h-4 w-4 text-muted-foreground" />
Discard
</CommandItem>
</CommandGroup>
</>
);
};
export default AICompletionCommands;
Link to reproduction
To reproduce
I get the error when i click on the Ask AI
option
Additional information
No response
Hey @Davidthecode,
I have the exact same issue. Did you ever find out how to resolve it ?
Thanks
ok @john-dw, i'll try it out
Downgrading cmdk package version to 0.2.1 did the trick. It works now.
Worked for me, thanks!
From https://github.com/pacocoursey/cmdk/releases:
Command.List is now required (CommandList in shadcn)
Rendering the Command.List part (CommandList if using shadcn) is now mandatory. Otherwise, you should expect to see an error like this:
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
The fix:
// Before
<Command label="Command Menu">
<Command.Input />
<Command.Item />
{/* ... */}
</Command>
// After
<Command label="Command Menu">
<Command.Input />
<Command.List>
<Command.Item />
{/* ... */}
</Command.List>
</Command>
Thank you very much! That worked