diff --git a/sdk-react/demo/TestPage.tsx b/sdk-react/demo/TestPage.tsx
index 2cb1bd15..c841c219 100644
--- a/sdk-react/demo/TestPage.tsx
+++ b/sdk-react/demo/TestPage.tsx
@@ -3,7 +3,7 @@ import { useRun } from "../src";
import { useAgent } from "../src/hooks/useAgent";
export function TestPage(props: {}) {
- const runConfig = useRun({
+ const run = useRun({
clusterId: "01J7M4V93BBZP3YJYSKPDEGZ2T",
baseUrl: "https://api.inferable.ai",
authType: "custom",
@@ -11,14 +11,13 @@ export function TestPage(props: {}) {
});
const { Trigger, Pane } = useAgent({
- initialMessage: "System Status",
- run: runConfig,
- userInputs: ["Times to ping"],
+ prompt: "Ping the server, and return the system status at the time of the ping.",
+ run,
});
return (
-
Get the system status
+
Check system
);
diff --git a/sdk-react/src/hooks/useAgent.css b/sdk-react/src/hooks/useAgent.css
index dc572230..635c0385 100644
--- a/sdk-react/src/hooks/useAgent.css
+++ b/sdk-react/src/hooks/useAgent.css
@@ -51,92 +51,6 @@
background-color: #e4e4e7;
}
-.agent-form {
- display: flex;
- flex-direction: column;
- gap: 0.75rem;
- font-family: var(--font-sans);
- width: 90%;
- padding: 0.5rem;
- flex-shrink: 0;
-}
-
-.agent-form-group {
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
-}
-
-.agent-label {
- font-size: 0.75rem;
- font-weight: 500;
- letter-spacing: -0.011em;
- color: var(--color-text-secondary);
-}
-
-.agent-form .agent-input {
- padding: 0.375rem 0.75rem;
- font-size: 0.75rem;
- border-radius: 0.375rem;
-}
-
-.agent-form .agent-button {
- align-self: flex-start;
- padding: 0.375rem 0.75rem;
- font-size: 0.75rem;
- border-radius: 0.375rem;
-}
-
-.agent-input {
- width: 100%;
- padding: 0.5rem 0.75rem;
- font-family: var(--font-sans);
- font-size: 0.875rem;
- letter-spacing: -0.011em;
- color: var(--color-text-primary);
- border: 1px solid var(--color-border);
- border-radius: 0.375rem;
- background: var(--color-background);
- transition: all 0.2s ease;
-}
-
-.agent-input:focus {
- outline: none;
- border-color: var(--color-text-tertiary);
- box-shadow: 0 0 0 0.125rem rgba(24, 24, 27, 0.05);
-}
-
-.agent-input::placeholder {
- color: #9ca3af;
-}
-
-.agent-button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: 0.5rem 1rem;
- font-family: var(--font-sans);
- font-size: 0.875rem;
- font-weight: 500;
- letter-spacing: -0.011em;
- color: var(--color-background);
- background-color: var(--color-primary);
- border-radius: 0.375rem;
- border: 1px solid var(--color-primary);
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.agent-button:hover {
- background-color: var(--color-primary-hover);
- border-color: var(--color-primary-hover);
-}
-
-.agent-button:focus {
- outline: none;
- box-shadow: 0 0 0 0.125rem rgba(24, 24, 27, 0.05);
-}
-
.agent-pane {
position: fixed;
top: 0;
@@ -159,7 +73,6 @@
bottom: auto;
right: auto;
height: 31.25rem;
- border-radius: 0.5rem;
overflow: hidden;
}
@@ -169,7 +82,6 @@
flex-direction: column;
background: transparent;
backdrop-filter: blur(10px);
- border-radius: 0.5rem;
border: 1px solid var(--color-border);
overflow: hidden;
position: relative;
@@ -188,10 +100,9 @@
display: flex;
justify-content: flex-start;
background: transparent;
- position: sticky;
- bottom: 0;
width: 100%;
- margin-top: 1rem;
+ margin-top: 0;
+ flex-shrink: 0;
}
.agent-message-composer form {
@@ -229,7 +140,6 @@
display: flex;
align-items: center;
gap: 0.5rem;
- width: calc(100% - 4rem);
}
.agent-message-input {
@@ -283,10 +193,9 @@
}
.agent-status {
- font-size: 0.7rem;
- color: var(--color-text-tertiary);
- margin-top: 0.5rem;
- margin-left: 0.25rem;
+ color: var(--color-text-secondary);
+ margin: 0;
+ font-size: 0.75rem;
}
.agent-bottom-bar {
@@ -305,13 +214,3 @@
z-index: 10;
flex-shrink: 0;
}
-
-.agent-status {
- color: var(--color-text-secondary);
- margin: 0;
-}
-
-.agent-message-composer {
- margin-top: 0;
- flex-shrink: 0;
-}
diff --git a/sdk-react/src/hooks/useAgent.tsx b/sdk-react/src/hooks/useAgent.tsx
index 5d9c2c5e..a322681a 100644
--- a/sdk-react/src/hooks/useAgent.tsx
+++ b/sdk-react/src/hooks/useAgent.tsx
@@ -1,7 +1,7 @@
"use client";
import React, { useCallback, useEffect, useMemo, useState } from "react";
-import { Message } from "../ui/message";
+import { Message, MessageLine } from "../ui/message";
import { useRun } from "./useRun";
import { z } from "zod";
import "./useAgent.css";
@@ -12,8 +12,7 @@ interface Message {
}
type UseAgentProps = {
- initialMessage: string;
- userInputs?: string[];
+ prompt: string;
run: ReturnType;
};
@@ -22,11 +21,17 @@ type UseAgentReturn = {
Pane: React.FC<{ floating?: boolean }>;
};
-export function useAgent({
- initialMessage,
- userInputs: userInputSchema,
- run,
-}: UseAgentProps): UseAgentReturn {
+const humanStatus = (run: ReturnType["run"]) => {
+ if (!run) return "Processing request...";
+ if (run.status === "done") return "Completed";
+ if (run.status === "running") return "Running...";
+ if (run.status === "paused") return "Paused";
+ if (run.status === "pending") return "Pending...";
+ if (run.status === "failed") return "An error occurred";
+ return "";
+};
+
+export function useAgent({ prompt: initialMessage, run }: UseAgentProps): UseAgentReturn {
const [isPaneOpen, setIsPaneOpen] = useState(false);
const triggerRef = React.useRef(null);
const [panePosition, setPanePosition] = useState({ top: 0, left: 0 });
@@ -42,16 +47,33 @@ export function useAgent({
}
}, [isPaneOpen]);
+ const initRunWithMessage = useCallback(
+ (message: string) => {
+ run
+ .init()
+ .then(() =>
+ run.createMessage({
+ message,
+ type: "human",
+ })
+ )
+ .catch(error => {
+ console.error(error);
+ });
+ },
+ [run]
+ );
+
const Trigger: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
return (
{
- if (isPaneOpen) {
- setIsPaneOpen(false);
- } else {
- setIsPaneOpen(true);
+ setIsPaneOpen(true);
+
+ if (!run.run?.id) {
+ initRunWithMessage(initialMessage);
}
}}
>
@@ -61,41 +83,6 @@ export function useAgent({
};
const Pane: React.FC<{ floating?: boolean }> = ({ floating }) => {
- const hasForm = userInputSchema && Object.keys(userInputSchema).length > 0;
-
- const initRunWithMessage = useCallback(
- (message: string) => {
- run
- .init()
- .then(() =>
- run.createMessage({
- message,
- type: "human",
- })
- )
- .catch(error => {
- console.error(error);
- });
- },
- [run]
- );
-
- const handleFormSubmit = useCallback(
- (formData: Record) => {
- const messageWithData = JSON.stringify({ message: initialMessage, data: formData });
- initRunWithMessage(messageWithData);
- },
- [initialMessage, initRunWithMessage]
- );
-
- useEffect(() => {
- if (!isPaneOpen || !run.run?.id || run.messages.length > 0) return;
-
- if (!hasForm) {
- initRunWithMessage(initialMessage);
- }
- }, [isPaneOpen, run.run?.id, run.messages.length, hasForm, initialMessage, initRunWithMessage]);
-
if (!isPaneOpen) return null;
const paneStyle = floating
@@ -107,107 +94,90 @@ export function useAgent({
width: "500px",
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
}
- : undefined;
+ : {
+ position: "fixed" as const,
+ width: "60%",
+ right: "0",
+ bottom: "0",
+ top: "0",
+ height: "100%",
+ margin: "0",
+ };
return (
- {hasForm && run.messages.length === 0 && (
-
- )}
{run.messages
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
- .map((message, index) => (
-
- ))}
+ .map((message, index) =>
+ index === 0 ? (
+ ${humanStatus(run.run)}`}
+ type={"human"}
+ />
+ ) : (
+
+ )
+ )}
-
- {run.run?.status === "done"
- ? "Completed"
- : run.run?.status === "running"
- ? "Running..."
- : run.run?.status === "paused"
- ? "Paused"
- : run.run?.status === "pending"
- ? "Pending..."
- : run.run?.status === "failed"
- ? "An error occurred"
- : ""}
-
- {run.run?.status === "done" && (
-
- {!isComposing ? (
-
-
diff --git a/sdk-react/src/hooks/useRun.ts b/sdk-react/src/hooks/useRun.ts
index 0c7dc927..f835c714 100644
--- a/sdk-react/src/hooks/useRun.ts
+++ b/sdk-react/src/hooks/useRun.ts
@@ -102,8 +102,8 @@ export function useRun
>(options: UseRunOptions): U
const runId = useRef();
- useInterval(async () => {
- if (!runId.current || !initialized) {
+ const poll = useCallback(async () => {
+ if (!runId.current) {
return;
}
@@ -153,7 +153,19 @@ export function useRun>(options: UseRunOptions): U
} catch (error) {
options.onError?.(error instanceof Error ? error : new Error(String(error)));
}
- }, options.pollInterval || 1000);
+
+ await new Promise(resolve => setTimeout(resolve, options.pollInterval || 1000));
+
+ return poll();
+ }, [client]);
+
+ useEffect(() => {
+ if (!runId.current || !initialized) {
+ return;
+ }
+
+ poll();
+ }, [poll, initialized, runId]);
const createMessage = useCallback(
async (input: CreateMessageInput) => {
diff --git a/sdk-react/src/ui/message.tsx b/sdk-react/src/ui/message.tsx
index 1f162774..6be5b8b7 100644
--- a/sdk-react/src/ui/message.tsx
+++ b/sdk-react/src/ui/message.tsx
@@ -27,9 +27,6 @@ const messageSchema = z.object({
type MessageProps = {
message: unknown;
- cellNumber?: number;
- isLastMessage?: boolean;
- className?: string;
};
const msgs = (m: z.infer) => {
@@ -93,7 +90,7 @@ export const MessageLine = ({
);
};
-export function Message({ message, cellNumber, isLastMessage = false, className }: MessageProps) {
+export function Message({ message }: MessageProps) {
const parsedMessage = messageSchema.safeParse(message);
if (!parsedMessage.success) {