├── .gitignore ├── agent-apis ├── .env.example ├── package.json ├── readme.md ├── scheduleWorkflow.ts ├── src │ ├── client.ts │ ├── functions │ │ ├── index.ts │ │ ├── llm.ts │ │ └── weather.ts │ ├── services.ts │ └── workflows │ │ ├── index.ts │ │ └── multistep.ts ├── tsconfig.json ├── workflow_get.png └── workflow_run.png ├── agent-chat ├── .env.example ├── chat_post.png ├── chat_put.png ├── chat_run.png ├── eventAgent.ts ├── package.json ├── readme.md ├── scheduleAgent.ts ├── src │ ├── agents │ │ ├── agent.ts │ │ └── index.ts │ ├── client.ts │ ├── functions │ │ ├── index.ts │ │ └── llmChat.ts │ ├── services.ts │ └── utils │ │ └── client.ts └── tsconfig.json ├── agent-rag ├── .env.example ├── chat_post.png ├── chat_put.png ├── chat_run.png ├── eventAgent.ts ├── package.json ├── readme.md ├── scheduleAgent.ts ├── src │ ├── agents │ │ ├── agent.ts │ │ └── index.ts │ ├── client.ts │ ├── functions │ │ ├── index.ts │ │ ├── llmChat.ts │ │ └── lookupSales.ts │ ├── services.ts │ └── utils │ │ └── client.ts └── tsconfig.json ├── agent-reactflow ├── .dockerignore ├── .gitignore ├── .vscode │ └── settings.json ├── Dockerfile ├── README.md ├── agent-event.png ├── agent-post.png ├── agent-reactflow.png ├── agent-run.png ├── apps │ ├── backend │ │ ├── .env.example │ │ ├── .gitignore │ │ ├── eslint.config.mjs │ │ ├── eventAgent.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── pnpm-lock.yaml │ │ ├── readme.md │ │ ├── scheduleAgent.ts │ │ ├── src │ │ │ ├── agents │ │ │ │ ├── chat.ts │ │ │ │ ├── flow.ts │ │ │ │ └── index.ts │ │ │ ├── client.ts │ │ │ ├── functions │ │ │ │ ├── dslInterpreter.ts │ │ │ │ ├── humanVerification.ts │ │ │ │ ├── idVerification.ts │ │ │ │ ├── index.ts │ │ │ │ ├── llmChat.ts │ │ │ │ ├── llmResponse.ts │ │ │ │ ├── mockFlow.ts │ │ │ │ └── sendAgentEvent.ts │ │ │ ├── services.ts │ │ │ ├── utils │ │ │ │ └── client.ts │ │ │ └── workflows │ │ │ │ ├── endFlow.ts │ │ │ │ ├── idVerification.ts │ │ │ │ ├── index.ts │ │ │ │ └── manualVerification.ts │ │ └── tsconfig.json │ └── frontend │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app │ │ ├── actions │ │ │ ├── agent.ts │ │ │ └── workflow.ts │ │ ├── api │ │ │ └── chat │ │ │ │ └── route.ts │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── GeistMonoVF.woff │ │ │ └── GeistVF.woff │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx │ │ ├── components.json │ │ ├── components │ │ ├── agent-builder.tsx │ │ ├── agent-chat.tsx │ │ ├── agent-header.tsx │ │ ├── agent-test.tsx │ │ ├── flow │ │ │ ├── autoLayout.tsx │ │ │ ├── baseEdge.tsx │ │ │ ├── baseHandle.tsx │ │ │ ├── baseNode.tsx │ │ │ ├── defaultNode.tsx │ │ │ ├── nodeHeader.tsx │ │ │ ├── nodeStatusIndicator.tsx │ │ │ ├── workflowEdge.tsx │ │ │ └── workflowNode.tsx │ │ ├── theme │ │ │ ├── theme-context.tsx │ │ │ └── theme-provider.tsx │ │ ├── ui │ │ │ ├── badge.tsx │ │ │ ├── button.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── separator.tsx │ │ │ └── textarea.tsx │ │ ├── workflow-edit.tsx │ │ └── workflow-selector.tsx │ │ ├── lib │ │ ├── agent-init.tsx │ │ ├── utils.ts │ │ └── workflowData.tsx │ │ ├── next.config.js │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── public │ │ ├── file-text.svg │ │ ├── globe.svg │ │ ├── next.svg │ │ ├── turborepo-dark.svg │ │ ├── turborepo-light.svg │ │ ├── vercel.svg │ │ └── window.svg │ │ ├── tailwind.config.ts │ │ ├── tsconfig copy.json │ │ └── tsconfig.json ├── package.json ├── packages │ ├── eslint-config │ │ ├── README.md │ │ ├── base.js │ │ ├── next.js │ │ ├── package.json │ │ └── react-internal.js │ └── typescript-config │ │ ├── base.json │ │ ├── nextjs.json │ │ ├── package.json │ │ └── react-library.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json ├── agent-stream ├── .env.example ├── chat_post.png ├── chat_put.png ├── chat_run.png ├── eventAgent.ts ├── package.json ├── readme.md ├── scheduleAgent.ts ├── src │ ├── agents │ │ ├── agent.ts │ │ └── index.ts │ ├── client.ts │ ├── functions │ │ ├── index.ts │ │ └── llmChat.ts │ ├── services.ts │ └── utils │ │ └── client.ts └── tsconfig.json ├── agent-telephony └── twilio-livekit │ ├── agent │ ├── .env.example │ ├── chat_post.png │ ├── chat_put.png │ ├── chat_run.png │ ├── eventAgent.ts │ ├── package.json │ ├── readme.md │ ├── scheduleAgent.ts │ ├── src │ │ ├── agents │ │ │ ├── agent.ts │ │ │ └── index.ts │ │ ├── client.ts │ │ ├── functions │ │ │ ├── contextDocs.ts │ │ │ ├── index.ts │ │ │ ├── livekitCall.ts │ │ │ ├── livekitCreateRoom.ts │ │ │ ├── livekitDeleteRoom.ts │ │ │ ├── livekitDispatch.ts │ │ │ ├── livekitOutboundTrunk.ts │ │ │ ├── livekitRecording.ts │ │ │ ├── livekitSendData.ts │ │ │ ├── livekitToken.ts │ │ │ ├── llmLogic.ts │ │ │ ├── llmTalk.ts │ │ │ └── sendAgentEvent.ts │ │ ├── services.ts │ │ ├── utils │ │ │ ├── livekitDispatchClient.ts │ │ │ ├── livekitEgressClient.ts │ │ │ ├── livekitRoomClient.ts │ │ │ ├── livekitSipClient.ts │ │ │ └── openaiClient.ts │ │ └── workflows │ │ │ ├── index.ts │ │ │ └── logic.ts │ └── tsconfig.json │ ├── agent_call.png │ ├── agent_replay.png │ ├── agent_voice_post.png │ ├── livekit-pipeline │ ├── .dockerignore │ ├── .env.example │ ├── .eslintrc │ ├── .gitignore │ ├── .prettierrc │ ├── Dockerfile │ ├── README.md │ ├── package.json │ ├── src │ │ ├── metrics.ts │ │ ├── pipeline.ts │ │ ├── restack │ │ │ ├── client.ts │ │ │ └── utils.ts │ │ ├── utils.ts │ │ └── worker.ts │ └── tsconfig.json │ └── readme.md ├── agent-todo ├── .env.example ├── chat_post.png ├── chat_put.png ├── chat_run.png ├── eventAgent.ts ├── package-lock.json ├── package.json ├── readme.md ├── scheduleAgent.ts ├── src │ ├── agents │ │ ├── agent.ts │ │ └── index.ts │ ├── client.ts │ ├── functions │ │ ├── createTodo.ts │ │ ├── getRandom.ts │ │ ├── getResult.ts │ │ ├── getTools.ts │ │ ├── index.ts │ │ ├── llmChat.ts │ │ ├── sendEvent.ts │ │ ├── types.ts │ │ └── utils │ │ │ └── responseUtils.ts │ ├── services.ts │ ├── utils │ │ └── client.ts │ └── workflows │ │ ├── executeTodo.ts │ │ └── index.ts └── tsconfig.json ├── agent-tool ├── .env.example ├── chat_post.png ├── chat_put.png ├── chat_run.png ├── eventAgent.ts ├── package.json ├── readme.md ├── scheduleAgent.ts ├── src │ ├── agents │ │ ├── agent.ts │ │ └── index.ts │ ├── client.ts │ ├── functions │ │ ├── getTools.ts │ │ ├── index.ts │ │ ├── llmChat.ts │ │ ├── lookupSales.ts │ │ └── toolTypes.ts │ ├── services.ts │ └── utils │ │ └── client.ts └── tsconfig.json ├── agent-voice └── livekit │ ├── agent │ ├── .env.example │ ├── chat_post.png │ ├── chat_put.png │ ├── chat_run.png │ ├── eventAgent.ts │ ├── package.json │ ├── readme.md │ ├── scheduleAgent.ts │ ├── src │ │ ├── agents │ │ │ ├── agent.ts │ │ │ └── index.ts │ │ ├── client.ts │ │ ├── functions │ │ │ ├── index.ts │ │ │ └── llmChat.ts │ │ ├── services.ts │ │ └── utils │ │ │ └── client.ts │ └── tsconfig.json │ ├── agent_voice_livekit.png │ ├── agent_voice_post.png │ ├── agent_voice_replay.png │ ├── livekit-pipeline │ ├── .dockerignore │ ├── .env.example │ ├── .eslintrc │ ├── .gitignore │ ├── .prettierrc │ ├── Dockerfile │ ├── README.md │ ├── package.json │ ├── src │ │ └── pipeline.ts │ └── tsconfig.json │ └── readme.md ├── child-workflows ├── .env.example ├── .prettierrc ├── package.json ├── readme.md ├── scheduleWorkflow.ts ├── src │ ├── client.ts │ ├── functions │ │ ├── hello.ts │ │ └── index.ts │ ├── services.ts │ └── workflows │ │ ├── child.ts │ │ ├── index.ts │ │ └── parent.ts └── tsconfig.json ├── features-alpha └── encryption │ ├── .env.example │ ├── package.json │ ├── pnpm-lock.yaml │ ├── readme.md │ ├── scheduleWorkflow.ts │ ├── src │ ├── client.ts │ ├── codec-server.ts │ ├── crypto.ts │ ├── data-converter.ts │ ├── encryption-codec.ts │ ├── functions │ │ ├── goodbye.ts │ │ ├── index.ts │ │ └── openai │ │ │ ├── chat │ │ │ ├── completionsBase.ts │ │ │ ├── completionsStream.ts │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── thread │ │ │ ├── createAssistant.ts │ │ │ ├── createMessageOnThread.ts │ │ │ ├── createThread.ts │ │ │ ├── index.ts │ │ │ └── runThread.ts │ │ │ ├── types │ │ │ ├── events.ts │ │ │ └── index.ts │ │ │ └── utils │ │ │ ├── aggregateStream.ts │ │ │ ├── client.ts │ │ │ ├── cost.ts │ │ │ ├── index.ts │ │ │ └── mergeToolCalls.ts │ ├── services.ts │ └── workflows │ │ ├── hello.ts │ │ └── index.ts │ └── tsconfig.json ├── readme.md └── refactor-needed ├── human-loop ├── package.json ├── readme.md ├── schedule.ts ├── src │ ├── agents │ │ ├── humanLoop.ts │ │ └── index.ts │ ├── client.ts │ ├── events │ │ ├── endEvent.ts │ │ ├── feedbackEvent.ts │ │ └── index.ts │ ├── functions │ │ ├── feedback.ts │ │ ├── goodbye.ts │ │ └── index.ts │ └── services.ts └── tsconfig.json ├── posthog ├── .env.example ├── package.json ├── readme.md ├── scheduleWorkflow.ts ├── src │ ├── client.ts │ ├── functions │ │ ├── index.ts │ │ ├── linear │ │ │ ├── createComment.ts │ │ │ ├── createIssue.ts │ │ │ ├── index.ts │ │ │ └── utils │ │ │ │ └── client.ts │ │ ├── openai │ │ │ ├── chat │ │ │ │ ├── completionsBase.ts │ │ │ │ ├── completionsStream.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── thread │ │ │ │ ├── createAssistant.ts │ │ │ │ ├── createMessageOnThread.ts │ │ │ │ ├── createThread.ts │ │ │ │ ├── index.ts │ │ │ │ └── runThread.ts │ │ │ ├── types │ │ │ │ ├── events.ts │ │ │ │ └── index.ts │ │ │ └── utils │ │ │ │ ├── aggregateStream.ts │ │ │ │ ├── client.ts │ │ │ │ ├── cost.ts │ │ │ │ ├── index.ts │ │ │ │ └── mergeToolCalls.ts │ │ ├── posthog │ │ │ ├── index.ts │ │ │ └── sessionRecording │ │ │ │ ├── blobChunks.ts │ │ │ │ ├── queryEvents.ts │ │ │ │ ├── recordings.ts │ │ │ │ ├── snapshotBlob.ts │ │ │ │ └── snapshots.ts │ │ └── utils │ │ │ ├── index.ts │ │ │ └── sendEventToWorkflow.ts │ ├── services.ts │ └── workflows │ │ ├── chunk.ts │ │ ├── digest.ts │ │ ├── index.ts │ │ └── recording.ts └── tsconfig.json └── voice ├── .env.example ├── Dockerfile.server ├── Dockerfile.services ├── callWorkflow.ts ├── package.json ├── readme.md ├── src ├── client.ts ├── functions │ ├── deepgram │ │ ├── index.ts │ │ ├── listen.ts │ │ ├── speak.ts │ │ └── utils │ │ │ └── client.ts │ ├── erp │ │ ├── checkInventory.ts │ │ ├── checkPrice.ts │ │ ├── index.ts │ │ ├── placeOrder.ts │ │ └── tools.ts │ ├── index.ts │ ├── openai │ │ ├── chat │ │ │ ├── completionsBase.ts │ │ │ ├── completionsStream.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── prompt.ts │ │ ├── thread │ │ │ ├── createAssistant.ts │ │ │ ├── createMessageOnThread.ts │ │ │ ├── createThread.ts │ │ │ ├── index.ts │ │ │ └── runThread.ts │ │ ├── types │ │ │ ├── events.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── aggregateStream.ts │ │ │ ├── client.ts │ │ │ ├── cost.ts │ │ │ ├── index.ts │ │ │ └── mergeToolCalls.ts │ ├── twilio │ │ ├── call.ts │ │ ├── index.ts │ │ └── utils │ │ │ └── client.ts │ ├── utils │ │ ├── index.ts │ │ └── sendEventToWorkflow.ts │ └── websocket │ │ ├── index.ts │ │ ├── listen.ts │ │ ├── send.ts │ │ ├── types │ │ ├── events.ts │ │ └── index.ts │ │ └── utils │ │ └── client.ts ├── server.ts ├── services.ts └── workflows │ ├── conversation │ ├── conversation.ts │ └── events.ts │ ├── index.ts │ ├── room │ ├── events.ts │ └── room.ts │ └── twilioCall.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env 4 | .npmrc 5 | tsconfig.tsbuildinfo 6 | .DS_Store 7 | pnpm-lock.yaml 8 | package-lock.yaml -------------------------------------------------------------------------------- /agent-apis/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /agent-apis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agent-apis", 3 | "version": "1.0.0", 4 | "description": "Agent with third party APIs", 5 | "main": "index.js", 6 | "scripts": { 7 | "start.watch": "nodemon src/services.ts", 8 | "dev": "npm run start.watch", 9 | "build": "tsc --build", 10 | "start": "node dist/services.js", 11 | "clean": "rm -rf node_modules", 12 | "schedule": "ts-node ./scheduleWorkflow.ts" 13 | }, 14 | "nodemonConfig": { 15 | "execMap": { 16 | "ts": "ts-node" 17 | }, 18 | "ext": "ts", 19 | "watch": [ 20 | "src" 21 | ] 22 | }, 23 | "dependencies": { 24 | "@restackio/ai": "^0.0.124", 25 | "@temporalio/workflow": "1.11.8", 26 | "dotenv": "^16.4.7", 27 | "openai": "^4.80.1" 28 | }, 29 | "devDependencies": { 30 | "@types/node": "^20.16.9", 31 | "nodemon": "^2.0.22", 32 | "ts-node": "^10.9.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /agent-apis/scheduleWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | 3 | export type InputSchedule = { 4 | name: string; 5 | }; 6 | 7 | async function scheduleWorkflow(input: InputSchedule) { 8 | try { 9 | const workflowId = `${Date.now()}-multistepWorkflow`; 10 | const runId = await client.scheduleWorkflow({ 11 | workflowName: "multistepWorkflow", 12 | workflowId, 13 | input, 14 | }); 15 | 16 | const result = await client.getWorkflowResult({ workflowId, runId }); 17 | 18 | console.log("Workflow result:", result); 19 | 20 | process.exit(0); // Exit the process successfully 21 | } catch (error) { 22 | console.error("Error scheduling workflow:", error); 23 | process.exit(1); // Exit the process with an error code 24 | } 25 | } 26 | 27 | scheduleWorkflow({ 28 | name: "test", 29 | }); 30 | -------------------------------------------------------------------------------- /agent-apis/src/client.ts: -------------------------------------------------------------------------------- 1 | import Restack from "@restackio/ai"; 2 | 3 | import "dotenv/config"; 4 | 5 | export const connectionOptions = { 6 | engineId: process.env.RESTACK_ENGINE_ID!, 7 | address: process.env.RESTACK_ENGINE_ADDRESS!, 8 | apiKey: process.env.RESTACK_ENGINE_API_KEY!, 9 | apiAddress: process.env.RESTACK_ENGINE_API_ADDRESS!, 10 | }; 11 | 12 | export const client = new Restack( 13 | process.env.RESTACK_ENGINE_API_KEY ? connectionOptions : undefined 14 | ); 15 | -------------------------------------------------------------------------------- /agent-apis/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./llm"; 2 | export * from "./weather"; 3 | -------------------------------------------------------------------------------- /agent-apis/src/functions/weather.ts: -------------------------------------------------------------------------------- 1 | import { FunctionFailure, log } from "@restackio/ai/function"; 2 | 3 | export const weather = async (): Promise => { 4 | const url = 5 | "https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m"; 6 | 7 | try { 8 | const response = await fetch(url); 9 | log.info("response", { response }); 10 | 11 | if (response.ok) { 12 | const data = await response.json(); 13 | log.info("weather data", { data }); 14 | return JSON.stringify(data); 15 | } else { 16 | log.error(`Error: ${response.status}`); 17 | throw new Error(`Error: ${response.status}`); 18 | } 19 | } catch (error) { 20 | log.error(`Error: ${error}`); 21 | throw FunctionFailure.nonRetryable(`Error fetching weather data: ${error}`); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /agent-apis/src/services.ts: -------------------------------------------------------------------------------- 1 | import { llm, weather } from "./functions"; 2 | import { client } from "./client"; 3 | 4 | async function services() { 5 | const workflowsPath = require.resolve("./workflows"); 6 | try { 7 | await Promise.all([ 8 | client.startService({ 9 | workflowsPath, 10 | functions: { llm, weather }, 11 | }), 12 | ]); 13 | 14 | console.log("Services running successfully."); 15 | } catch (e) { 16 | console.error("Failed to run services", e); 17 | } 18 | } 19 | 20 | services().catch((err) => { 21 | console.error("Error running services:", err); 22 | }); 23 | -------------------------------------------------------------------------------- /agent-apis/src/workflows/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./multistep"; 2 | -------------------------------------------------------------------------------- /agent-apis/src/workflows/multistep.ts: -------------------------------------------------------------------------------- 1 | import { step } from "@restackio/ai/workflow"; 2 | import * as functions from "../functions"; 3 | 4 | interface Input { 5 | name: string; 6 | } 7 | 8 | export async function multistepWorkflow({ name }: Input) { 9 | const userContent = `Greet this person: ${name}.`; 10 | 11 | // Step 1 get weather data from external API 12 | const weatherData = await step({}).weather(); 13 | 14 | // Step 1 create greeting message with openai 15 | 16 | const openaiOutput = await step({}).llm({ 17 | systemContent: `You are a personal assitant and have access to weather data ${weatherData}. Always greet person with relevant info from weather data`, 18 | userContent, 19 | }); 20 | 21 | return { 22 | message: openaiOutput, 23 | weatherData, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /agent-apis/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "Node16", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "outDir": "./dist", 9 | "rootDir": "./src", 10 | "resolveJsonModule": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } -------------------------------------------------------------------------------- /agent-apis/workflow_get.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-apis/workflow_get.png -------------------------------------------------------------------------------- /agent-apis/workflow_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-apis/workflow_run.png -------------------------------------------------------------------------------- /agent-chat/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | 3 | -------------------------------------------------------------------------------- /agent-chat/chat_post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-chat/chat_post.png -------------------------------------------------------------------------------- /agent-chat/chat_put.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-chat/chat_put.png -------------------------------------------------------------------------------- /agent-chat/chat_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-chat/chat_run.png -------------------------------------------------------------------------------- /agent-chat/eventAgent.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | 3 | export type EventInput = { 4 | agentId: string; 5 | runId: string; 6 | }; 7 | 8 | async function eventAgent(input: EventInput) { 9 | try { 10 | await client.sendAgentEvent({ 11 | event: { 12 | name: "message", 13 | input: { content: "Tell me a joke" }, 14 | }, 15 | agent: { 16 | agentId: input.agentId, 17 | runId: input.runId, 18 | }, 19 | }); 20 | 21 | await client.sendAgentEvent({ 22 | event: { 23 | name: "end", 24 | }, 25 | agent: { 26 | agentId: input.agentId, 27 | runId: input.runId, 28 | }, 29 | }); 30 | 31 | process.exit(0); // Exit the process successfully 32 | } catch (error) { 33 | console.error("Error sending event to agent:", error); 34 | process.exit(1); // Exit the process with an error code 35 | } 36 | } 37 | 38 | eventAgent({ 39 | agentId: "agent-id", 40 | runId: "run-id", 41 | }); 42 | -------------------------------------------------------------------------------- /agent-chat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agent_chat", 3 | "version": "0.0.1", 4 | "description": "Restack agent chat example", 5 | "scripts": { 6 | "dev": "open-cli http://localhost:5233 && tsx watch --include src src/services.ts", 7 | "build": "tsc --build", 8 | "start": "node dist/services.js", 9 | "clean": "rm -rf node_modules", 10 | "schedule-agent": "tsx scheduleAgent.ts", 11 | "event-agent": "tsx eventAgent.ts" 12 | }, 13 | "dependencies": { 14 | "@restackio/ai": "^0.0.124", 15 | "@temporalio/workflow": "1.11.8", 16 | "dotenv": "^16.4.7", 17 | "openai": "^4.80.1" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "20.16.9", 21 | "dotenv-cli": "^7.4.2", 22 | "open-cli": "^8.0.0", 23 | "prettier": "3.3.3", 24 | "tsx": "4.19.2", 25 | "typescript": "^5.7.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /agent-chat/scheduleAgent.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | 3 | export type InputSchedule = { 4 | name: string; 5 | }; 6 | 7 | async function scheduleAgent(input: InputSchedule) { 8 | try { 9 | const agentId = `${Date.now()}-AgentChat`; 10 | const runId = await client.scheduleAgent({ 11 | agentName: "agentChat", 12 | agentId, 13 | input, 14 | }); 15 | 16 | const result = await client.getAgentResult({ agentId, runId }); 17 | 18 | console.log("Agent result:", result); 19 | 20 | process.exit(0); // Exit the process successfully 21 | } catch (error) { 22 | console.error("Error scheduling agent:", error); 23 | process.exit(1); // Exit the process with an error code 24 | } 25 | } 26 | 27 | scheduleAgent({ 28 | name: "test", 29 | }); 30 | -------------------------------------------------------------------------------- /agent-chat/src/agents/agent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineEvent, 3 | onEvent, 4 | condition, 5 | log, 6 | step, 7 | } from "@restackio/ai/agent"; 8 | import * as functions from "../functions"; 9 | 10 | export type EndEvent = { 11 | end: boolean; 12 | }; 13 | 14 | export const messagesEvent = defineEvent("messages"); 15 | export const endEvent = defineEvent("end"); 16 | 17 | type AgentChatOutput = { 18 | messages: functions.Message[]; 19 | }; 20 | 21 | export async function agentChat(): Promise { 22 | let endReceived = false; 23 | let messages: functions.Message[] = []; 24 | 25 | onEvent(messagesEvent, async ({ messages }: { messages: functions.Message[] }) => { 26 | const result = await step({}).llmChat({ 27 | messages, 28 | }); 29 | messages.push(result); 30 | return messages; 31 | }); 32 | 33 | onEvent(endEvent, async () => { 34 | endReceived = true; 35 | }); 36 | 37 | // We use the `condition` function to wait for the event goodbyeReceived to return `True`. 38 | await condition(() => endReceived); 39 | 40 | log.info("end condition met"); 41 | return { messages }; 42 | } 43 | -------------------------------------------------------------------------------- /agent-chat/src/agents/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./agent"; 2 | -------------------------------------------------------------------------------- /agent-chat/src/client.ts: -------------------------------------------------------------------------------- 1 | import Restack from "@restackio/ai"; 2 | 3 | import "dotenv/config"; 4 | 5 | export const connectionOptions = { 6 | engineId: process.env.RESTACK_ENGINE_ID!, 7 | address: process.env.RESTACK_ENGINE_ADDRESS!, 8 | apiKey: process.env.RESTACK_ENGINE_API_KEY!, 9 | apiAddress: process.env.RESTACK_ENGINE_API_ADDRESS!, 10 | }; 11 | 12 | export const client = new Restack( 13 | process.env.RESTACK_ENGINE_API_KEY ? connectionOptions : undefined 14 | ); 15 | -------------------------------------------------------------------------------- /agent-chat/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./llmChat"; 2 | -------------------------------------------------------------------------------- /agent-chat/src/services.ts: -------------------------------------------------------------------------------- 1 | import { llmChat } from "./functions"; 2 | import { client } from "./client"; 3 | 4 | async function services() { 5 | const agentsPath = require.resolve("./agents"); 6 | try { 7 | await Promise.all([ 8 | client.startService({ 9 | agentsPath: agentsPath, 10 | functions: { llmChat }, 11 | }), 12 | ]); 13 | 14 | console.log("Services running successfully."); 15 | } catch (e) { 16 | console.error("Failed to run services", e); 17 | } 18 | } 19 | 20 | services().catch((err) => { 21 | console.error("Error running services:", err); 22 | }); 23 | -------------------------------------------------------------------------------- /agent-chat/src/utils/client.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from "openai/index"; 2 | import "dotenv/config"; 3 | 4 | let openaiInstance: OpenAI | null = null; 5 | 6 | export const openaiClient = ({ 7 | apiKey = process.env.OPENAI_API_KEY, 8 | }: { 9 | apiKey?: string; 10 | }): OpenAI => { 11 | if (!apiKey) { 12 | throw new Error("API key is required to create OpenAI client."); 13 | } 14 | 15 | if (!openaiInstance) { 16 | openaiInstance = new OpenAI({ 17 | apiKey, 18 | }); 19 | } 20 | return openaiInstance; 21 | }; 22 | -------------------------------------------------------------------------------- /agent-chat/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "Node16", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "outDir": "./dist", 9 | "rootDir": "./src", 10 | "resolveJsonModule": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } -------------------------------------------------------------------------------- /agent-rag/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | 3 | -------------------------------------------------------------------------------- /agent-rag/chat_post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-rag/chat_post.png -------------------------------------------------------------------------------- /agent-rag/chat_put.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-rag/chat_put.png -------------------------------------------------------------------------------- /agent-rag/chat_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-rag/chat_run.png -------------------------------------------------------------------------------- /agent-rag/eventAgent.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | 3 | export type EventInput = { 4 | agentId: string; 5 | runId: string; 6 | }; 7 | 8 | async function eventAgent(input: EventInput) { 9 | try { 10 | await client.sendAgentEvent({ 11 | event: { 12 | name: "message", 13 | input: { content: "Sales on boots?" }, 14 | }, 15 | agent: { 16 | agentId: input.agentId, 17 | runId: input.runId, 18 | }, 19 | }); 20 | 21 | await client.sendAgentEvent({ 22 | event: { 23 | name: "end", 24 | }, 25 | agent: { 26 | agentId: input.agentId, 27 | runId: input.runId, 28 | }, 29 | }); 30 | 31 | process.exit(0); // Exit the process successfully 32 | } catch (error) { 33 | console.error("Error sending event to agent:", error); 34 | process.exit(1); // Exit the process with an error code 35 | } 36 | } 37 | 38 | eventAgent({ 39 | agentId: "agent-id", 40 | runId: "run-id", 41 | }); 42 | -------------------------------------------------------------------------------- /agent-rag/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agent-rag", 3 | "version": "0.0.1", 4 | "description": "Restack Agent with RAG example", 5 | "scripts": { 6 | "dev": "open-cli http://localhost:5233 && tsx watch --include src src/services.ts", 7 | "build": "tsc --build", 8 | "clean": "rm -rf node_modules", 9 | "schedule": "tsx scheduleAgent.ts", 10 | "event": "tsx eventAgent.ts" 11 | }, 12 | "dependencies": { 13 | "@restackio/ai": "^0.0.124", 14 | "@temporalio/workflow": "1.11.8", 15 | "dotenv": "^16.4.7", 16 | "openai": "^4.80.1", 17 | "zod": "^3.24.1" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "20.16.9", 21 | "dotenv-cli": "^7.4.2", 22 | "open-cli": "^8.0.0", 23 | "prettier": "3.3.3", 24 | "tsx": "4.19.2", 25 | "typescript": "^5.7.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /agent-rag/scheduleAgent.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | import { agentChatTool } from "./src/agents/agent"; 3 | export type InputSchedule = { 4 | name: string; 5 | }; 6 | 7 | async function scheduleAgent(input: InputSchedule) { 8 | try { 9 | const agentId = `${Date.now()}-${agentChatTool.name}`; 10 | const runId = await client.scheduleAgent({ 11 | agentName: agentChatTool.name, 12 | agentId, 13 | input, 14 | }); 15 | 16 | const result = await client.getAgentResult({ agentId, runId }); 17 | 18 | console.log("Agent result:", result); 19 | 20 | process.exit(0); // Exit the process successfully 21 | } catch (error) { 22 | console.error("Error scheduling agent:", error); 23 | process.exit(1); // Exit the process with an error code 24 | } 25 | } 26 | 27 | scheduleAgent({ 28 | name: "test", 29 | }); 30 | -------------------------------------------------------------------------------- /agent-rag/src/agents/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./agent"; 2 | -------------------------------------------------------------------------------- /agent-rag/src/client.ts: -------------------------------------------------------------------------------- 1 | import Restack from "@restackio/ai"; 2 | 3 | import "dotenv/config"; 4 | 5 | export const connectionOptions = { 6 | engineId: process.env.RESTACK_ENGINE_ID!, 7 | address: process.env.RESTACK_ENGINE_ADDRESS!, 8 | apiKey: process.env.RESTACK_ENGINE_API_KEY!, 9 | apiAddress: process.env.RESTACK_ENGINE_API_ADDRESS!, 10 | }; 11 | 12 | export const client = new Restack( 13 | process.env.RESTACK_ENGINE_API_KEY ? connectionOptions : undefined 14 | ); 15 | -------------------------------------------------------------------------------- /agent-rag/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./llmChat"; 2 | export * from "./lookupSales"; 3 | -------------------------------------------------------------------------------- /agent-rag/src/services.ts: -------------------------------------------------------------------------------- 1 | import { llmChat, lookupSales } from "./functions"; 2 | import { client } from "./client"; 3 | 4 | async function services() { 5 | const agentsPath = require.resolve("./agents"); 6 | try { 7 | await Promise.all([ 8 | client.startService({ 9 | agentsPath: agentsPath, 10 | functions: { llmChat, lookupSales }, 11 | }), 12 | ]); 13 | 14 | console.log("Services running successfully."); 15 | } catch (e) { 16 | console.error("Failed to run services", e); 17 | } 18 | } 19 | 20 | services().catch((err) => { 21 | console.error("Error running services:", err); 22 | }); 23 | -------------------------------------------------------------------------------- /agent-rag/src/utils/client.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from "openai/index"; 2 | import "dotenv/config"; 3 | 4 | let openaiInstance: OpenAI | null = null; 5 | 6 | export const openaiClient = ({ 7 | apiKey = process.env.OPENAI_API_KEY, 8 | }: { 9 | apiKey?: string; 10 | }): OpenAI => { 11 | if (!apiKey) { 12 | throw new Error("API key is required to create OpenAI client."); 13 | } 14 | 15 | if (!openaiInstance) { 16 | openaiInstance = new OpenAI({ 17 | apiKey, 18 | }); 19 | } 20 | return openaiInstance; 21 | }; 22 | -------------------------------------------------------------------------------- /agent-rag/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "Node16", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "outDir": "./dist", 9 | "rootDir": "./src", 10 | "resolveJsonModule": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } -------------------------------------------------------------------------------- /agent-reactflow/.dockerignore: -------------------------------------------------------------------------------- 1 | # Ignore node_modules 2 | node_modules 3 | 4 | # Ignore build outputs 5 | .next 6 | out 7 | build 8 | dist 9 | 10 | # Ignore local environment files 11 | .env 12 | .env.local 13 | .env.development.local 14 | .env.test.local 15 | .env.production.local 16 | 17 | # Ignore logs 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Ignore Turbo cache 23 | .turbo 24 | 25 | # Ignore Vercel 26 | .vercel 27 | 28 | # Ignore miscellaneous files 29 | .DS_Store 30 | *.pem 31 | 32 | # Ignore other files as per .gitignore 33 | .git 34 | .gitignore 35 | .env 36 | 37 | # Ensure pnpm-lock.yaml is not ignored 38 | !pnpm-lock.yaml -------------------------------------------------------------------------------- /agent-reactflow/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | 6 | # Local env files 7 | .env 8 | .env.local 9 | .env.development.local 10 | .env.test.local 11 | .env.production.local 12 | 13 | # Testing 14 | coverage 15 | 16 | # Turbo 17 | .turbo 18 | 19 | # Vercel 20 | .vercel 21 | 22 | # Build Outputs 23 | .next/ 24 | out/ 25 | build 26 | dist 27 | 28 | 29 | # Debug 30 | npm-debug.log* 31 | yarn-debug.log* 32 | yarn-error.log* 33 | 34 | # Misc 35 | .DS_Store 36 | *.pem 37 | 38 | # Ensure pnpm-lock.yaml is not ignored 39 | !pnpm-lock.yaml 40 | -------------------------------------------------------------------------------- /agent-reactflow/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /agent-reactflow/agent-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/agent-event.png -------------------------------------------------------------------------------- /agent-reactflow/agent-post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/agent-post.png -------------------------------------------------------------------------------- /agent-reactflow/agent-reactflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/agent-reactflow.png -------------------------------------------------------------------------------- /agent-reactflow/agent-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/agent-run.png -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/.env.example: -------------------------------------------------------------------------------- 1 | 2 | # For inference 3 | OPENAI_API_KEY= 4 | 5 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | media 4 | dist 5 | .eslintcache -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { config } from "@agent-reactflow/eslint-config/base"; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/eventAgent.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | 3 | export type EventInput = { 4 | agentId: string; 5 | runId: string; 6 | }; 7 | 8 | async function eventAgent(input: EventInput) { 9 | try { 10 | await client.sendAgentEvent({ 11 | event: { 12 | name: "flowEvent", 13 | input: { name: "idVerification", input: { type: "id", documentNumber: "1234567890" } }, 14 | }, 15 | agent: { 16 | agentId: input.agentId, 17 | runId: input.runId, 18 | }, 19 | }); 20 | 21 | // await client.sendAgentEvent({ 22 | // event: { 23 | // name: "end", 24 | // }, 25 | // agent: { 26 | // agentId: input.agentId, 27 | // runId: input.runId, 28 | // }, 29 | // }); 30 | 31 | process.exit(0); // Exit the process successfully 32 | } catch (error) { 33 | console.error("Error sending event to agent:", error); 34 | process.exit(1); // Exit the process with an error code 35 | } 36 | } 37 | 38 | eventAgent({"agentId":"1743008631706-agentFlow","runId":"0195d369-0b9d-7ded-ab82-20e275e295da"}); 39 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@agent-reactflow/backend", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "tsx src/services.ts", 8 | "start.watch": "nodemon src/services.ts", 9 | "dev": "open-cli http://localhost:5233 && tsx watch --include src src/services.ts", 10 | "lint": "eslint src --fix --max-warnings 0 --cache", 11 | "build": "tsc --build", 12 | "clean": "rm -rf node_modules", 13 | "workflow": "tsx ./scheduleWorkflow.ts", 14 | "event": "tsx ./eventAgent.ts" 15 | }, 16 | "dependencies": { 17 | "@restackio/ai": "^0.0.124", 18 | "@temporalio/workflow": "1.11.8", 19 | "dotenv": "^16.4.5", 20 | "node-fetch": "^3.3.2", 21 | "openai": "^4.80.1", 22 | "reactflow": "^11.11.4", 23 | "typescript": "^5.8.2", 24 | "ws": "^8.18.1", 25 | "zod": "^3.24.2" 26 | }, 27 | "devDependencies": { 28 | "@agent-reactflow/eslint-config": "workspace:*", 29 | "@agent-reactflow/typescript-config": "workspace:*", 30 | "@types/node": "20.16.9", 31 | "@types/ws": "^8.18.0", 32 | "dotenv-cli": "^7.4.2", 33 | "open-cli": "^8.0.0", 34 | "prettier": "3.3.3", 35 | "tsx": "4.19.2" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/apps/backend/readme.md -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/scheduleAgent.ts: -------------------------------------------------------------------------------- 1 | import { client } from "./src/client"; 2 | 3 | export type InputSchedule = { 4 | name: string; 5 | }; 6 | 7 | async function scheduleAgent(input: InputSchedule) { 8 | try { 9 | const agentId = `${Date.now()}-agentFlow`; 10 | const runId = await client.scheduleAgent({ 11 | agentName: "agentFlow", 12 | agentId, 13 | input, 14 | }); 15 | 16 | const result = await client.getAgentResult({ agentId, runId }); 17 | 18 | console.log("Agent result:", result); 19 | 20 | process.exit(0); // Exit the process successfully 21 | } catch (error) { 22 | console.error("Error scheduling agent:", error); 23 | process.exit(1); // Exit the process with an error code 24 | } 25 | } 26 | 27 | scheduleAgent({ 28 | name: "test", 29 | }); 30 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/agents/chat.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineEvent, 3 | onEvent, 4 | condition, 5 | log, 6 | step, 7 | } from "@restackio/ai/agent"; 8 | import * as functions from "../functions"; 9 | 10 | const messagesEvent = defineEvent("messages"); 11 | const endEvent = defineEvent("end"); 12 | 13 | type AgentChatOutput = { 14 | messages: functions.Message[]; 15 | }; 16 | 17 | export async function agentChat(): Promise { 18 | let endReceived = false; 19 | const messages: functions.Message[] = []; 20 | 21 | onEvent(messagesEvent, async ({ messages, tools, stream = true }: { messages: functions.Message[], tools: any, stream?: boolean }) => { 22 | const result = await step({}).llmChat({ 23 | messages, 24 | tools, 25 | stream 26 | }); 27 | messages.push(result); 28 | return messages; 29 | }); 30 | 31 | onEvent(endEvent, async () => { 32 | endReceived = true; 33 | }); 34 | 35 | // We use the `condition` function to wait for the event goodbyeReceived to return `True`. 36 | await condition(() => endReceived); 37 | 38 | log.info("end condition met"); 39 | return { messages }; 40 | } 41 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/agents/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./flow"; 2 | export * from "./chat"; -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/client.ts: -------------------------------------------------------------------------------- 1 | import Restack from "@restackio/ai"; 2 | 3 | import "dotenv/config"; 4 | 5 | export const apiAddress = process.env.RESTACK_ENGINE_API_ADDRESS! 6 | 7 | export const connectionOptions = { 8 | engineId: process.env.RESTACK_ENGINE_ID!, 9 | address: process.env.RESTACK_ENGINE_ADDRESS!, 10 | apiKey: process.env.RESTACK_ENGINE_API_KEY!, 11 | apiAddress, 12 | }; 13 | 14 | export const client = new Restack( 15 | process.env.RESTACK_ENGINE_API_KEY ? connectionOptions : undefined 16 | ); 17 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/functions/humanVerification.ts: -------------------------------------------------------------------------------- 1 | import { FunctionFailure, log } from "@restackio/ai/function"; 2 | 3 | 4 | export type HumanVerificationInput = { 5 | context: string; 6 | }; 7 | 8 | export type HumanVerificationOutput = { 9 | status: "approved" | "declined"; 10 | }; 11 | 12 | export const humanVerification = async ({ 13 | context, 14 | }: HumanVerificationInput): Promise => { 15 | try { 16 | log.info("humanVerification input:", {input: {context}}); 17 | 18 | // Simulate status response 19 | const statuses: HumanVerificationOutput['status'][] = ['approved', 'declined']; 20 | const randomStatusIndex = Math.floor(Math.random() * statuses.length); 21 | const status = statuses[randomStatusIndex]; 22 | 23 | const output: HumanVerificationOutput = { 24 | status, 25 | }; 26 | 27 | log.info(`humanVerification output: ${output}`); 28 | return output; 29 | } catch (error) { 30 | throw FunctionFailure.nonRetryable(`Error humanVerification chat: ${error}`); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./llmResponse"; 2 | export * from "./idVerification"; 3 | export * from "./dslInterpreter"; 4 | export * from "./humanVerification"; 5 | export * from "./mockFlow"; 6 | export * from "./sendAgentEvent"; 7 | export * from "./llmChat"; -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/functions/sendAgentEvent.ts: -------------------------------------------------------------------------------- 1 | import { FunctionFailure } from "@restackio/ai/function"; 2 | import { client } from "../client" 3 | 4 | import "dotenv/config"; 5 | 6 | export const sendAgentEvent = async ({ 7 | eventName, 8 | eventInput, 9 | agentId, 10 | runId, 11 | }: { 12 | eventName: string; 13 | eventInput: any; 14 | agentId: string; 15 | runId: string; 16 | }) => { 17 | 18 | try { 19 | const sentEvent = await client.sendAgentEvent({ 20 | event: { 21 | name: eventName, 22 | input: eventInput, 23 | }, 24 | agent: { 25 | agentId: agentId, 26 | runId: runId, 27 | } 28 | }) 29 | 30 | return sentEvent; 31 | 32 | } catch (error) { 33 | throw FunctionFailure.nonRetryable(`Error sending agent event: ${error}`); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/services.ts: -------------------------------------------------------------------------------- 1 | import { llmResponse, idVerification, humanVerification, dslInterpreter, mockFlow, sendAgentEvent, llmChat } from "./functions"; 2 | import { client } from "./client"; 3 | 4 | async function services() { 5 | const agentsPath = require.resolve("./agents"); 6 | const workflowsPath = require.resolve("./workflows"); 7 | try { 8 | await Promise.all([ 9 | client.startService({ 10 | agentsPath: agentsPath, 11 | functions: { dslInterpreter, mockFlow, sendAgentEvent, llmChat }, 12 | }), 13 | client.startService({ 14 | workflowsPath: workflowsPath, 15 | functions: { llmResponse, idVerification, humanVerification }, 16 | taskQueue: "workflow" 17 | }), 18 | ]); 19 | 20 | console.log("Services running successfully."); 21 | } catch (e) { 22 | console.error("Failed to run services", e); 23 | } 24 | } 25 | 26 | services().catch((err) => { 27 | console.error("Error running services:", err); 28 | }); 29 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/utils/client.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from "openai/index"; 2 | import "dotenv/config"; 3 | 4 | let openaiInstance: OpenAI | null = null; 5 | 6 | export const openaiClient = ({ 7 | apiKey = process.env.OPENAI_API_KEY, 8 | }: { 9 | apiKey?: string; 10 | }): OpenAI => { 11 | if (!apiKey) { 12 | throw new Error("API key is required to create OpenAI client."); 13 | } 14 | 15 | if (!openaiInstance) { 16 | openaiInstance = new OpenAI({ 17 | apiKey, 18 | }); 19 | } 20 | return openaiInstance; 21 | }; 22 | -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/workflows/endFlow.ts: -------------------------------------------------------------------------------- 1 | import {step, workflowInfo } from "@restackio/ai/workflow"; 2 | import * as functions from "../functions"; 3 | 4 | 5 | export type EndFlowInput = { 6 | eventData: { 7 | response: "success" | "failure"; 8 | } 9 | }; 10 | 11 | export type EndFlowOutput = { 12 | response: "success" | "failure"; 13 | rawResponse: any; 14 | }; 15 | 16 | export async function endFlow(input: EndFlowInput): Promise { 17 | 18 | 19 | const agentId = workflowInfo().parent?.workflowId; 20 | const runId = workflowInfo().parent?.runId; 21 | 22 | if (!agentId || !runId) { 23 | throw new Error("Workflow ID or run ID is not available"); 24 | } 25 | 26 | await step({}).sendAgentEvent({ 27 | eventName: 'end', 28 | eventInput: {}, 29 | agentId, 30 | runId, 31 | }); 32 | 33 | if (input.eventData.response === "success") { 34 | return { 35 | response: "success", 36 | rawResponse: {}, 37 | }; 38 | } else { 39 | return { 40 | response: "failure", 41 | rawResponse: {}, 42 | }; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/workflows/idVerification.ts: -------------------------------------------------------------------------------- 1 | import {step } from "@restackio/ai/workflow"; 2 | import * as functions from "../functions"; 3 | 4 | export type DocCaptureWorkflowInput = { 5 | eventData: { 6 | type: "id" | "passport" | "driverLicense"; 7 | documentNumber: string; 8 | }, 9 | flow: { 10 | prompt: string; 11 | outputConditions: string[]; 12 | } 13 | }; 14 | 15 | export type IdVerificationWorkflowOutput = { 16 | response: string[]; 17 | rawResponse: any; 18 | } 19 | 20 | export async function idVerification(input: DocCaptureWorkflowInput): Promise { 21 | 22 | const verificationResult = await step({taskQueue: "workflow",}).idVerification({ 23 | type: input.eventData.type, 24 | documentNumber: input.eventData.documentNumber, 25 | }); 26 | 27 | const llmResponse = await step({taskQueue: "workflow",}).llmResponse({ 28 | messages: [ 29 | { 30 | role: "user", 31 | content: `${input.flow.prompt} : ${JSON.stringify(verificationResult)}`, 32 | }, 33 | ], 34 | workflowName: "idVerification", 35 | outputConditions: input.flow.outputConditions, 36 | }); 37 | 38 | return { 39 | response: llmResponse, 40 | rawResponse: verificationResult, 41 | } 42 | } -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/workflows/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./idVerification"; 2 | export * from "./manualVerification"; 3 | export * from "./endFlow"; -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/src/workflows/manualVerification.ts: -------------------------------------------------------------------------------- 1 | import {step } from "@restackio/ai/agent"; 2 | import * as functions from "../functions"; 3 | 4 | export type manualVerificationInput = { 5 | eventData: { 6 | context: string; 7 | }, 8 | flow: { 9 | prompt?: string; 10 | outputConditions: string[]; 11 | } 12 | }; 13 | 14 | 15 | export type manualVerificationOutput = { 16 | response: string[]; 17 | rawResponse: any; 18 | } 19 | 20 | export async function manualVerification(input: manualVerificationInput): Promise { 21 | console.log("Manual Verification Workflow Executed"); 22 | 23 | const verificationResult = await step({taskQueue: "workflow"}).humanVerification({ 24 | context: input.eventData.context, 25 | }); 26 | 27 | const llmResponse = await step({taskQueue: "workflow"}).llmResponse({ 28 | messages: [ 29 | { 30 | role: "user", 31 | content: `${input.flow.prompt} : ${JSON.stringify(verificationResult)}`, 32 | }, 33 | ], 34 | workflowName: "manualVerification", 35 | outputConditions: input.flow.outputConditions, 36 | }); 37 | 38 | return { 39 | response: llmResponse, 40 | rawResponse: verificationResult, 41 | }; 42 | 43 | } -------------------------------------------------------------------------------- /agent-reactflow/apps/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "Node16", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "outDir": "./dist", 9 | "rootDir": "./src", 10 | "resolveJsonModule": true 11 | }, 12 | "include": ["src/**/*.ts"], 13 | "exclude": ["node_modules"] 14 | } -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # env files (can opt-in for commiting if needed) 29 | .env* 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/actions/workflow.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | import Restack from "@restackio/ai"; 3 | 4 | const connectionOptions = { 5 | engineId: process.env.RESTACK_ENGINE_ID!, 6 | address: process.env.RESTACK_ENGINE_ADDRESS!, 7 | apiKey: process.env.RESTACK_ENGINE_API_KEY!, 8 | }; 9 | 10 | const client = new Restack( 11 | process.env.RESTACK_ENGINE_API_KEY ? connectionOptions : undefined 12 | ); 13 | 14 | export async function runWorkflow({ 15 | workflowName = "workflowFlow", 16 | input = {}, 17 | }: { 18 | workflowName: string, 19 | input: any, 20 | }) : Promise { 21 | if (!workflowName || !input) { 22 | throw new Error("Workflow name and input are required"); 23 | } 24 | 25 | const workflowId = `${Date.now()}-${workflowName.toString()}`; 26 | 27 | const runId = await client.scheduleWorkflow({ 28 | workflowName, 29 | workflowId, 30 | input, 31 | taskQueue: "workflow", 32 | }); 33 | 34 | return { 35 | workflowId, 36 | runId 37 | } 38 | } 39 | 40 | export async function getWorkflowResult({ 41 | workflowId, 42 | runId 43 | }: { 44 | workflowId: string, 45 | runId: string 46 | }) : Promise { 47 | const result = await client.getWorkflowResult({ 48 | workflowId, 49 | runId 50 | }); 51 | return result 52 | } 53 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/api/chat/route.ts: -------------------------------------------------------------------------------- 1 | import { createOpenAI } from '@ai-sdk/openai'; 2 | import { streamText, tool } from 'ai'; 3 | import { z } from 'zod'; 4 | 5 | export const maxDuration = 30; 6 | 7 | export async function POST(req: Request) { 8 | const { messages, agentId, runId } = await req.json(); 9 | try { 10 | 11 | const restackEngineHostname = process.env.RESTACK_ENGINE_ADDRESS ? `https://${process.env.RESTACK_ENGINE_ADDRESS}` : 'http://localhost:9233'; 12 | 13 | const openaiClient = createOpenAI({ 14 | apiKey: 'next-flow-frontend', 15 | baseURL: `${restackEngineHostname}/stream/agents/agentChat/${agentId}/${runId}`, 16 | }) 17 | 18 | const result = streamText({ 19 | model: openaiClient('gpt-4.1-mini'), 20 | messages, 21 | tools: { 22 | updateFlow: tool({ 23 | description: 'Create or update flow', 24 | parameters: z.object({ 25 | flow: z.any() 26 | }), 27 | execute: async ({ flow }) => { 28 | return { 29 | flow, 30 | }; 31 | }, 32 | }), 33 | }, 34 | toolCallStreaming: true, 35 | }); 36 | 37 | return result.toDataStreamResponse(); 38 | 39 | } catch (error) { 40 | console.error(error); 41 | return new Response("Error", { status: 500 }); 42 | } 43 | } -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/apps/frontend/app/favicon.ico -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/apps/frontend/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/restackio/examples-typescript/0ff6de63a62537d2f6f4a58633a495caa7ad5301/agent-reactflow/apps/frontend/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react" 2 | import type { Metadata } from "next" 3 | import { Inter } from "next/font/google" 4 | import "./globals.css" 5 | import { ThemeProvider } from "../components/theme/theme-provider" 6 | 7 | const inter = Inter({ subsets: ["latin"] }) 8 | 9 | export const metadata: Metadata = { 10 | title: "Agent Builder", 11 | description: "Build and run agents with React Flow and Restack", 12 | } 13 | 14 | export default function RootLayout({ 15 | children, 16 | }: Readonly<{ 17 | children: React.ReactNode 18 | }>) { 19 | return ( 20 | 21 | 22 | 23 | {children} 24 | 25 | 26 | 27 | ) 28 | } 29 | 30 | import './globals.css' -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/app/page.tsx: -------------------------------------------------------------------------------- 1 | import WorkflowBuilder from "../components/agent-builder" 2 | 3 | export default function Home() { 4 | return ( 5 |
6 | 7 |
8 | ) 9 | } 10 | 11 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "../components", 15 | "utils": "../lib/utils", 16 | "ui": "../components/ui", 17 | "lib": "../lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/flow/baseHandle.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react"; 2 | import { Handle, HandleProps } from "@xyflow/react"; 3 | 4 | import { cn } from "../../lib/utils"; 5 | 6 | export type BaseHandleProps = HandleProps; 7 | 8 | export const BaseHandle = forwardRef( 9 | ({ className, children, ...props }, ref) => { 10 | return ( 11 | 21 | {children} 22 | 23 | ); 24 | }, 25 | ) as React.ForwardRefExoticComponent>; 26 | 27 | BaseHandle.displayName = "BaseHandle"; -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/flow/baseNode.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef, HTMLAttributes } from "react"; 2 | 3 | import { cn } from "../../lib/utils"; 4 | 5 | export const BaseNode = forwardRef< 6 | HTMLDivElement, 7 | HTMLAttributes & { selected?: boolean } 8 | >(({ className, selected, ...props }, ref) => ( 9 |
20 | )); 21 | 22 | BaseNode.displayName = "BaseNode"; -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/theme/theme-context.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext, useState, ReactNode } from 'react'; 2 | 3 | interface ThemeContextType { 4 | theme: string; 5 | toggleTheme: () => void; 6 | } 7 | 8 | const ThemeContext = createContext(undefined); 9 | 10 | export const ThemeProvider = ({ children }: { children: ReactNode }) => { 11 | const [theme, setTheme] = useState('light'); 12 | 13 | const toggleTheme = () => { 14 | setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light')); 15 | }; 16 | 17 | return ( 18 | 19 |
{children}
20 |
21 | ); 22 | }; 23 | 24 | export const useTheme = () => { 25 | const context = useContext(ThemeContext); 26 | if (!context) { 27 | throw new Error('useTheme must be used within a ThemeProvider'); 28 | } 29 | return context; 30 | }; -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/theme/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { 5 | ThemeProvider as NextThemesProvider, 6 | type ThemeProviderProps, 7 | } from 'next-themes' 8 | 9 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 10 | return {children} 11 | } 12 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "../../lib/utils" 5 | 6 | const badgeVariants = cva( 7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 13 | secondary: 14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 | destructive: 16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 17 | outline: "text-foreground", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | }, 23 | } 24 | ) 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ) 34 | } 35 | 36 | export { Badge, badgeVariants } 37 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "../../lib/utils" 4 | 5 | const Input = React.forwardRef>( 6 | ({ className, type, ...props }, ref) => { 7 | return ( 8 | 17 | ) 18 | } 19 | ) 20 | Input.displayName = "Input" 21 | 22 | export { Input } 23 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "../../lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 5 | 6 | import { cn } from "../../lib/utils" 7 | 8 | const Separator = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >( 12 | ( 13 | { className, orientation = "horizontal", decorative = true, ...props }, 14 | ref 15 | ) => ( 16 | 27 | ) 28 | ) 29 | Separator.displayName = SeparatorPrimitive.Root.displayName 30 | 31 | export { Separator } 32 | -------------------------------------------------------------------------------- /agent-reactflow/apps/frontend/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "../../lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |