basic suggested action scaffolding
This commit is contained in:
@@ -17,3 +17,5 @@ export const userSettingsAtom = atom<UserSettings | null>(null);
|
|||||||
|
|
||||||
// Atom for storing allow-listed environment variables
|
// Atom for storing allow-listed environment variables
|
||||||
export const envVarsAtom = atom<Record<string, string | undefined>>({});
|
export const envVarsAtom = atom<Record<string, string | undefined>>({});
|
||||||
|
|
||||||
|
export const previewPanelKeyAtom = atom<number>(0);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { atom } from "jotai";
|
import { atom } from "jotai";
|
||||||
import type { Proposal, ProposalResult } from "@/lib/schemas";
|
import type { CodeProposal, ProposalResult } from "@/lib/schemas";
|
||||||
|
|
||||||
export const proposalResultAtom = atom<ProposalResult | null>(null);
|
export const proposalResultAtom = atom<ProposalResult | null>(null);
|
||||||
|
|||||||
@@ -25,17 +25,16 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { useProposal } from "@/hooks/useProposal";
|
import { useProposal } from "@/hooks/useProposal";
|
||||||
import { Proposal } from "@/lib/schemas";
|
import {
|
||||||
|
CodeProposal,
|
||||||
|
ActionProposal,
|
||||||
|
Proposal,
|
||||||
|
SuggestedAction,
|
||||||
|
ProposalResult,
|
||||||
|
} from "@/lib/schemas";
|
||||||
import type { Message } from "@/ipc/ipc_types";
|
import type { Message } from "@/ipc/ipc_types";
|
||||||
import { isPreviewOpenAtom } from "@/atoms/viewAtoms";
|
import { isPreviewOpenAtom } from "@/atoms/viewAtoms";
|
||||||
interface ChatInputActionsProps {
|
import { useRunApp } from "@/hooks/useRunApp";
|
||||||
proposal: Proposal;
|
|
||||||
onApprove: () => void;
|
|
||||||
onReject: () => void;
|
|
||||||
isApprovable: boolean; // Can be used to enable/disable buttons
|
|
||||||
isApproving: boolean; // State for approving
|
|
||||||
isRejecting: boolean; // State for rejecting
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ChatInput({ chatId }: { chatId?: number }) {
|
export function ChatInput({ chatId }: { chatId?: number }) {
|
||||||
const [inputValue, setInputValue] = useAtom(chatInputValueAtom);
|
const [inputValue, setInputValue] = useAtom(chatInputValueAtom);
|
||||||
@@ -52,12 +51,12 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
|
|
||||||
// Use the hook to fetch the proposal
|
// Use the hook to fetch the proposal
|
||||||
const {
|
const {
|
||||||
proposal,
|
proposalResult,
|
||||||
messageId,
|
|
||||||
isLoading: isProposalLoading,
|
isLoading: isProposalLoading,
|
||||||
error: proposalError,
|
error: proposalError,
|
||||||
refreshProposal,
|
refreshProposal,
|
||||||
} = useProposal(chatId);
|
} = useProposal(chatId);
|
||||||
|
const { proposal, chatId: proposalChatId, messageId } = proposalResult ?? {};
|
||||||
|
|
||||||
const adjustHeight = () => {
|
const adjustHeight = () => {
|
||||||
const textarea = textareaRef.current;
|
const textarea = textareaRef.current;
|
||||||
@@ -205,9 +204,9 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<div className="flex flex-col space-y-2 border border-border rounded-lg bg-(--background-lighter) shadow-sm">
|
<div className="flex flex-col border border-border rounded-lg bg-(--background-lighter) shadow-sm">
|
||||||
{/* Only render ChatInputActions if proposal is loaded */}
|
{/* Only render ChatInputActions if proposal is loaded */}
|
||||||
{proposal && (
|
{proposal && proposalResult?.chatId === chatId && (
|
||||||
<ChatInputActions
|
<ChatInputActions
|
||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
onApprove={handleApprove}
|
onApprove={handleApprove}
|
||||||
@@ -267,6 +266,47 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapActionToButton(action: SuggestedAction) {
|
||||||
|
const { restartApp } = useRunApp();
|
||||||
|
switch (action.id) {
|
||||||
|
case "restart-app":
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
key={action.id}
|
||||||
|
onClick={restartApp}
|
||||||
|
>
|
||||||
|
Restart App
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
console.error(`Unsupported action: ${action.id}`);
|
||||||
|
return (
|
||||||
|
<Button variant="outline" size="sm" disabled key={action.id}>
|
||||||
|
Unsupported: {action.id}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ActionProposalActions({ proposal }: { proposal: ActionProposal }) {
|
||||||
|
return (
|
||||||
|
<div className="p-2 pb-0">
|
||||||
|
{proposal.actions.map((action) => mapActionToButton(action))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChatInputActionsProps {
|
||||||
|
proposal: Proposal;
|
||||||
|
onApprove: () => void;
|
||||||
|
onReject: () => void;
|
||||||
|
isApprovable: boolean; // Can be used to enable/disable buttons
|
||||||
|
isApproving: boolean; // State for approving
|
||||||
|
isRejecting: boolean; // State for rejecting
|
||||||
|
}
|
||||||
|
|
||||||
// Update ChatInputActions to accept props
|
// Update ChatInputActions to accept props
|
||||||
function ChatInputActions({
|
function ChatInputActions({
|
||||||
proposal,
|
proposal,
|
||||||
@@ -279,6 +319,9 @@ function ChatInputActions({
|
|||||||
const [autoApprove, setAutoApprove] = useState(false);
|
const [autoApprove, setAutoApprove] = useState(false);
|
||||||
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
||||||
|
|
||||||
|
if (proposal.type === "action-proposal") {
|
||||||
|
return <ActionProposalActions proposal={proposal}></ActionProposalActions>;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="border-b border-border">
|
<div className="border-b border-border">
|
||||||
<div className="p-2">
|
<div className="p-2">
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { useAtom, useAtomValue } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { previewModeAtom, selectedAppIdAtom } from "../../atoms/appAtoms";
|
import {
|
||||||
|
previewModeAtom,
|
||||||
|
previewPanelKeyAtom,
|
||||||
|
selectedAppIdAtom,
|
||||||
|
} from "../../atoms/appAtoms";
|
||||||
import { useLoadApp } from "@/hooks/useLoadApp";
|
import { useLoadApp } from "@/hooks/useLoadApp";
|
||||||
import { CodeView } from "./CodeView";
|
import { CodeView } from "./CodeView";
|
||||||
import { PreviewIframe } from "./PreviewIframe";
|
import { PreviewIframe } from "./PreviewIframe";
|
||||||
@@ -99,14 +103,11 @@ export function PreviewPanel() {
|
|||||||
const [isConsoleOpen, setIsConsoleOpen] = useState(false);
|
const [isConsoleOpen, setIsConsoleOpen] = useState(false);
|
||||||
const { runApp, stopApp, restartApp, error, loading, app } = useRunApp();
|
const { runApp, stopApp, restartApp, error, loading, app } = useRunApp();
|
||||||
const runningAppIdRef = useRef<number | null>(null);
|
const runningAppIdRef = useRef<number | null>(null);
|
||||||
const [key, setKey] = useState(0);
|
const key = useAtomValue(previewPanelKeyAtom);
|
||||||
|
|
||||||
const handleRestart = useCallback(() => {
|
const handleRestart = useCallback(() => {
|
||||||
if (selectedAppId !== null) {
|
restartApp();
|
||||||
restartApp(selectedAppId);
|
}, [restartApp]);
|
||||||
setKey((prevKey) => prevKey + 1);
|
|
||||||
}
|
|
||||||
}, [selectedAppId, restartApp]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const previousAppId = runningAppIdRef.current;
|
const previousAppId = runningAppIdRef.current;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import type { Proposal, ProposalResult } from "@/lib/schemas"; // Import Proposal type
|
import type { CodeProposal, ProposalResult } from "@/lib/schemas"; // Import Proposal type
|
||||||
import { proposalResultAtom } from "@/atoms/proposalAtoms";
|
import { proposalResultAtom } from "@/atoms/proposalAtoms";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
export function useProposal(chatId?: number | undefined) {
|
export function useProposal(chatId?: number | undefined) {
|
||||||
@@ -8,40 +8,35 @@ export function useProposal(chatId?: number | undefined) {
|
|||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const fetchProposal = useCallback(
|
const fetchProposal = useCallback(async () => {
|
||||||
async (innerChatId?: number) => {
|
if (chatId === undefined) {
|
||||||
chatId = chatId ?? innerChatId;
|
setProposalResult(null);
|
||||||
console.log("fetching proposal for chatId", chatId);
|
setIsLoading(false);
|
||||||
if (chatId === undefined) {
|
|
||||||
setProposalResult(null);
|
|
||||||
setIsLoading(false);
|
|
||||||
setError(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsLoading(true);
|
|
||||||
setError(null);
|
setError(null);
|
||||||
setProposalResult(null); // Reset on new fetch
|
return;
|
||||||
try {
|
}
|
||||||
// Type assertion might be needed depending on how IpcClient is typed
|
setIsLoading(true);
|
||||||
const result = (await IpcClient.getInstance().getProposal(
|
setError(null);
|
||||||
chatId
|
setProposalResult(null); // Reset on new fetch
|
||||||
)) as ProposalResult | null;
|
try {
|
||||||
|
// Type assertion might be needed depending on how IpcClient is typed
|
||||||
|
const result = (await IpcClient.getInstance().getProposal(
|
||||||
|
chatId
|
||||||
|
)) as ProposalResult | null;
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
setProposalResult(result);
|
setProposalResult(result);
|
||||||
} else {
|
} else {
|
||||||
setProposalResult(null); // Explicitly set to null if IPC returns null
|
setProposalResult(null); // Explicitly set to null if IPC returns null
|
||||||
}
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error("Error fetching proposal:", err);
|
|
||||||
setError(err.message || "Failed to fetch proposal");
|
|
||||||
setProposalResult(null); // Clear proposal data on error
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
},
|
} catch (err: any) {
|
||||||
[chatId]
|
console.error("Error fetching proposal:", err);
|
||||||
); // Depend on chatId
|
setError(err.message || "Failed to fetch proposal");
|
||||||
|
setProposalResult(null); // Clear proposal data on error
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}, [chatId]); // Depend on chatId
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchProposal();
|
fetchProposal();
|
||||||
@@ -52,18 +47,10 @@ export function useProposal(chatId?: number | undefined) {
|
|||||||
// };
|
// };
|
||||||
}, [fetchProposal]); // Re-run effect if fetchProposal changes (due to chatId change)
|
}, [fetchProposal]); // Re-run effect if fetchProposal changes (due to chatId change)
|
||||||
|
|
||||||
const refreshProposal = useCallback(
|
|
||||||
(chatId?: number) => {
|
|
||||||
fetchProposal(chatId);
|
|
||||||
},
|
|
||||||
[fetchProposal]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
proposal: proposalResult?.proposal ?? null,
|
proposalResult: proposalResult,
|
||||||
messageId: proposalResult?.messageId,
|
|
||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
refreshProposal, // Expose the refresh function
|
refreshProposal: fetchProposal, // Expose the refresh function
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import { useState, useCallback } from "react";
|
import { useState, useCallback } from "react";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { appOutputAtom, appUrlAtom, currentAppAtom } from "@/atoms/appAtoms";
|
import {
|
||||||
import { useAtom, useSetAtom } from "jotai";
|
appOutputAtom,
|
||||||
|
appUrlAtom,
|
||||||
|
currentAppAtom,
|
||||||
|
previewPanelKeyAtom,
|
||||||
|
selectedAppIdAtom,
|
||||||
|
} from "@/atoms/appAtoms";
|
||||||
|
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||||
import { App } from "@/ipc/ipc_types";
|
import { App } from "@/ipc/ipc_types";
|
||||||
|
|
||||||
export function useRunApp() {
|
export function useRunApp() {
|
||||||
@@ -10,7 +16,8 @@ export function useRunApp() {
|
|||||||
const [app, setApp] = useAtom(currentAppAtom);
|
const [app, setApp] = useAtom(currentAppAtom);
|
||||||
const setAppOutput = useSetAtom(appOutputAtom);
|
const setAppOutput = useSetAtom(appOutputAtom);
|
||||||
const [appUrlObj, setAppUrlObj] = useAtom(appUrlAtom);
|
const [appUrlObj, setAppUrlObj] = useAtom(appUrlAtom);
|
||||||
|
const setPreviewPanelKey = useSetAtom(previewPanelKeyAtom);
|
||||||
|
const appId = useAtomValue(selectedAppIdAtom);
|
||||||
const runApp = useCallback(async (appId: number) => {
|
const runApp = useCallback(async (appId: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -63,7 +70,10 @@ export function useRunApp() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const restartApp = useCallback(async (appId: number) => {
|
const restartApp = useCallback(async () => {
|
||||||
|
if (appId === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const ipcClient = IpcClient.getInstance();
|
const ipcClient = IpcClient.getInstance();
|
||||||
@@ -91,6 +101,7 @@ export function useRunApp() {
|
|||||||
console.error(`Error restarting app ${appId}:`, error);
|
console.error(`Error restarting app ${appId}:`, error);
|
||||||
setError(error instanceof Error ? error : new Error(String(error)));
|
setError(error instanceof Error ? error : new Error(String(error)));
|
||||||
} finally {
|
} finally {
|
||||||
|
setPreviewPanelKey((prevKey) => prevKey + 1);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
|||||||
import { useLoadVersions } from "./useLoadVersions";
|
import { useLoadVersions } from "./useLoadVersions";
|
||||||
import { showError } from "@/lib/toast";
|
import { showError } from "@/lib/toast";
|
||||||
import { useProposal } from "./useProposal";
|
import { useProposal } from "./useProposal";
|
||||||
|
import { useSearch } from "@tanstack/react-router";
|
||||||
|
|
||||||
export function getRandomString() {
|
export function getRandomString() {
|
||||||
return Math.random().toString(36).substring(2, 15);
|
return Math.random().toString(36).substring(2, 15);
|
||||||
@@ -31,7 +32,8 @@ export function useStreamChat() {
|
|||||||
const { refreshApp } = useLoadApp(selectedAppId);
|
const { refreshApp } = useLoadApp(selectedAppId);
|
||||||
const setStreamCount = useSetAtom(chatStreamCountAtom);
|
const setStreamCount = useSetAtom(chatStreamCountAtom);
|
||||||
const { refreshVersions } = useLoadVersions(selectedAppId);
|
const { refreshVersions } = useLoadVersions(selectedAppId);
|
||||||
const { refreshProposal } = useProposal();
|
const { id: chatId } = useSearch({ from: "/chat" });
|
||||||
|
const { refreshProposal } = useProposal(chatId);
|
||||||
const streamMessage = useCallback(
|
const streamMessage = useCallback(
|
||||||
async ({
|
async ({
|
||||||
prompt,
|
prompt,
|
||||||
@@ -91,7 +93,7 @@ export function useStreamChat() {
|
|||||||
if (response.updatedFiles) {
|
if (response.updatedFiles) {
|
||||||
setIsPreviewOpen(true);
|
setIsPreviewOpen(true);
|
||||||
}
|
}
|
||||||
refreshProposal(chatId);
|
refreshProposal();
|
||||||
|
|
||||||
// Keep the same as below
|
// Keep the same as below
|
||||||
setIsStreaming(false);
|
setIsStreaming(false);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ipcMain, type IpcMainInvokeEvent } from "electron";
|
import { ipcMain, type IpcMainInvokeEvent } from "electron";
|
||||||
import type { Proposal } from "@/lib/schemas";
|
import type { CodeProposal, ProposalResult } from "@/lib/schemas";
|
||||||
import { db } from "../../db";
|
import { db } from "../../db";
|
||||||
import { messages } from "../../db/schema";
|
import { messages } from "../../db/schema";
|
||||||
import { desc, eq, and, Update } from "drizzle-orm";
|
import { desc, eq, and, Update } from "drizzle-orm";
|
||||||
@@ -19,13 +19,6 @@ interface ParsedProposal {
|
|||||||
title: string;
|
title: string;
|
||||||
files: string[];
|
files: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define return type for getProposalHandler
|
|
||||||
interface ProposalResult {
|
|
||||||
proposal: Proposal;
|
|
||||||
messageId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isParsedProposal(obj: any): obj is ParsedProposal {
|
function isParsedProposal(obj: any): obj is ParsedProposal {
|
||||||
return (
|
return (
|
||||||
obj &&
|
obj &&
|
||||||
@@ -54,12 +47,23 @@ const getProposalHandler = async (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (latestAssistantMessage?.approvalState === "rejected") {
|
||||||
latestAssistantMessage?.approvalState === "approved" ||
|
|
||||||
latestAssistantMessage?.approvalState === "rejected"
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (latestAssistantMessage?.approvalState === "approved") {
|
||||||
|
return {
|
||||||
|
proposal: {
|
||||||
|
type: "action-proposal",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
id: "restart-app",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
chatId: chatId,
|
||||||
|
messageId: latestAssistantMessage.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (latestAssistantMessage?.content && latestAssistantMessage.id) {
|
if (latestAssistantMessage?.content && latestAssistantMessage.id) {
|
||||||
const messageId = latestAssistantMessage.id; // Get the message ID
|
const messageId = latestAssistantMessage.id; // Get the message ID
|
||||||
@@ -74,7 +78,8 @@ const getProposalHandler = async (
|
|||||||
|
|
||||||
// Check if we have enough information to create a proposal
|
// Check if we have enough information to create a proposal
|
||||||
if (proposalTitle || proposalFiles.length > 0) {
|
if (proposalTitle || proposalFiles.length > 0) {
|
||||||
const proposal: Proposal = {
|
const proposal: CodeProposal = {
|
||||||
|
type: "code-proposal",
|
||||||
// Use parsed title or a default title if summary tag is missing but write tags exist
|
// Use parsed title or a default title if summary tag is missing but write tags exist
|
||||||
title: proposalTitle ?? "Proposed File Changes",
|
title: proposalTitle ?? "Proposed File Changes",
|
||||||
securityRisks: [], // Keep empty
|
securityRisks: [], // Keep empty
|
||||||
@@ -85,7 +90,7 @@ const getProposalHandler = async (
|
|||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
console.log("Generated proposal on the fly:", proposal);
|
console.log("Generated proposal on the fly:", proposal);
|
||||||
return { proposal, messageId }; // Return proposal and messageId
|
return { proposal, chatId, messageId }; // Return proposal and messageId
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
"No relevant tags found in the latest assistant message content."
|
"No relevant tags found in the latest assistant message content."
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import type {
|
|||||||
Message,
|
Message,
|
||||||
Version,
|
Version,
|
||||||
} from "./ipc_types";
|
} from "./ipc_types";
|
||||||
import type { Proposal, ProposalResult } from "@/lib/schemas";
|
import type { CodeProposal, ProposalResult } from "@/lib/schemas";
|
||||||
import { showError } from "@/lib/toast";
|
import { showError } from "@/lib/toast";
|
||||||
|
|
||||||
export interface ChatStreamCallbacks {
|
export interface ChatStreamCallbacks {
|
||||||
|
|||||||
@@ -111,14 +111,26 @@ export interface FileChange {
|
|||||||
summary: string;
|
summary: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// New Proposal interface
|
export interface CodeProposal {
|
||||||
export interface Proposal {
|
type: "code-proposal";
|
||||||
title: string;
|
title: string;
|
||||||
securityRisks: SecurityRisk[];
|
securityRisks: SecurityRisk[];
|
||||||
filesChanged: FileChange[];
|
filesChanged: FileChange[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SuggestedAction {
|
||||||
|
id: "restart-app";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActionProposal {
|
||||||
|
type: "action-proposal";
|
||||||
|
actions: SuggestedAction[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Proposal = CodeProposal | ActionProposal;
|
||||||
|
|
||||||
export interface ProposalResult {
|
export interface ProposalResult {
|
||||||
proposal: Proposal;
|
proposal: Proposal;
|
||||||
|
chatId: number;
|
||||||
messageId: number;
|
messageId: number;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user