Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 86 additions & 4 deletions agent-reactflow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

A sample repository to have low code editor with React Flow of Agents built with Restack.

See the full documentation on our [Agent with React Flow](https://docs.restack.io/blueprints/agent-reactflow) page.

### Apps

- `frontend`: another [Next.js](https://nextjs.org/) app
- `frontend`: a [Next.js](https://nextjs.org/) app
- `backend`: a [Restack](https://restack.io/) app

## Requirements
Expand All @@ -27,11 +29,91 @@ pnpm i
pnpm run dev
```

Leveraging turborepo, this will start both frontend and backend.
Leveraging TurboRepo, this will start both frontend and backend.
Your code will be running and syncing with Restack to execute agents.

## Run agents

### from frontend
### From frontend

![Run agents from frontend](./agent-reactflow.png)

### from UI

You can run agents from the UI by clicking the "Run" button.

![Run agents from UI](./agent-post.png)

### from API

You can run agents from the API by using the generated endpoint:

`POST http://localhost:6233/api/agents/agentFlow`

### from any client

You can run agents with any client connected to Restack, for example:

```bash
pnpm schedule-agent
```

executes `scheduleAgent.ts` which will connect to Restack and execute the `agentFlow` agent.

## Send events to the Agent

### from Backend Developer UI

You can send events like or end from the UI.

![Send events from UI](./agent-event.png)

And see the events in the run:

![See events in UI](./agent-run.png)

### from API

You can send events to the agent by using the following endpoint:

`PUT http://localhost:6233/api/agents/agentFlow/:agentId/:runId`

with the payload:

```json
{
"name": "idVerification",
"input": {
"type": "id",
"documentNumber": "1234567890"
}
}
```

to send messages to the agent.

or

```json
{
"eventName": "end"
}
```

to end the conversation with the agent.

### from any client

You can send event to the agent with any client connected to Restack, for example:

Modify agentId and runId in eventAgent.ts and then run:

```bash
pnpm event-agent
```

It will connect to Restack and send an events to the agent.

## Deploy on Restack Cloud

![Run agents from frontend](./agent-reactflow.png)
To deploy the application on Restack, you can create an account at [https://console.restack.io](https://console.restack.io)
Binary file added agent-reactflow/agent-event.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added agent-reactflow/agent-post.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added agent-reactflow/agent-run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion agent-reactflow/apps/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.env
node_modules
media
dist
dist
.eslintcache
4 changes: 4 additions & 0 deletions agent-reactflow/apps/backend/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { config } from "@agent-reactflow/eslint-config/base";

/** @type {import("eslint").Linter.Config} */
export default config;
4 changes: 2 additions & 2 deletions agent-reactflow/apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
"start": "tsx src/services.ts",
"start.watch": "nodemon src/services.ts",
"dev": "open-cli http://localhost:5233 && tsx watch --include src src/services.ts",
"lint": "eslint src --fix --max-warnings 0 --cache",
"build": "tsc --build",
"clean": "rm -rf node_modules",
"workflow": "tsx ./scheduleWorkflow.ts",
"event": "tsx ./eventAgent.ts",
"restack-up": "node restack_up.mjs"
"event": "tsx ./eventAgent.ts"
},
"dependencies": {
"@restackio/ai": "^0.0.119",
Expand Down
29 changes: 29 additions & 0 deletions agent-reactflow/apps/backend/scheduleAgent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { client } from "./src/client";

export type InputSchedule = {
name: string;
};

async function scheduleAgent(input: InputSchedule) {
try {
const agentId = `${Date.now()}-agentFlow`;
const runId = await client.scheduleAgent({
agentName: "agentFlow",
agentId,
input,
});

const result = await client.getAgentResult({ agentId, runId });

console.log("Agent result:", result);

process.exit(0); // Exit the process successfully
} catch (error) {
console.error("Error scheduling agent:", error);
process.exit(1); // Exit the process with an error code
}
}

scheduleAgent({
name: "test",
});
6 changes: 3 additions & 3 deletions agent-reactflow/apps/backend/src/agents/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
condition,
log,
step,
sleep,
} from "@restackio/ai/agent";
import * as functions from "../functions";

Expand All @@ -17,11 +16,12 @@ type AgentChatOutput = {

export async function agentChat(): Promise<AgentChatOutput> {
let endReceived = false;
let messages: functions.Message[] = [];
const messages: functions.Message[] = [];

onEvent(messagesEvent, async ({ messages, stream = true }: { messages: functions.Message[], stream?: boolean }) => {
onEvent(messagesEvent, async ({ messages, tools, stream = true }: { messages: functions.Message[], tools: any, stream?: boolean }) => {
const result = await step<typeof functions>({}).llmChat({
messages,
tools,
stream
});
messages.push(result);
Expand Down
2 changes: 1 addition & 1 deletion agent-reactflow/apps/backend/src/agents/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export type AgentFlowOutput = {
}
export async function agentFlow({flowJson}: AgentFlowInput): Promise<AgentFlowOutput> {
let endReceived = false;
let eventResults: AgentFlowOutput['results'] = []
const eventResults: AgentFlowOutput['results'] = []

try {

Expand Down
33 changes: 6 additions & 27 deletions agent-reactflow/apps/backend/src/functions/llmChat.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { FunctionFailure, log } from "@restackio/ai/function";
import { ChatCompletionCreateParamsNonStreaming, ChatCompletionCreateParamsStreaming, ChatCompletionTool } from "openai/resources/chat/completions";
import { FunctionFailure, log, streamToWebsocket } from "@restackio/ai/function";
import { ChatCompletionCreateParamsNonStreaming, ChatCompletionCreateParamsStreaming } from "openai/resources/chat/completions";

import { openaiClient } from "../utils/client";
import { apiAddress } from "../client";
import { streamToWebsocket } from "./stream";
import z from "zod";

export type Message = {
role: "system" | "user" | "assistant";
Expand All @@ -16,13 +14,15 @@ export type OpenAIChatInput = {
model?: string;
messages: Message[];
stream?: boolean;
tools?: any;
};

export const llmChat = async ({
systemContent = "",
model = "gpt-4o-mini",
model = "gpt-4o",
messages,
stream = true,
tools,
}: OpenAIChatInput): Promise<Message> => {
try {
const openai = openaiClient({});
Expand All @@ -36,28 +36,7 @@ export const llmChat = async ({
: []),
...(messages ?? []),
],
tools: [
{
type: "function",
function: {
name: "reactflow",
description: "Update flow",
parameters: {
type: "object",
properties: {
flow: {
type: "object",
description: "The json object of the flow to update"
}
},
required: [
"flow"
],
additionalProperties: false,
},
},
},
],
tools,
model,
stream,
};
Expand Down
80 changes: 0 additions & 80 deletions agent-reactflow/apps/backend/src/functions/stream.ts

This file was deleted.

14 changes: 11 additions & 3 deletions agent-reactflow/apps/backend/src/workflows/endFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@ export type EndFlowInput = {

export type EndFlowOutput = {
response: "success" | "failure";
rawResponse: {};
rawResponse: any;
};

export async function endFlow(input: EndFlowInput): Promise<EndFlowOutput> {


const agentId = workflowInfo().parent?.workflowId;
const runId = workflowInfo().parent?.runId;

if (!agentId || !runId) {
throw new Error("Workflow ID or run ID is not available");
}

await step<typeof functions>({}).sendAgentEvent({
eventName: 'end',
eventInput: {},
agentId: workflowInfo().parent?.workflowId!,
runId: workflowInfo().parent?.runId!,
agentId,
runId,
});

if (input.eventData.response === "success") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,4 @@ export async function idVerification(input: DocCaptureWorkflowInput): Promise<Id
response: llmResponse,
rawResponse: verificationResult,
}

}
Loading