mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2026-07-09 16:09:13 +00:00
feat: hint that Copilot accepts pasted recorded steps from other agents (#7097)
This commit is contained in:
parent
a95bab83a3
commit
121d323ec2
4 changed files with 95 additions and 2 deletions
|
|
@ -0,0 +1,61 @@
|
|||
import { useState } from "react";
|
||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||
|
||||
import { cn } from "@/util/utils";
|
||||
import { usePasteSkillHintStore } from "@/store/usePasteSkillHintStore";
|
||||
|
||||
export function PasteRecordedStepsHint({ className }: { className?: string }) {
|
||||
const dismissed = usePasteSkillHintStore((s) => s.dismissed);
|
||||
const dismiss = usePasteSkillHintStore((s) => s.dismiss);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
if (dismissed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"shrink-0 rounded-lg border border-border bg-slate-elevation2 px-3 py-2 text-xs text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="flex items-start gap-2">
|
||||
<span aria-hidden className="leading-5">
|
||||
💡
|
||||
</span>
|
||||
<div className="flex-1">
|
||||
<span>
|
||||
Already recorded this with another agent? Paste the steps into
|
||||
Copilot to build it here.
|
||||
</span>{" "}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setExpanded((prev) => !prev)}
|
||||
className="font-medium text-foreground underline-offset-2 hover:underline"
|
||||
>
|
||||
{expanded ? "Hide" : "How?"}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Dismiss"
|
||||
onClick={dismiss}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<Cross2Icon className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
{expanded ? (
|
||||
<ol className="mt-2 list-decimal space-y-1 pl-8">
|
||||
<li>
|
||||
In your agent (e.g. the Claude Chrome extension), open your recorded
|
||||
workflow and copy its prompt text.
|
||||
</li>
|
||||
<li>Paste it into the Copilot chat.</li>
|
||||
<li>Copilot turns it into a Skyvern agent you can run and edit.</li>
|
||||
</ol>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import { stringify as convertToYAML } from "yaml";
|
|||
import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore";
|
||||
import { useCopilotActionStore } from "@/store/useCopilotActionStore";
|
||||
import { useCopilotHeaderStore } from "@/store/useCopilotHeaderStore";
|
||||
import { usePasteSkillHintStore } from "@/store/usePasteSkillHintStore";
|
||||
import { WorkflowCreateYAMLRequest } from "@/routes/workflows/types/workflowYamlTypes";
|
||||
import { WorkflowApiResponse } from "@/routes/workflows/types/workflowTypes";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
|
|
@ -509,6 +510,7 @@ export function WorkflowCopilotChat({
|
|||
);
|
||||
const [autoAccept, setAutoAccept] = useState<boolean>(false);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const dismissPasteSkillHint = usePasteSkillHintStore((s) => s.dismiss);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [queuedPrompt, setQueuedPrompt] = useState<QueuedPrompt | null>(null);
|
||||
const [narrative, setNarrative] =
|
||||
|
|
@ -2382,10 +2384,11 @@ export function WorkflowCopilotChat({
|
|||
? "Type a message to send next…"
|
||||
: isWaitingForLiveBrowser
|
||||
? "Type a prompt to send when ready..."
|
||||
: "Message Skyvern Copilot…"
|
||||
: "Message Skyvern Copilot, or paste recorded steps…"
|
||||
}
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onPaste={() => dismissPasteSkillHint()}
|
||||
onKeyDown={handleKeyPress}
|
||||
disabled={inputDisabled}
|
||||
rows={1}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import { usePostHog } from "posthog-js/react";
|
|||
|
||||
import { StreamStatusPanel } from "@/routes/streaming/StreamDiagnostics";
|
||||
|
||||
import { PasteRecordedStepsHint } from "@/routes/workflows/copilot/PasteRecordedStepsHint";
|
||||
import { useRecordingStore } from "@/store/useRecordingStore";
|
||||
|
||||
import { HeroRecording } from "./runview/HeroRecording";
|
||||
import { HeroScreenshot } from "./runview/HeroScreenshot";
|
||||
import { RunLiveStream } from "./runview/RunLiveStream";
|
||||
|
|
@ -28,6 +31,7 @@ export function BrowserTab() {
|
|||
liveSurface,
|
||||
} = useBrowserPaneView();
|
||||
const postHog = usePostHog();
|
||||
const isRecording = useRecordingStore((s) => s.isRecording);
|
||||
|
||||
const {
|
||||
workflowRun,
|
||||
|
|
@ -61,7 +65,9 @@ export function BrowserTab() {
|
|||
const showRunStream = liveSurface === "run" && runId != null;
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-0 w-full flex-col p-3">
|
||||
<div className="flex h-full min-h-0 w-full flex-col gap-3 p-3">
|
||||
{!isRecording ? <PasteRecordedStepsHint /> : null}
|
||||
|
||||
<div className="relative flex min-h-0 flex-1 items-center justify-center overflow-hidden rounded-lg border border-border bg-slate-950">
|
||||
{view === "live" ? (
|
||||
showRunStream ? (
|
||||
|
|
|
|||
23
skyvern-frontend/src/store/usePasteSkillHintStore.ts
Normal file
23
skyvern-frontend/src/store/usePasteSkillHintStore.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { create } from "zustand";
|
||||
import { persist, createJSONStorage } from "zustand/middleware";
|
||||
|
||||
type PasteSkillHintState = {
|
||||
dismissed: boolean;
|
||||
dismiss: () => void;
|
||||
};
|
||||
|
||||
export const PASTE_SKILL_HINT_STORAGE_KEY = "skyvern.copilot.pasteSkillHint";
|
||||
|
||||
export const usePasteSkillHintStore = create<PasteSkillHintState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
dismissed: false,
|
||||
dismiss: () => set({ dismissed: true }),
|
||||
}),
|
||||
{
|
||||
name: PASTE_SKILL_HINT_STORAGE_KEY,
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
partialize: (state) => ({ dismissed: state.dismissed }),
|
||||
},
|
||||
),
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue