mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-02 01:33:15 +00:00
Feat: Loading state action list (#360)
* init action-list loading state * loading state logic * rm comments * simplify * fix loading logic * CR: DRY loadingActionsCard refactor * hybrid loading logic; content + stream load * fix duplicate loading actions text --------- Co-authored-by: Brace Sproul <braceasproul@gmail.com>
This commit is contained in:
parent
2a05332693
commit
23f72d0669
2 changed files with 76 additions and 45 deletions
|
|
@ -21,6 +21,7 @@ import { AcceptedPlanStep } from "../gen-ui/accepted-plan-step";
|
|||
import { PlannerGraphState } from "@open-swe/shared/open-swe/planner/types";
|
||||
import { GraphState, PlanItem } from "@open-swe/shared/open-swe/types";
|
||||
import { HumanResponse } from "@langchain/langgraph/prebuilt";
|
||||
import { LoadingActionsCardContent } from "./thread-view-loading";
|
||||
|
||||
interface AcceptedPlanEventData {
|
||||
planTitle: string;
|
||||
|
|
@ -105,6 +106,8 @@ export function ActionsRenderer<State extends PlannerGraphState | GraphState>({
|
|||
const [customNodeEvents, setCustomNodeEvents] = useState<CustomNodeEvent[]>(
|
||||
[],
|
||||
);
|
||||
const joinedRunId = useRef<string | undefined>(undefined);
|
||||
const [streamLoading, setStreamLoading] = useState(false);
|
||||
const stream = useStream<State>({
|
||||
apiUrl: process.env.NEXT_PUBLIC_API_URL,
|
||||
assistantId: graphId,
|
||||
|
|
@ -167,15 +170,31 @@ export function ActionsRenderer<State extends PlannerGraphState | GraphState>({
|
|||
});
|
||||
}, [stream.messages]);
|
||||
|
||||
const streamJoined = useRef(false);
|
||||
// Clear streamLoading as soon as we get any content (agent has started running)
|
||||
useEffect(() => {
|
||||
if (!streamJoined.current && runId) {
|
||||
streamJoined.current = true;
|
||||
// TODO: If the SDK changes go in, use this instead:
|
||||
// stream.joinStream(runId, undefined, { streamMode: ["values", "messages", "custom"]}).catch(console.error);
|
||||
stream.joinStream(runId).catch(console.error);
|
||||
const hasContent =
|
||||
(stream.messages && stream.messages.length > 0) ||
|
||||
customNodeEvents.length > 0;
|
||||
|
||||
if (hasContent && streamLoading) {
|
||||
setStreamLoading(false);
|
||||
}
|
||||
}, [runId]);
|
||||
}, [stream.messages, customNodeEvents, streamLoading]);
|
||||
|
||||
// TODO: If the SDK changes go in, use this instead:
|
||||
// stream.joinStream(runId, undefined, { streamMode: ["values", "messages", "custom"]}).catch(console.error);
|
||||
useEffect(() => {
|
||||
if (runId && runId !== joinedRunId.current) {
|
||||
joinedRunId.current = runId;
|
||||
setStreamLoading(true);
|
||||
stream
|
||||
.joinStream(runId)
|
||||
.catch(console.error)
|
||||
.finally(() => setStreamLoading(false));
|
||||
} else if (!runId) {
|
||||
joinedRunId.current = undefined;
|
||||
}
|
||||
}, [runId, stream]);
|
||||
|
||||
useEffect(() => {
|
||||
if (stream.isLoading) {
|
||||
|
|
@ -214,6 +233,10 @@ export function ActionsRenderer<State extends PlannerGraphState | GraphState>({
|
|||
}
|
||||
}, [stream.values, graphId]);
|
||||
|
||||
if (streamLoading) {
|
||||
return <LoadingActionsCardContent />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
{initializeEvents.length > 0 && steps.length > 0 && (
|
||||
|
|
|
|||
|
|
@ -8,9 +8,51 @@ interface ThreadViewLoadingProps {
|
|||
onBackToHome?: () => void;
|
||||
}
|
||||
|
||||
const isEven = (num: number) => num % 2 === 0;
|
||||
function isEven(n: number) {
|
||||
return n % 2 === 0;
|
||||
}
|
||||
|
||||
export function LoadingActionsSection() {
|
||||
export function LoadingActionsCardContent() {
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{Array.from({ length: 8 }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="border-border bg-muted/30 space-y-2 rounded-lg border p-3 dark:bg-gray-900"
|
||||
>
|
||||
{isEven(i) ? (
|
||||
<div className="bg-background space-y-1 rounded p-2 dark:bg-black">
|
||||
<div className="bg-muted h-2 w-32 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-2 w-48 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="bg-muted h-4 w-4 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-3 w-40 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="bg-muted h-3 w-16 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-4 w-4 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="border-border space-y-2 rounded-lg border-2 border-dashed p-3">
|
||||
<div className="bg-muted h-12 animate-pulse rounded dark:bg-gray-800"></div>
|
||||
<div className="bg-muted h-7 w-16 animate-pulse rounded dark:bg-gray-800"></div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 pt-3">
|
||||
<div className="bg-muted h-8 flex-1 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-8 flex-1 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function LoadingActionsCard() {
|
||||
return (
|
||||
<Card className="border-border bg-card dark:bg-gray-950">
|
||||
<CardHeader className="p-3">
|
||||
|
|
@ -24,41 +66,7 @@ export function LoadingActionsSection() {
|
|||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3 p-3 pt-0">
|
||||
{Array.from({ length: 8 }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="border-border bg-muted/30 space-y-2 rounded-lg border p-3 dark:bg-gray-900"
|
||||
>
|
||||
{isEven(i) ? (
|
||||
<div className="bg-background space-y-1 rounded p-2 dark:bg-black">
|
||||
<div className="bg-muted h-2 w-32 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-2 w-48 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="bg-muted h-4 w-4 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-3 w-40 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="bg-muted h-3 w-16 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-4 w-4 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="border-border space-y-2 rounded-lg border-2 border-dashed p-3">
|
||||
<div className="bg-muted h-12 animate-pulse rounded dark:bg-gray-800"></div>
|
||||
<div className="bg-muted h-7 w-16 animate-pulse rounded dark:bg-gray-800"></div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 pt-3">
|
||||
<div className="bg-muted h-8 flex-1 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
<div className="bg-muted h-8 flex-1 animate-pulse rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
<LoadingActionsCardContent />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -143,7 +151,7 @@ export function ThreadViewLoading({ onBackToHome }: ThreadViewLoadingProps) {
|
|||
|
||||
<div className="flex h-full flex-1 flex-col">
|
||||
<div className="flex-1 space-y-4 overflow-y-auto p-4">
|
||||
<LoadingActionsSection />
|
||||
<LoadingActionsCard />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue