diff --git a/ui/admin/app/components/chat/Message.tsx b/ui/admin/app/components/chat/Message.tsx
index 3708c513e..a4b925875 100644
--- a/ui/admin/app/components/chat/Message.tsx
+++ b/ui/admin/app/components/chat/Message.tsx
@@ -1,21 +1,34 @@
import "@radix-ui/react-tooltip";
import { WrenchIcon } from "lucide-react";
-import React, { useMemo } from "react";
+import React, { useMemo, useState } from "react";
+import { useForm } from "react-hook-form";
import Markdown, { defaultUrlTransform } from "react-markdown";
import rehypeExternalLinks from "rehype-external-links";
import remarkGfm from "remark-gfm";
-import { OAuthPrompt } from "~/lib/model/chatEvents";
+import { AuthPrompt } from "~/lib/model/chatEvents";
import { Message as MessageType } from "~/lib/model/messages";
+import { PromptApiService } from "~/lib/service/api/PromptApi";
import { cn } from "~/lib/utils";
import { TypographyP } from "~/components/Typography";
import { MessageDebug } from "~/components/chat/MessageDebug";
import { ToolCallInfo } from "~/components/chat/ToolCallInfo";
+import { ControlledInput } from "~/components/form/controlledInputs";
import { CustomMarkdownComponents } from "~/components/react-markdown";
import { ToolIcon } from "~/components/tools/ToolIcon";
import { Button } from "~/components/ui/button";
import { Card } from "~/components/ui/card";
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "~/components/ui/dialog";
+import { Form } from "~/components/ui/form";
+import { Link } from "~/components/ui/link";
+import { useAsync } from "~/hooks/useAsync";
interface MessageProps {
message: MessageType;
@@ -126,7 +139,9 @@ export const Message = React.memo(({ message }: MessageProps) => {
Message.displayName = "Message";
-function PromptMessage({ prompt }: { prompt: OAuthPrompt }) {
+function PromptMessage({ prompt }: { prompt: AuthPrompt }) {
+ const [open, setOpen] = useState(false);
+
if (!prompt.metadata) return null;
return (
@@ -141,23 +156,107 @@ function PromptMessage({ prompt }: { prompt: OAuthPrompt }) {
Tool Call requires authentication
-
+ Authenticate with {prompt.metadata.category}
+
+ )}
+
+ {prompt.metadata.authType === "basic" && prompt.fields && (
+
+ )}
);
}
+
+function PromptAuthForm({
+ prompt,
+ onSuccess,
+}: {
+ prompt: AuthPrompt;
+ onSuccess: () => void;
+}) {
+ const authenticate = useAsync(PromptApiService.promptResponse, {
+ onSuccess,
+ });
+
+ const form = useForm>({
+ defaultValues: prompt.fields?.reduce(
+ (acc, field) => {
+ acc[field] = "";
+ return acc;
+ },
+ {} as Record
+ ),
+ });
+
+ const handleSubmit = form.handleSubmit(async (values) =>
+ authenticate.execute({ id: prompt.id, response: values })
+ );
+
+ return (
+
+
+ );
+}
diff --git a/ui/admin/app/lib/model/chatEvents.ts b/ui/admin/app/lib/model/chatEvents.ts
index 189bad3da..2ac485d7c 100644
--- a/ui/admin/app/lib/model/chatEvents.ts
+++ b/ui/admin/app/lib/model/chatEvents.ts
@@ -13,23 +13,30 @@ export type ToolCall = {
};
};
-type PromptOAuthMeta = {
- authType: "oauth";
- authURL: string;
+type PromptAuthMetaBase = {
category: string;
icon: string;
toolContext: string;
toolDisplayName: string;
};
-export type OAuthPrompt = {
+type PromptOAuthMeta = PromptAuthMetaBase & {
+ authType: "oauth";
+ authURL: string;
+};
+
+type PromptAuthBasicMeta = PromptAuthMetaBase & {
+ authType: "basic";
+};
+
+export type AuthPrompt = {
id?: string;
name: string;
time?: Date;
message: string;
fields?: string[];
sensitive?: boolean;
- metadata?: PromptOAuthMeta;
+ metadata?: PromptOAuthMeta | PromptAuthBasicMeta;
};
// note(ryanhopperlowe) renaming this to ChatEvent to differentiate itself specifically for a chat with an agent
@@ -45,7 +52,7 @@ export type ChatEvent = {
waitingOnModel?: boolean;
toolInput?: ToolInput;
toolCall?: ToolCall;
- prompt?: OAuthPrompt;
+ prompt?: AuthPrompt;
};
export function combineChatEvents(events: ChatEvent[]): ChatEvent[] {
diff --git a/ui/admin/app/lib/model/messages.ts b/ui/admin/app/lib/model/messages.ts
index d7813b86e..72c5c6880 100644
--- a/ui/admin/app/lib/model/messages.ts
+++ b/ui/admin/app/lib/model/messages.ts
@@ -1,4 +1,4 @@
-import { ChatEvent, OAuthPrompt, ToolCall } from "~/lib/model/chatEvents";
+import { AuthPrompt, ChatEvent, ToolCall } from "~/lib/model/chatEvents";
import { Run } from "~/lib/model/runs";
export interface Message {
@@ -6,7 +6,7 @@ export interface Message {
sender: "user" | "agent";
// note(ryanhopperlowe) we only support one tool call per message for now
// leaving it as an array case that changes in the future
- prompt?: OAuthPrompt;
+ prompt?: AuthPrompt;
tools?: ToolCall[];
runId?: string;
isLoading?: boolean;
@@ -40,7 +40,7 @@ export const toolCallMessage = (toolCall: ToolCall): Message => ({
tools: [toolCall],
});
-export const promptMessage = (prompt: OAuthPrompt, runID: string): Message => ({
+export const promptMessage = (prompt: AuthPrompt, runID: string): Message => ({
sender: "agent",
text: prompt.message,
prompt,
diff --git a/ui/admin/app/lib/routers/apiRoutes.ts b/ui/admin/app/lib/routers/apiRoutes.ts
index 4951a4f77..947be4c58 100644
--- a/ui/admin/app/lib/routers/apiRoutes.ts
+++ b/ui/admin/app/lib/routers/apiRoutes.ts
@@ -127,6 +127,10 @@ export const ApiRoutes = {
buildUrl(`/threads/${threadId}/knowledge`),
getFiles: (threadId: string) => buildUrl(`/threads/${threadId}/files`),
},
+ prompt: {
+ base: () => buildUrl("/prompt"),
+ promptResponse: () => buildUrl("/prompt"),
+ },
runs: {
base: () => buildUrl("/runs"),
getRunById: (runId: string) => buildUrl(`/runs/${runId}`),
diff --git a/ui/admin/app/lib/service/api/PromptApi.tsx b/ui/admin/app/lib/service/api/PromptApi.tsx
new file mode 100644
index 000000000..d8db2cce7
--- /dev/null
+++ b/ui/admin/app/lib/service/api/PromptApi.tsx
@@ -0,0 +1,14 @@
+import { ApiRoutes } from "~/lib/routers/apiRoutes";
+import { request } from "~/lib/service/api/primitives";
+
+async function promptResponse(prompt: {
+ id?: string;
+ response?: Record;
+}) {
+ await request({
+ method: "POST",
+ url: ApiRoutes.prompt.promptResponse().url,
+ data: prompt,
+ });
+}
+export const PromptApiService = { promptResponse };