diff --git a/.gitignore b/.gitignore index cdfdca1..7b1aca4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,6 @@ # dependencies /node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions # next.js /.next/ @@ -29,10 +22,6 @@ next-env.d.ts # logs *.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* # caches .cache/ @@ -56,4 +45,4 @@ Thumbs.db # local notes CLAUDE.md -AGENTS.md \ No newline at end of file +AGENTS.md diff --git a/components.json b/components.json index dba50c6..8cbe7f2 100644 --- a/components.json +++ b/components.json @@ -4,7 +4,7 @@ "rsc": true, "tsx": true, "tailwind": { - "config": "tailwind.config.ts", + "config": "tailwind.config.mjs", "css": "src/app/globals.css", "baseColor": "slate", "cssVariables": true, @@ -15,6 +15,6 @@ "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", - "hooks": "@/hooks" + "hooks": "@/app/hooks" } } diff --git a/next.config.ts b/next.config.ts index a0640d3..e9ffa30 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,30 +1,7 @@ import type { NextConfig } from "next"; -// EvoScientist `EvoSci deploy` backend (langgraph dev), default 127.0.0.1:6174. -// Override with LANGGRAPH_API_URL if you used `EvoSci deploy --port `. -const LANGGRAPH_TARGET = - process.env.LANGGRAPH_API_URL || "http://127.0.0.1:6174"; - const nextConfig: NextConfig = { - // Allow loading the dev UI (and its HMR resources) from these LAN hosts, - // e.g. opening http://192.168.0.59:3000 from a phone on the same Wi-Fi. - // Add/replace with your Mac's LAN IP (see `ipconfig getifaddr en0`). - allowedDevOrigins: ["192.168.0.59"], - - // Same-origin reverse proxy to the EvoScientist backend. The browser talks - // only to this Next server; Next (running on the Mac) forwards to the - // backend on 127.0.0.1. This lets a phone reach the backend WITHOUT the - // EvoScientist repo binding to 0.0.0.0, and avoids cross-origin/CORS issues. - // In the UI's config dialog, set Deployment URL to: /lg - // Dev-only: rewrites don't apply to a future static export build. - async rewrites() { - return [ - { - source: "/lg/:path*", - destination: `${LANGGRAPH_TARGET}/:path*`, - }, - ]; - }, + /* config options here */ }; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 2beaefa..4883b87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@langchain/core": "1.1.19", "@langchain/langgraph-sdk": "1.0.3", - "@radix-ui/colors": "^1.0.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-scroll-area": "^1.2.9", @@ -38,8 +37,6 @@ }, "devDependencies": { "@eslint/js": "^9", - "@headlessui/tailwindcss": "^0.2.2", - "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.9", "@types/node": "^20", @@ -555,19 +552,6 @@ "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, - "node_modules/@headlessui/tailwindcss": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", - "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "tailwindcss": "^3.0 || ^4.0" - } - }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -1495,12 +1479,6 @@ "node": ">=12.4.0" } }, - "node_modules/@radix-ui/colors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-1.0.1.tgz", - "integrity": "sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg==", - "license": "MIT" - }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -2222,16 +2200,6 @@ "tslib": "^2.8.0" } }, - "node_modules/@tailwindcss/container-queries": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz", - "integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "tailwindcss": ">=3.2.0" - } - }, "node_modules/@tailwindcss/forms": { "version": "0.5.11", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.11.tgz", diff --git a/package.json b/package.json index eecdfc0..d75b7bf 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "dependencies": { "@langchain/core": "1.1.19", "@langchain/langgraph-sdk": "1.0.3", - "@radix-ui/colors": "^1.0.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-scroll-area": "^1.2.9", @@ -44,8 +43,6 @@ }, "devDependencies": { "@eslint/js": "^9", - "@headlessui/tailwindcss": "^0.2.2", - "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.9", "@types/node": "^20", diff --git a/src/app/components/ConfigDialog.tsx b/src/app/components/ConfigDialog.tsx index 17de2e0..04b85f4 100644 --- a/src/app/components/ConfigDialog.tsx +++ b/src/app/components/ConfigDialog.tsx @@ -12,13 +12,13 @@ import { import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; -import { DEFAULT_ASSISTANT_ID, StandaloneConfig } from "@/lib/config"; +import { DEFAULT_ASSISTANT_ID, DeploymentConfig } from "@/lib/config"; interface ConfigDialogProps { open: boolean; onOpenChange: (open: boolean) => void; - onSave: (config: StandaloneConfig) => void; - initialConfig?: StandaloneConfig; + onSave: (config: DeploymentConfig) => void; + initialConfig?: DeploymentConfig; } export function ConfigDialog({ diff --git a/src/app/hooks/useChat.ts b/src/app/hooks/useChat.ts index 139b78e..f7cd46a 100644 --- a/src/app/hooks/useChat.ts +++ b/src/app/hooks/useChat.ts @@ -2,11 +2,7 @@ import { useCallback } from "react"; import { useStream } from "@langchain/langgraph-sdk/react"; -import { - type Message, - type Assistant, - type Checkpoint, -} from "@langchain/langgraph-sdk"; +import { type Message, type Assistant } from "@langchain/langgraph-sdk"; import { v4 as uuidv4 } from "uuid"; import type { UseStreamThread } from "@langchain/langgraph-sdk/react"; import type { TodoItem } from "@/app/types/types"; @@ -71,34 +67,6 @@ export function useChat({ [stream, activeAssistant?.config, onHistoryRevalidate] ); - const runSingleStep = useCallback( - ( - messages: Message[], - checkpoint?: Checkpoint, - isRerunningSubagent?: boolean, - optimisticMessages?: Message[] - ) => { - if (checkpoint) { - stream.submit(undefined, { - ...(optimisticMessages - ? { optimisticValues: { messages: optimisticMessages } } - : {}), - config: activeAssistant?.config, - checkpoint: checkpoint, - ...(isRerunningSubagent - ? { interruptAfter: ["tools"] } - : { interruptBefore: ["tools"] }), - }); - } else { - stream.submit( - { messages }, - { config: activeAssistant?.config, interruptBefore: ["tools"] } - ); - } - }, - [stream, activeAssistant?.config] - ); - const setFiles = useCallback( async (files: Record) => { if (!threadId) return; @@ -109,29 +77,6 @@ export function useChat({ [client, threadId] ); - const continueStream = useCallback( - (hasTaskToolCall?: boolean) => { - stream.submit(undefined, { - config: { - ...(activeAssistant?.config || {}), - recursion_limit: 100, - }, - ...(hasTaskToolCall - ? { interruptAfter: ["tools"] } - : { interruptBefore: ["tools"] }), - }); - // Update thread list when continuing stream - onHistoryRevalidate?.(); - }, - [stream, activeAssistant?.config, onHistoryRevalidate] - ); - - const markCurrentThreadAsResolved = useCallback(() => { - stream.submit(null, { command: { goto: "__end__", update: null } }); - // Update thread list when marking thread as resolved - onHistoryRevalidate?.(); - }, [stream, onHistoryRevalidate]); - const resumeInterrupt = useCallback( (value: any) => { stream.submit(null, { command: { resume: value } }); @@ -156,12 +101,8 @@ export function useChat({ isLoading: stream.isLoading, isThreadLoading: stream.isThreadLoading, interrupt: stream.interrupt, - getMessagesMetadata: stream.getMessagesMetadata, sendMessage, - runSingleStep, - continueStream, stopStream, - markCurrentThreadAsResolved, resumeInterrupt, }; } diff --git a/src/app/page.tsx b/src/app/page.tsx index e17dbba..792f127 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -3,7 +3,7 @@ import React, { useState, useEffect, useCallback, Suspense } from "react"; import Image from "next/image"; import { useQueryState } from "nuqs"; -import { getConfig, saveConfig, StandaloneConfig } from "@/lib/config"; +import { getConfig, saveConfig, DeploymentConfig } from "@/lib/config"; import { ConfigDialog } from "@/app/components/ConfigDialog"; import { Button } from "@/components/ui/button"; import { Assistant } from "@langchain/langgraph-sdk"; @@ -19,10 +19,10 @@ import { ChatProvider } from "@/providers/ChatProvider"; import { ChatInterface } from "@/app/components/ChatInterface"; interface HomePageInnerProps { - config: StandaloneConfig; + config: DeploymentConfig; configDialogOpen: boolean; setConfigDialogOpen: (open: boolean) => void; - handleSaveConfig: (config: StandaloneConfig) => void; + handleSaveConfig: (config: DeploymentConfig) => void; } function HomePageInner({ @@ -170,7 +170,7 @@ function HomePageInner({
{sidebar && ( <> @@ -214,7 +214,7 @@ function HomePageInner({ } function HomePageContent() { - const [config, setConfig] = useState(null); + const [config, setConfig] = useState(null); const [configDialogOpen, setConfigDialogOpen] = useState(false); const [assistantId, setAssistantId] = useQueryState("assistantId"); @@ -239,7 +239,7 @@ function HomePageContent() { } }, [config, assistantId, setAssistantId]); - const handleSaveConfig = useCallback((newConfig: StandaloneConfig) => { + const handleSaveConfig = useCallback((newConfig: DeploymentConfig) => { saveConfig(newConfig); setConfig(newConfig); }, []); @@ -257,7 +257,7 @@ function HomePageContent() { />
-

Welcome to Standalone Chat

+

Welcome to EvoScientist

Configure your deployment to get started

diff --git a/src/app/utils/utils.ts b/src/app/utils/utils.ts index 545cde5..aa88baf 100644 --- a/src/app/utils/utils.ts +++ b/src/app/utils/utils.ts @@ -1,10 +1,4 @@ import { Message } from "@langchain/langgraph-sdk"; -import { type ClassValue, clsx } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} export function extractStringFromMessageContent(message: Message): string { return typeof message.content === "string" @@ -60,98 +54,3 @@ export function extractSubAgentContent(data: unknown): string { // Fallback for any other type return JSON.stringify(data, null, 2); } - -export function isPreparingToCallTaskTool(messages: Message[]): boolean { - const lastMessage = messages[messages.length - 1]; - return ( - (lastMessage.type === "ai" && - lastMessage.tool_calls?.some( - (call: { name?: string }) => call.name === "task" - )) || - false - ); -} - -export function formatMessageForLLM(message: Message): string { - let role: string; - if (message.type === "human") { - role = "Human"; - } else if (message.type === "ai") { - role = "Assistant"; - } else if (message.type === "tool") { - role = `Tool Result`; - } else { - role = message.type || "Unknown"; - } - - const timestamp = message.id ? ` (${message.id.slice(0, 8)})` : ""; - - let contentText = ""; - - // Extract content text - if (typeof message.content === "string") { - contentText = message.content; - } else if (Array.isArray(message.content)) { - const textParts: string[] = []; - - message.content.forEach((part: any) => { - if (typeof part === "string") { - textParts.push(part); - } else if (part && typeof part === "object" && part.type === "text") { - textParts.push(part.text || ""); - } - // Ignore other types like tool_use in content - we handle tool calls separately - }); - - contentText = textParts.join("\n\n").trim(); - } - - // For tool messages, include additional tool metadata - if (message.type === "tool") { - const toolName = (message as any).name || "unknown_tool"; - const toolCallId = (message as any).tool_call_id || ""; - role = `Tool Result [${toolName}]`; - if (toolCallId) { - role += ` (call_id: ${toolCallId.slice(0, 8)})`; - } - } - - // Handle tool calls from .tool_calls property (for AI messages) - const toolCallsText: string[] = []; - if ( - message.type === "ai" && - message.tool_calls && - Array.isArray(message.tool_calls) && - message.tool_calls.length > 0 - ) { - message.tool_calls.forEach((call: any) => { - const toolName = call.name || "unknown_tool"; - const toolArgs = call.args ? JSON.stringify(call.args, null, 2) : "{}"; - toolCallsText.push(`[Tool Call: ${toolName}]\nArguments: ${toolArgs}`); - }); - } - - // Combine content and tool calls - const parts: string[] = []; - if (contentText) { - parts.push(contentText); - } - if (toolCallsText.length > 0) { - parts.push(...toolCallsText); - } - - if (parts.length === 0) { - return `${role}${timestamp}: [Empty message]`; - } - - if (parts.length === 1) { - return `${role}${timestamp}: ${parts[0]}`; - } - - return `${role}${timestamp}:\n${parts.join("\n\n")}`; -} - -export function formatConversationForLLM(messages: Message[]): string { - const formattedMessages = messages.map(formatMessageForLLM); - return formattedMessages.join("\n\n---\n\n"); -} diff --git a/src/lib/config.ts b/src/lib/config.ts index a5e4855..ea859af 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,4 +1,4 @@ -export interface StandaloneConfig { +export interface DeploymentConfig { deploymentUrl: string; assistantId: string; langsmithApiKey?: string; @@ -11,14 +11,14 @@ export const DEFAULT_ASSISTANT_ID = "EvoScientist"; const CONFIG_KEY = "evoscientist-config"; -export function getConfig(): StandaloneConfig | null { +export function getConfig(): DeploymentConfig | null { if (typeof window === "undefined") return null; const stored = localStorage.getItem(CONFIG_KEY); if (!stored) return null; try { - const parsed = JSON.parse(stored) as StandaloneConfig; + const parsed = JSON.parse(stored) as DeploymentConfig; // Always pin the assistant to the EvoScientist main agent. return { ...parsed, assistantId: DEFAULT_ASSISTANT_ID }; } catch { @@ -26,7 +26,7 @@ export function getConfig(): StandaloneConfig | null { } } -export function saveConfig(config: StandaloneConfig): void { +export function saveConfig(config: DeploymentConfig): void { if (typeof window === "undefined") return; localStorage.setItem(CONFIG_KEY, JSON.stringify(config)); } diff --git a/tailwind.config.mjs b/tailwind.config.mjs index 3d82552..5057fb9 100644 --- a/tailwind.config.mjs +++ b/tailwind.config.mjs @@ -1,10 +1,7 @@ -import { blackA, green, mauve, slate, violet } from "@radix-ui/colors"; import plugin from "tailwindcss/plugin"; -import containerQueries from "@tailwindcss/container-queries"; import typography from "@tailwindcss/typography"; import forms from "@tailwindcss/forms"; import tailwindcssAnimate from "tailwindcss-animate"; -import headlessui from "@headlessui/tailwindcss"; /** @type {import('tailwindcss').Config} */ export default { @@ -366,11 +363,9 @@ export default { }, }, plugins: [ - containerQueries, typography, forms, tailwindcssAnimate, - headlessui, plugin(({ addUtilities, addBase }) => { addBase({ input: {