Skip to content

Commit ec504b8

Browse files
authored
feat: New react hooks: useInferable, useRun, and useMessages (#460)
* WIP: Stashed changes for 52f41f4d * chore: Refactor sdk-react hooks for improved structure and functionality * feat: Add tests and enhance documentation for useInferable and useMessages hooks * chore: Update README and demo for improved SDK usage examples * feat: Add demo video and create run button in React SDK * update * update * update * update * update
1 parent 3c88910 commit ec504b8

19 files changed

+1457
-725
lines changed
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Card, CardContent } from "@/components/ui/card";
2+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
3+
import { formatRelative } from "date-fns";
4+
import { startCase } from "lodash";
5+
import { ChevronDown } from "lucide-react";
6+
import { MessageContainerProps } from "./workflow-event";
7+
import { z } from "zod";
8+
9+
export function TemplateMessage({
10+
createdAt,
11+
displayableContext,
12+
data,
13+
}: MessageContainerProps<"template"> & { runId: string }) {
14+
return (
15+
<Card>
16+
<div className="flex items-center justify-between p-4 border-b">
17+
<div className="flex items-center gap-2">
18+
<div className="text-sm text-muted-foreground">
19+
{createdAt ? formatRelative(new Date(createdAt), new Date()) : "unknown"}
20+
</div>
21+
</div>
22+
</div>
23+
{Object.entries({ ...data, ...displayableContext }).map(([key, value]) => (
24+
<CardContent className="flex flex-col" key={key}>
25+
{key === "message" ? (
26+
<Collapsible>
27+
<CollapsibleTrigger className="flex items-center cursor-pointer">
28+
<p className="text-sm text-muted-foreground mr-2">{startCase(key)}</p>
29+
<ChevronDown className="w-4 h-4" />
30+
</CollapsibleTrigger>
31+
<CollapsibleContent>
32+
<p className="text-sm whitespace-pre-wrap mt-2">{value as string}</p>
33+
</CollapsibleContent>
34+
</Collapsible>
35+
) : (
36+
<>
37+
<p className="text-sm text-muted-foreground">{startCase(key)}</p>
38+
{typeof value === "object" ? (
39+
<pre className="text-sm whitespace-pre-wrap bg-muted p-2 rounded-md">
40+
{JSON.stringify(value, null, 2)}
41+
</pre>
42+
) : (
43+
<p className="text-sm whitespace-pre-wrap">{value as string}</p>
44+
)}
45+
</>
46+
)}
47+
</CardContent>
48+
))}
49+
</Card>
50+
);
51+
}

control-plane/src/modules/contract.ts

+4
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ export const definition = {
663663
headers: z.object({
664664
authorization: z.string(),
665665
}),
666+
query: z.object({
667+
after: z.string().default("0"),
668+
last: z.coerce.number().min(10).max(50).default(50),
669+
}),
666670
responses: {
667671
200: z.array(unifiedMessageDataSchema),
668672
401: z.undefined(),

control-plane/src/modules/router.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
assertMessageOfType,
1313
editHumanMessage,
1414
getRunMessagesForDisplay,
15+
getRunMessagesForDisplayWithPolling,
1516
} from "./workflows/workflow-messages";
1617
import { addMessageAndResume, assertRunReady } from "./workflows/workflows";
1718
import { runsRouter } from "./workflows/router";
@@ -281,9 +282,11 @@ export const router = initServer().router(contract, {
281282
const auth = request.request.getAuth();
282283
await auth.canAccess({ run: { clusterId, runId } });
283284

284-
const messages = await getRunMessagesForDisplay({
285+
const messages = await getRunMessagesForDisplayWithPolling({
285286
clusterId,
286287
runId,
288+
after: request.query.after,
289+
last: request.query.last,
287290
});
288291

289292
return {

control-plane/src/modules/workflows/workflow-messages.ts

+31
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,37 @@ export const getRunMessagesForDisplay = async ({
184184
});
185185
};
186186

187+
export const getRunMessagesForDisplayWithPolling = async ({
188+
clusterId,
189+
runId,
190+
last = 100,
191+
after = "0",
192+
}: {
193+
clusterId: string;
194+
runId: string;
195+
last?: number;
196+
after?: string;
197+
}): Promise<UnifiedMessage[]> => {
198+
let rowsCount = 0;
199+
const delay = 200;
200+
const timeout = 20_000;
201+
const startTime = Date.now();
202+
203+
do {
204+
const messages = await getRunMessagesForDisplay({ clusterId, runId, last, after });
205+
rowsCount = messages.length;
206+
207+
if (rowsCount > 0) {
208+
return messages;
209+
}
210+
211+
await new Promise(resolve => setTimeout(resolve, delay));
212+
} while (Date.now() - startTime < timeout);
213+
214+
// Return empty array if no messages found after timeout
215+
return [];
216+
};
217+
187218
export const getWorkflowMessages = async ({
188219
clusterId,
189220
runId,

0 commit comments

Comments
 (0)