├── frontend ├── launch_server.sh ├── src │ ├── app │ │ ├── favicon.ico │ │ ├── globals.css │ │ └── layout.tsx │ ├── components │ │ ├── PromptBarButton.tsx │ │ ├── ResearchProgressFooter.module.css │ │ ├── ResearchProgressItem.module.css │ │ ├── PromptBarButton.module.css │ │ ├── ResearchTypeSelector.module.css │ │ ├── PromptBar.module.css │ │ ├── ResearchProgressList.module.css │ │ ├── ResearchProgressItem.tsx │ │ ├── ReportViewer.tsx │ │ ├── ResearchStrategyEditor.module.css │ │ ├── PromptBar.tsx │ │ ├── ResearchTypeSelector.tsx │ │ ├── ResearchProgressFooter.tsx │ │ ├── ResearchProgressList.tsx │ │ ├── ResearchStrategyEditor.tsx │ │ ├── ResearchProgressHeader.tsx │ │ ├── ResearchProgressHeader.module.css │ │ └── ReportViewer.module.css │ ├── config │ │ └── index.ts │ └── types │ │ └── ApplicationState.ts ├── postcss.config.mjs ├── public │ ├── vercel.svg │ ├── window.svg │ ├── file.svg │ ├── globe.svg │ └── next.svg ├── eslint.config.mjs ├── env.example ├── tsconfig.json ├── .gitignore ├── package.json ├── next.config.ts ├── DISCLAIMER.txt ├── CONTRIBUTING.md └── README.md ├── backend ├── requirements.txt ├── frame │ ├── prompts │ │ ├── udr_minimal │ │ │ ├── 2.auto.txt │ │ │ ├── 1.code_skill.py │ │ │ ├── 0.code_skill.py │ │ │ └── 3.auto.txt │ │ └── udr_minimal_generating │ │ │ ├── 1.auto.txt │ │ │ ├── 0.code_skill.py │ │ │ └── 2.routine_generating.txt │ ├── __init__.py │ ├── tidings.py │ ├── trace.py │ ├── errands │ │ ├── message_generating_routine_call.txt │ │ ├── message_code_call.txt │ │ ├── message_routine_call.txt │ │ ├── message_code_variables.txt │ │ ├── message_routine_variables.txt │ │ ├── message_data_processing.txt │ │ ├── message_code_skill_processing.txt │ │ ├── message_code_processing.txt │ │ ├── message_routine_processing.txt │ │ ├── message_type.txt │ │ └── message_generating_routine_processing.txt │ ├── routines.py │ ├── errands4.py │ └── clients.py ├── .gitignore ├── env.example ├── launch_server.sh ├── sessions.py ├── CHANGELOG.md ├── insert_license.py ├── DISCLAIMER.txt ├── CONTRIBUTING.md ├── items.py ├── scan_research_dry.py └── setup.py ├── LICENSE.txt └── README.md /frontend/launch_server.sh: -------------------------------------------------------------------------------- 1 | npm run dev > npm_run_dev.txt 2>&1 & disown $! -------------------------------------------------------------------------------- /frontend/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVlabs/UniversalDeepResearch/HEAD/frontend/src/app/favicon.ico -------------------------------------------------------------------------------- /frontend/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /frontend/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | python-dotenv 4 | attr 5 | datasets 6 | docstring_parser 7 | evaluate 8 | openai==1.65.1 9 | transformers 10 | tavily-python -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal/2.auto.txt: -------------------------------------------------------------------------------- 1 | The following is the prompt data to be used in later procedures. 2 | 3 | PROMPT: 4 | Produce a comprehensive report on the major Christian events that took place this year between the 20th and 22nd of April 2025. -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal_generating/1.auto.txt: -------------------------------------------------------------------------------- 1 | The following is the prompt data to be used in later procedures. 2 | 3 | PROMPT: 4 | Produce a comprehensive report on the major Christian events that took place this year between the 20th and 22nd of April 2025. -------------------------------------------------------------------------------- /frontend/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /frontend/env.example: -------------------------------------------------------------------------------- 1 | # Backend API Configuration 2 | # The base URL of your backend server (without protocol) 3 | NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost 4 | # The port your backend server is running on 5 | NEXT_PUBLIC_BACKEND_PORT=8000 6 | # API version to use (v1 or v2) 7 | NEXT_PUBLIC_API_VERSION=v2 8 | 9 | # Runtime Configuration 10 | # Enable dry run mode (true/false) 11 | NEXT_PUBLIC_DRY_RUN=false 12 | # Enable V2 API (true/false) 13 | NEXT_PUBLIC_ENABLE_V2_API=true 14 | 15 | # Frontend Configuration 16 | # The port for the frontend development server 17 | NEXT_PUBLIC_FRONTEND_PORT=3000 18 | # The host for the frontend development server 19 | NEXT_PUBLIC_FRONTEND_HOST=localhost -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | SPDX-License-Identifier: Apache-2.0 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | # Python 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.so 6 | .Python 7 | build/ 8 | develop-eggs/ 9 | dist/ 10 | downloads/ 11 | eggs/ 12 | .eggs/ 13 | lib/ 14 | lib64/ 15 | parts/ 16 | sdist/ 17 | var/ 18 | wheels/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | 23 | # Virtual Environment 24 | venv/ 25 | ENV/ 26 | env/ 27 | .venv/ 28 | 29 | # IDE 30 | .idea/ 31 | .vscode/ 32 | *.swp 33 | *.swo 34 | 35 | # Environment variables 36 | .env 37 | .env.local 38 | 39 | # Logs 40 | *.log 41 | 42 | # OS 43 | .DS_Store 44 | Thumbs.db 45 | 46 | # user-added 47 | instances/ 48 | tavily_api.txt 49 | nvdev_api.txt 50 | mock_instances/ 51 | logs/ 52 | uvicorn_main.txt 53 | 54 | .DS_Store 55 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /backend/frame/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | -------------------------------------------------------------------------------- /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.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # development logs 34 | npm_run_dev.txt 35 | uvicorn_main.txt 36 | 37 | # env files (can opt-in for committing if needed) 38 | .env* 39 | 40 | # vercel 41 | .vercel 42 | 43 | # typescript 44 | *.tsbuildinfo 45 | next-env.d.ts 46 | 47 | 48 | **/.DS_Store -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@heroicons/react": "^2.2.0", 13 | "next": "15.4.0", 14 | "react": "^19.0.0", 15 | "react-dom": "^19.0.0", 16 | "react-icons": "^5.1.0", 17 | "react-markdown": "^10.1.0", 18 | "remark-gfm": "^4.0.1", 19 | "uuid": "^11.1.0" 20 | }, 21 | "devDependencies": { 22 | "@eslint/eslintrc": "^3", 23 | "@tailwindcss/postcss": "^4", 24 | "@types/node": "^20", 25 | "@types/react": "^19", 26 | "@types/react-dom": "^19", 27 | "eslint": "^9", 28 | "eslint-config-next": "15.3.0", 29 | "tailwindcss": "^4", 30 | "typescript": "^5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /frontend/next.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import type { NextConfig } from "next"; 18 | 19 | const nextConfig: NextConfig = { 20 | /* config options here */ 21 | }; 22 | 23 | export default nextConfig; 24 | -------------------------------------------------------------------------------- /frontend/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/env.example: -------------------------------------------------------------------------------- 1 | # Universal Deep Research Backend (UDR-B) - Environment Configuration 2 | # Copy this file to .env and customize the values for your deployment 3 | 4 | # Server Configuration 5 | HOST=0.0.0.0 6 | PORT=8000 7 | LOG_LEVEL=info 8 | 9 | # CORS Configuration 10 | FRONTEND_URL=http://localhost:3000 11 | ALLOW_CREDENTIALS=true 12 | 13 | # Model Configuration 14 | DEFAULT_MODEL=llama-3.1-nemotron-253b 15 | LLM_BASE_URL=https://integrate.api.nvidia.com/v1 16 | LLM_API_KEY_FILE=nvdev_api.txt 17 | LLM_TEMPERATURE=0.2 18 | LLM_TOP_P=0.7 19 | LLM_MAX_TOKENS=2048 20 | 21 | # Search Configuration 22 | TAVILY_API_KEY_FILE=tavily_api.txt 23 | MAX_SEARCH_RESULTS=10 24 | 25 | # Research Configuration 26 | MAX_TOPICS=1 27 | MAX_SEARCH_PHRASES=1 28 | MOCK_DIRECTORY=mock_instances/stocks_24th_3_sections 29 | RANDOM_SEED=42 30 | 31 | # Logging Configuration 32 | LOG_DIR=logs 33 | TRACE_ENABLED=true 34 | COPY_INTO_STDOUT=false 35 | 36 | # FrameV4 Configuration 37 | LONG_CONTEXT_CUTOFF=8192 38 | FORCE_LONG_CONTEXT=false 39 | MAX_ITERATIONS=1024 40 | INTERACTION_LEVEL=none 41 | 42 | # Model-specific overrides (optional) 43 | # LLAMA_3_1_8B_BASE_URL=https://integrate.api.nvidia.com/v1 44 | # LLAMA_3_1_8B_MODEL=nvdev/meta/llama-3.1-8b-instruct 45 | # LLAMA_3_1_8B_TEMPERATURE=0.2 46 | # LLAMA_3_1_8B_TOP_P=0.7 47 | # LLAMA_3_1_8B_MAX_TOKENS=2048 -------------------------------------------------------------------------------- /frontend/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/globals.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | @import "tailwindcss"; 18 | 19 | :root { 20 | --background: #ffffff; 21 | --foreground: #171717; 22 | } 23 | 24 | @theme inline { 25 | --color-background: var(--background); 26 | --color-foreground: var(--foreground); 27 | --font-sans: var(--font-geist-sans); 28 | --font-mono: var(--font-geist-mono); 29 | } 30 | 31 | @media (prefers-color-scheme: dark) { 32 | :root { 33 | --background: #0a0a0a; 34 | --foreground: #ededed; 35 | } 36 | } 37 | 38 | body { 39 | background: var(--background); 40 | color: var(--foreground); 41 | font-family: Arial, Helvetica, sans-serif; 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/components/PromptBarButton.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 'use client'; 18 | 19 | import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; 20 | import styles from './PromptBarButton.module.css'; 21 | 22 | interface PromptBarButtonProps { 23 | onClick: () => void; 24 | disabled?: boolean; 25 | } 26 | 27 | export default function PromptBarButton({ onClick, disabled = false }: PromptBarButtonProps) { 28 | return ( 29 | 37 | ); 38 | } -------------------------------------------------------------------------------- /backend/launch_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Universal Deep Research Backend (UDR-B) - Server Launch Script 4 | # This script launches the FastAPI server with proper configuration 5 | 6 | # Load environment variables if .env file exists 7 | if [ -f ".env" ]; then 8 | echo "Loading environment variables from .env file..." 9 | export $(cat .env | grep -v '^#' | xargs) 10 | fi 11 | 12 | # Set default values if not provided 13 | HOST=${HOST:-0.0.0.0} 14 | PORT=${PORT:-8000} 15 | LOG_LEVEL=${LOG_LEVEL:-info} 16 | 17 | echo "Starting Universal Deep Research Backend (UDR-B)..." 18 | echo "Host: $HOST" 19 | echo "Port: $PORT" 20 | echo "Log Level: $LOG_LEVEL" 21 | 22 | # Launch the server 23 | uvicorn main:app \ 24 | --reload \ 25 | --env-file .env \ 26 | --access-log \ 27 | --log-level=$LOG_LEVEL \ 28 | --host $HOST \ 29 | --port $PORT \ 30 | > uvicorn_main.txt 2>&1 & 31 | 32 | # Wait a moment for the process to start 33 | sleep 2 34 | 35 | # Find the uvicorn process ID using ps and grep 36 | PID=$(ps aux | grep "uvicorn main:app" | grep -v grep | awk '{print $2}' | head -1) 37 | 38 | if [ -n "$PID" ]; then 39 | echo "Server started with PID: $PID" 40 | echo "To stop the server, run: kill $PID" 41 | else 42 | echo "Warning: Could not find uvicorn process ID" 43 | fi 44 | 45 | # Disown the process so it continues running after the script exits 46 | disown $! 47 | 48 | echo "Server started in background. Check uvicorn_main.txt for logs." 49 | echo "API available at: http://$HOST:$PORT" -------------------------------------------------------------------------------- /backend/sessions.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | """ 16 | Session management utilities for the Universal Deep Research Backend (UDR-B). 17 | 18 | This module provides functions for generating unique session identifiers 19 | that combine timestamps with random components for tracking research sessions. 20 | """ 21 | 22 | import uuid 23 | from datetime import datetime 24 | 25 | 26 | def generate_session_key() -> str: 27 | """ 28 | Generates a unique session key combining timestamp and random components. 29 | Format: {timestamp}-{random_uuid} 30 | Example: "20240315T123456Z-a1b2c3d4" 31 | 32 | Returns: 33 | str: A unique session identifier 34 | """ 35 | timestamp = datetime.now().strftime("%Y%m%dT%H%M%SZ") 36 | random_component = str(uuid.uuid4())[:8] # First 8 chars of UUID 37 | return f"{timestamp}-{random_component}" 38 | -------------------------------------------------------------------------------- /frontend/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import type { Metadata } from "next"; 18 | import { Geist, Geist_Mono } from "next/font/google"; 19 | import "./globals.css"; 20 | 21 | const geistSans = Geist({ 22 | variable: "--font-geist-sans", 23 | subsets: ["latin"], 24 | }); 25 | 26 | const geistMono = Geist_Mono({ 27 | variable: "--font-geist-mono", 28 | subsets: ["latin"], 29 | }); 30 | 31 | export const metadata: Metadata = { 32 | title: "Deep Research", 33 | description: "Frame-powered Universal Deep Research demo", 34 | }; 35 | 36 | export default function RootLayout({ 37 | children, 38 | }: Readonly<{ 39 | children: React.ReactNode; 40 | }>) { 41 | return ( 42 | 43 | 46 | {children} 47 | 48 | 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal/1.code_skill.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | def perform_search(search_phrase: str): 16 | """ 17 | Performs a search using the Tavily API and returns a list of search result objects. 18 | 19 | Args: 20 | search_phrase (str): The phrase to search for using the Tavily API. 21 | 22 | Returns: 23 | List[Dict[str, Any]]: A list of search result dictionaries obtained from the Tavily API. Each dictionary has 'content' field with text retrieved from the result, and a 'url' field that keeps the url of the search result. 24 | 25 | Raises: 26 | TavilyClientError: If there is an issue with the Tavily API client or the search request. 27 | KeyError: If the expected 'results' key is missing in the search response. 28 | 29 | """ 30 | from tavily import TavilyClient 31 | 32 | client = TavilyClient(api_key="tvly-dev-XXXX") 33 | search_response = client.search(search_phrase, include_raw_content=True) 34 | return search_response["results"] 35 | -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal_generating/0.code_skill.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | def perform_search(search_phrase: str): 16 | """ 17 | Performs a search using the Tavily API and returns a list of search result objects. 18 | 19 | Args: 20 | search_phrase (str): The phrase to search for using the Tavily API. 21 | 22 | Returns: 23 | List[Dict[str, Any]]: A list of search result dictionaries obtained from the Tavily API. Each dictionary has 'content' field with text retrieved from the result, and a 'url' field that keeps the url of the search result. 24 | 25 | Raises: 26 | TavilyClientError: If there is an issue with the Tavily API client or the search request. 27 | KeyError: If the expected 'results' key is missing in the search response. 28 | 29 | """ 30 | from tavily import TavilyClient 31 | 32 | client = TavilyClient(api_key="tvly-dev-XXXX") 33 | search_response = client.search(search_phrase, include_raw_content=True) 34 | return search_response["results"] 35 | -------------------------------------------------------------------------------- /backend/frame/tidings.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | from typing import Any 16 | 17 | 18 | class Tiding: 19 | def __init__( 20 | self, natural_name: str, python_name: str, description: str, content: Any 21 | ) -> None: 22 | self.natural_name = natural_name 23 | self.python_name = python_name 24 | self.description = description 25 | self.content = content 26 | 27 | def __str__(self) -> str: 28 | return f"Natural name: {self.natural_name}\nPython name: {self.python_name}\nDescription: {self.description}\nContent: {self.content}" 29 | 30 | def to_dict(self) -> dict: 31 | return { 32 | "natural_name": self.natural_name, 33 | "python_name": self.python_name, 34 | "description": self.description, 35 | "content": self.content, 36 | "type": type(self.content).__name__, 37 | } 38 | 39 | def from_dict(self, tiding: dict) -> None: 40 | self.natural_name = tiding["natural_name"] 41 | self.python_name = tiding["python_name"] 42 | self.description = tiding["description"] 43 | self.content = tiding["content"] 44 | -------------------------------------------------------------------------------- /backend/frame/trace.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | import os 16 | import sys 17 | from typing import Callable 18 | 19 | 20 | class Trace: 21 | def __init__( 22 | self, 23 | path: str | None = None, 24 | copy_into_stdout: bool = False, 25 | hook: Callable = None, 26 | ) -> None: 27 | self.path = path 28 | self.entries = [] 29 | self.copy_into_stdout = copy_into_stdout 30 | self.hook = hook 31 | 32 | # set self.file to a new file if path is not None or to stdout if it is None 33 | self.file = open(path, "w") if path is not None else open(os.devnull, "w") 34 | 35 | def write(self, entry: str) -> None: 36 | self.entries.append(entry) 37 | print(entry, file=self.file, flush=True) 38 | if self.copy_into_stdout: 39 | print(entry, file=sys.stdout, flush=True) 40 | if self.hook is not None: 41 | self.hook(entry) 42 | 43 | def close(self) -> None: 44 | self.file.close() 45 | 46 | def __call__(self, *args) -> None: 47 | for arg in args: 48 | self.write(str(arg)) 49 | 50 | def write_separator(self) -> None: 51 | self.write("#" * 80) 52 | -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal/0.code_skill.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | def send_message(type, description, **kwargs): 16 | """ 17 | Sends a message by appending it to the global `__messages` list. 18 | 19 | This function creates a message dictionary with a specified type and description, 20 | along with any additional keyword arguments provided. The constructed message is 21 | then added to the global `__messages` list for further processing or logging. 22 | 23 | Args: 24 | type (str): The type of the message (e.g., "error", "info", "warning"). 25 | description (str): A brief description of the message content. 26 | **kwargs: Additional key-value pairs to include in the message dictionary. 27 | 28 | Raises: 29 | NameError: If the global variable `__messages` is not defined. 30 | 31 | Example: 32 | send_message( 33 | type="info", 34 | description="Process completed successfully", 35 | report="Reporting information" # optional, added for this particular example 36 | ) 37 | """ 38 | global __messages 39 | message = {"type": type, "description": description, **kwargs} 40 | __messages.append(message) 41 | -------------------------------------------------------------------------------- /frontend/src/components/ResearchProgressFooter.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .footer { 18 | display: flex; 19 | justify-content: space-between; 20 | align-items: center; 21 | padding: 1rem; 22 | border-top: 1px solid rgb(229 231 235); 23 | background-color: rgb(243 244 246); 24 | } 25 | 26 | .stats { 27 | display: flex; 28 | align-items: center; 29 | gap: 1rem; 30 | } 31 | 32 | .time { 33 | color: rgb(17 24 39); 34 | font-size: 0.875rem; 35 | font-weight: 500; 36 | } 37 | 38 | .searchCount, 39 | .queryCount { 40 | display: flex; 41 | align-items: center; 42 | gap: 0.5rem; 43 | color: rgb(17 24 39); 44 | font-size: 0.875rem; 45 | } 46 | 47 | .searchIcon, 48 | .queryIcon { 49 | height: 1rem; 50 | width: 1rem; 51 | color: rgb(107 114 128); 52 | } 53 | 54 | /* Dark mode styles */ 55 | @media (prefers-color-scheme: dark) { 56 | .footer { 57 | border-top-color: rgb(55 65 81); 58 | background-color: rgb(31 41 55); 59 | } 60 | 61 | .time { 62 | color: rgb(243 244 246); 63 | } 64 | 65 | .searchCount, 66 | .queryCount { 67 | color: rgb(243 244 246); 68 | } 69 | 70 | .searchIcon, 71 | .queryIcon { 72 | color: rgb(156 163 175); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /frontend/src/components/ResearchProgressItem.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .item { 18 | display: flex; 19 | padding: 1rem; 20 | gap: 1rem; 21 | border-bottom: 1px solid rgb(229 231 235); 22 | transition: background-color 0.2s ease-in-out; 23 | } 24 | 25 | .item:hover { 26 | background-color: rgb(229 231 235); 27 | } 28 | 29 | .iconContainer { 30 | display: flex; 31 | align-items: flex-start; 32 | padding-top: 0.25rem; 33 | } 34 | 35 | .icon { 36 | height: 1.25rem; 37 | width: 1.25rem; 38 | color: rgb(107 114 128); 39 | } 40 | 41 | .content { 42 | flex: 1; 43 | display: flex; 44 | flex-direction: column; 45 | gap: 0.25rem; 46 | } 47 | 48 | .description { 49 | color: rgb(17 24 39); 50 | font-size: 0.875rem; 51 | line-height: 1.25rem; 52 | } 53 | 54 | .timestamp { 55 | color: rgb(107 114 128); 56 | font-size: 0.75rem; 57 | } 58 | 59 | /* Dark mode styles */ 60 | @media (prefers-color-scheme: dark) { 61 | .item { 62 | border-bottom-color: rgb(55 65 81); 63 | } 64 | 65 | .item:hover { 66 | background-color: rgb(55 65 81); 67 | } 68 | 69 | .icon { 70 | color: rgb(156 163 175); 71 | } 72 | 73 | .description { 74 | color: rgb(243 244 246); 75 | } 76 | 77 | .timestamp { 78 | color: rgb(156 163 175); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /frontend/src/components/PromptBarButton.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .button { 18 | position: absolute; 19 | right: 0.5rem; 20 | bottom: 0.75rem; 21 | padding: 0.5rem; 22 | background: none; 23 | border: none; 24 | cursor: pointer; 25 | border-radius: 0.5rem; 26 | transition: all 0.2s ease-in-out; 27 | } 28 | 29 | .button:hover { 30 | background-color: rgb(229 231 235); 31 | } 32 | 33 | .button.disabled { 34 | cursor: not-allowed; 35 | opacity: 0.5; 36 | } 37 | 38 | .button.disabled:hover { 39 | background-color: transparent; 40 | } 41 | 42 | .icon { 43 | height: 1.25rem; 44 | width: 1.25rem; 45 | color: rgb(156 163 175); 46 | transition: color 0.2s ease-in-out; 47 | } 48 | 49 | .button:hover .icon { 50 | color: rgb(107 114 128); 51 | } 52 | 53 | .button.disabled:hover .icon { 54 | color: rgb(156 163 175); 55 | } 56 | 57 | /* Dark mode styles */ 58 | @media (prefers-color-scheme: dark) { 59 | .button:hover { 60 | background-color: rgb(55 65 81); 61 | } 62 | 63 | .icon { 64 | color: rgb(107 114 128); 65 | } 66 | 67 | .button:hover .icon { 68 | color: rgb(156 163 175); 69 | } 70 | 71 | .button.disabled:hover { 72 | background-color: transparent; 73 | } 74 | 75 | .button.disabled:hover .icon { 76 | color: rgb(107 114 128); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /frontend/src/components/ResearchTypeSelector.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .container { 18 | display: flex; 19 | gap: 0.5rem; 20 | } 21 | 22 | .button { 23 | display: flex; 24 | align-items: center; 25 | gap: 0.5rem; 26 | padding: 0.2rem 0.5rem; 27 | background-color: rgb(243 244 246); 28 | border: 1px solid transparent; 29 | border-radius: 0.5rem; 30 | cursor: pointer; 31 | transition: all 0.2s ease-in-out; 32 | } 33 | 34 | .button:disabled:not(.selected) { 35 | cursor: not-allowed; 36 | opacity: 0.5; 37 | } 38 | 39 | .button:not(:disabled):hover { 40 | background-color: rgb(229 231 235); 41 | } 42 | 43 | .button.selected { 44 | border-color: rgb(75 85 99); 45 | } 46 | 47 | .icon { 48 | width: 0.875rem; 49 | height: 0.875rem; 50 | color: rgb(75 85 99); 51 | } 52 | 53 | .label { 54 | font-size: 0.75rem; 55 | font-weight: 500; 56 | color: rgb(55 65 81); 57 | } 58 | 59 | /* Dark mode styles */ 60 | @media (prefers-color-scheme: dark) { 61 | .button { 62 | background-color: rgb(55 65 81); 63 | } 64 | 65 | .button:hover { 66 | background-color: rgb(75 85 99); 67 | } 68 | 69 | .button.selected { 70 | border-color: rgb(209 213 219); 71 | } 72 | 73 | .icon { 74 | color: rgb(209 213 219); 75 | } 76 | 77 | .label { 78 | color: rgb(229 231 235); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /backend/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to the Universal Deep Research Backend (UDR-B) will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.0] - 2025-07-15 9 | 10 | ### Added 11 | 12 | - Initial release of Universal Deep Research Backend (UDR-B) 13 | - FastAPI-based REST API with streaming responses 14 | - Intelligent research capabilities using LLMs and web search 15 | - Multi-model support through compatible APIs (OpenAI, NVIDIA, local vLLM) 16 | - Tavily API integration for web search functionality 17 | - Session management with persistent research sessions 18 | - Advanced FrameV4 reasoning framework 19 | - Dry run mode for testing with mock data 20 | - Comprehensive configuration system with environment variables 21 | - Real-time progress updates via Server-Sent Events 22 | - CORS support for frontend integration 23 | - Logging and tracing capabilities 24 | - Mock data for development and testing 25 | 26 | ### Technical Features 27 | 28 | - `/api/research` endpoint for comprehensive research workflow 29 | - `/api/research2` endpoint for advanced FrameV4-based research 30 | - Modular architecture with configurable components 31 | - Support for multiple LLM providers and models 32 | - Environment-based configuration management 33 | - Setup script for easy deployment 34 | - Comprehensive error handling and validation 35 | 36 | ### Documentation 37 | 38 | - Complete README with setup and usage instructions 39 | - API endpoint documentation 40 | - Configuration guide 41 | - Troubleshooting section 42 | - Disclaimer for research/demonstration use 43 | 44 | ### Research/Demonstration Focus 45 | 46 | - Prototype implementation for AI research concepts 47 | - Experimental features for academic research 48 | - Not intended for production use 49 | - Comprehensive legal disclaimer included 50 | 51 | --- 52 | 53 | ## Version History 54 | 55 | - **1.0.0**: Initial research prototype release 56 | -------------------------------------------------------------------------------- /backend/frame/errands/message_generating_routine_call.txt: -------------------------------------------------------------------------------- 1 | You are a helpful assistant for generating a Python function call snippet. Your task is to process the MESSAGE, the generated CODE (a function definition), and the TIDINGS (a set of variable names and values). Your goal is to output a single line of Python code that calls the function defined in CODE, passing the variable names from TIDINGS as arguments (not their values), and captures the returned generator. The function defined in CODE always returns a generator of dictionaries (Generator[dict[str, Any], None, None]). 2 | 3 | ===SEPARATOR=== 4 | You are given: 5 | - MESSAGE: the original user message (for context) that was used to produce CODE 6 | - CODE: a Python function definition (already generated) 7 | - TIDINGS: a set of variable names and values (as would be passed to the function), some of which might be useful to pass to CODE in order to accomplish the intent of code in MESSAGE 8 | 9 | Your job is to: 10 | 1. Output a single line of Python code that calls the function defined in CODE, passing the variable names from TIDINGS as named arguments (keyword arguments) where applicable/relevant/good fit. 11 | 2. Capture the returned generator into a __generator variable, such as 12 | __generator = function_from_CODE(var1=var1, var2=var2, ...) 13 | where var1, var2, ... are the variable names from TIDINGS. 14 | 3. Output only the Python code line, with no extra text, comments, or formatting. 15 | 16 | If there are no tidings, call the function defined in CODE with no arguments: 17 | __generator = function_from_CODE() 18 | 19 | This is the end of the instructions. Below is the input to process. 20 | 21 | MESSAGE: 22 | {message} 23 | 24 | CODE: 25 | {code} 26 | 27 | TIDINGS: 28 | {tidings} 29 | 30 | Reminders: 31 | - Output just the function call to the functiond defined in CODE so that the intent of MESSAGE (from which CODE was generated) is fulfilled. 32 | - To pass variables into the function call, use variable names described under TIDINGS. 33 | - Do not output any other text. Do not output any surrounding backticks or code tags. -------------------------------------------------------------------------------- /backend/frame/errands/message_code_call.txt: -------------------------------------------------------------------------------- 1 | You are a helpful assistant for generating a Python function call snippet. Your task is to process the MESSAGE, the generated CODE (a function definition), and the TIDINGS (a set of variable names and values). Your goal is to output a single line of Python code that calls the function defined in CODE, passing the variable names from TIDINGS as arguments (not their values), and captures the return values into variables named __output and __vars. The function defined in CODE always returns a tuple (output: str, variables: dict[str, Any]). 2 | 3 | ===SEPARATOR=== 4 | You are given: 5 | - MESSAGE: the original user message (for context) that was used to produce CODE 6 | - CODE: a Python function definition (already generated) 7 | - TIDINGS: a set of variable names and values (as would be passed to the function), some of which might be useful to pass to CODE in order to accomplish the intent of code in MESSAGE 8 | 9 | Your job is to: 10 | 1. Output a single line of Python code that calls the function defined in CODE, passing the variable names from TIDINGS as named arguments (keyword arguments) where applicable/relevant/good fit. 11 | 2. Capture the return values into variables named __output and __vars, like this: 12 | __output, __vars = function_from_CODE(var1=var1, var2=var2, ...) 13 | where var1, var2, ... are the variable names from TIDINGS. 14 | 3. Output only the Python code line, with no extra text, comments, or formatting. 15 | 16 | If there are no tidings, call the function defined in CODE with no arguments: 17 | __output, __vars = function_from_CODE() 18 | 19 | This is the end of the instructions. Below is the input to process. 20 | 21 | MESSAGE: 22 | {message} 23 | 24 | CODE: 25 | {code} 26 | 27 | TIDINGS: 28 | {tidings} 29 | 30 | Reminders: 31 | - Output just the function call to the functiond defined in CODE so that the intent of MESSAGE (from which CODE was generated) is fulfilled. 32 | - To pass variables into the function call, use variable names described under TIDINGS. 33 | - Do not output any other text. Do not output any surrounding backticks or code tags. -------------------------------------------------------------------------------- /backend/frame/errands/message_routine_call.txt: -------------------------------------------------------------------------------- 1 | You are a helpful assistant for generating a Python function call snippet. Your task is to process the MESSAGE, the generated CODE (a function definition), and the TIDINGS (a set of variable names and values). Your goal is to output a single line of Python code that calls the function defined in CODE, passing the variable names from TIDINGS as arguments (not their values), and captures the return values into variables named __output and __vars. The function defined in CODE always returns a tuple (output: str, variables: dict[str, Any]). 2 | 3 | ===SEPARATOR=== 4 | You are given: 5 | - MESSAGE: the original user message (for context) that was used to produce CODE 6 | - CODE: a Python function definition (already generated) 7 | - TIDINGS: a set of variable names and values (as would be passed to the function), some of which might be useful to pass to CODE in order to accomplish the intent of code in MESSAGE 8 | 9 | Your job is to: 10 | 1. Output a single line of Python code that calls the function defined in CODE, passing the variable names from TIDINGS as named arguments (keyword arguments) where applicable/relevant/good fit. 11 | 2. Capture the return values into variables named __output and __vars, like this: 12 | __output, __vars = function_from_CODE(var1=var1, var2=var2, ...) 13 | where var1, var2, ... are the variable names from TIDINGS. 14 | 3. Output only the Python code line, with no extra text, comments, or formatting. 15 | 16 | If there are no tidings, call the function defined in CODE with no arguments: 17 | __output, __vars = function_from_CODE() 18 | 19 | This is the end of the instructions. Below is the input to process. 20 | 21 | MESSAGE: 22 | {message} 23 | 24 | CODE: 25 | {code} 26 | 27 | TIDINGS: 28 | {tidings} 29 | 30 | Reminders: 31 | - Output just the function call to the functiond defined in CODE so that the intent of MESSAGE (from which CODE was generated) is fulfilled. 32 | - To pass variables into the function call, use variable names described under TIDINGS. 33 | - Do not output any other text. Do not output any surrounding backticks or code tags. -------------------------------------------------------------------------------- /backend/frame/errands/message_code_variables.txt: -------------------------------------------------------------------------------- 1 | You are an expert Python code and documentation analyst. Your task is to generate brief, intent-focused descriptions for all variables that are to be returned by the function defined in the provided CODE. Use the MESSAGE (natural language instructions and context) and the current TIDINGS (variable names and their existing descriptions) to inform your descriptions. 2 | 3 | ===SEPARATOR=== 4 | You are an expert Python code and documentation analyst. Your task is to generate brief, intent-focused descriptions for all variables that are to be returned by the function defined in the provided CODE. Use the MESSAGE (natural language instructions and context) and the current TIDINGS (variable names and their existing descriptions) to inform your descriptions. 5 | 6 | Guidelines: 7 | - If a variable's description in TIDINGS is already sufficient and perhaps better than what you could generate, copy it exactly as is. 8 | - Otherwise, write a new description that is brief, captures the type hints if possible, and describes the intent and role of the variable. Include other names if the MESSAGE gives any. 9 | - The description should not be too long or too short; it should be just informative enough. 10 | - Focus on the intent and role of each variable. 11 | 12 | # Note: For each line in TIDINGS, the format is: 13 | # variable_name: value # description 14 | # Only use the description after the '#' for reference; ignore the value. 15 | 16 | For each variable that will be returned by the function in CODE, output a mapping in the following format: 17 | 18 | variable_name # description 19 | 20 | Only include variables that are returned by the function. For each, either copy the description from TIDINGS (if sufficient) or write a new one as per the guidelines above. 21 | 22 | Reminders: 23 | - Output the descriptions in the form variable_name # description 24 | - Use expert description but don't get too verbose 25 | - Do not output any other text. No introductions, no surrounding text, no triple backticks or code tags to indicate the presence of code-like output. Output just the descriptions in the requested format. Do not output any other text. 26 | 27 | Input: 28 | MESSAGE: 29 | {message} 30 | 31 | CODE: 32 | {code} 33 | 34 | TIDINGS (variable: value # description): 35 | {tidings} -------------------------------------------------------------------------------- /backend/frame/errands/message_routine_variables.txt: -------------------------------------------------------------------------------- 1 | You are an expert Python code and documentation analyst. Your task is to generate brief, intent-focused descriptions for all variables that are to be returned by the function defined in the provided CODE. Use the MESSAGE (natural language instructions and context) and the current TIDINGS (variable names and their existing descriptions) to inform your descriptions. 2 | 3 | ===SEPARATOR=== 4 | 5 | You are an expert Python code and documentation analyst. Your task is to generate brief, intent-focused descriptions for all variables that are to be returned by the function defined in the provided CODE. Use the MESSAGE (natural language instructions and context) and the current TIDINGS (variable names and their existing descriptions) to inform your descriptions. 6 | 7 | Guidelines: 8 | - If a variable's description in TIDINGS is already sufficient and perhaps better than what you could generate, copy it exactly as is. 9 | - Otherwise, write a new description that is brief, captures the type hints if possible, and describes the intent and role of the variable. Include other names if the MESSAGE gives any. 10 | - The description should not be too long or too short; it should be just informative enough. 11 | - Focus on the intent and role of each variable. 12 | 13 | # Note: For each line in TIDINGS, the format is: 14 | # variable_name: value # description 15 | # Only use the description after the '#' for reference; ignore the value. 16 | 17 | For each variable that will be returned by the function in CODE, output a mapping in the following format: 18 | 19 | variable_name # description 20 | 21 | Only include variables that are returned by the function. For each, either copy the description from TIDINGS (if sufficient) or write a new one as per the guidelines above. 22 | 23 | Reminders: 24 | - Output the descriptions in the form variable_name # description 25 | - Use expert description but don't get too verbose 26 | - Do not output any other text. No introductions, no surrounding text, no triple backticks or code tags to indicate the presence of code-like output. Output just the descriptions in the requested format. Do not output any other text. 27 | 28 | Input: 29 | MESSAGE: 30 | {message} 31 | 32 | CODE: 33 | {code} 34 | 35 | TIDINGS (variable: value # description): 36 | {tidings} -------------------------------------------------------------------------------- /frontend/src/config/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | export interface AppConfig { 18 | // Backend API Configuration 19 | backend: { 20 | baseUrl: string; 21 | port: number; 22 | apiVersion: 'v1' | 'v2'; 23 | }; 24 | 25 | // Runtime Configuration 26 | runtime: { 27 | dryRun: boolean; 28 | enableV2Api: boolean; 29 | }; 30 | 31 | // Frontend Configuration 32 | frontend: { 33 | port: number; 34 | host: string; 35 | }; 36 | } 37 | 38 | // Default configuration 39 | const defaultConfig: AppConfig = { 40 | backend: { 41 | baseUrl: process.env.NEXT_PUBLIC_BACKEND_BASE_URL || 'http://localhost', 42 | port: parseInt(process.env.NEXT_PUBLIC_BACKEND_PORT || '8000'), 43 | apiVersion: (process.env.NEXT_PUBLIC_API_VERSION as 'v1' | 'v2') || 'v2', 44 | }, 45 | runtime: { 46 | dryRun: process.env.NEXT_PUBLIC_DRY_RUN === 'true', 47 | enableV2Api: process.env.NEXT_PUBLIC_ENABLE_V2_API !== 'false', 48 | }, 49 | frontend: { 50 | port: parseInt(process.env.NEXT_PUBLIC_FRONTEND_PORT || '3000'), 51 | host: process.env.NEXT_PUBLIC_FRONTEND_HOST || 'localhost', 52 | }, 53 | }; 54 | 55 | // Helper function to get the full backend URL 56 | export const getBackendUrl = (config: AppConfig = defaultConfig): string => { 57 | return `${config.backend.baseUrl}:${config.backend.port}`; 58 | }; 59 | 60 | // Helper function to get the API endpoint 61 | export const getApiEndpoint = (config: AppConfig = defaultConfig): string => { 62 | const baseUrl = getBackendUrl(config); 63 | const endpoint = config.runtime.enableV2Api ? '/api/research2' : '/api/research'; 64 | return `${baseUrl}${endpoint}`; 65 | }; 66 | 67 | export default defaultConfig; -------------------------------------------------------------------------------- /frontend/src/components/PromptBar.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .promptContainer { 18 | position: relative; 19 | width: 100%; 20 | max-width: 42rem; 21 | } 22 | 23 | .promptBody { 24 | position: relative; 25 | width: 100%; 26 | } 27 | 28 | .promptTextarea { 29 | width: 100%; 30 | padding: 1rem; 31 | padding-right: 3rem; 32 | background-color: rgb(243 244 246); 33 | border-radius: 1rem; 34 | border: none; 35 | resize: none; 36 | overflow: hidden; 37 | min-height: 1.5rem; 38 | max-height: 200px; 39 | color: rgb(17 24 39); 40 | transition: all 0.2s ease-in-out; 41 | line-height: 1.5; 42 | } 43 | 44 | .promptTextarea:hover { 45 | background-color: rgb(229 231 235); 46 | box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); 47 | } 48 | 49 | .promptTextarea:focus { 50 | outline: none; 51 | box-shadow: 0 0 0 2px rgb(209 213 219); 52 | background-color: rgb(243 244 246); 53 | } 54 | 55 | .promptTextarea::placeholder { 56 | color: rgb(107 114 128); 57 | } 58 | 59 | .promptTextarea.disabled { 60 | background-color: rgb(229 231 235); 61 | color: rgb(156 163 175); 62 | cursor: not-allowed; 63 | } 64 | 65 | .promptTextarea.disabled:hover { 66 | background-color: rgb(229 231 235); 67 | box-shadow: none; 68 | } 69 | 70 | .promptBarFooter { 71 | display: flex; 72 | justify-content: space-between; 73 | align-items: center; 74 | margin-top: 0.5rem; 75 | width: 100%; 76 | } 77 | 78 | .shortcutHint { 79 | position: relative; 80 | font-size: 0.75rem; 81 | color: rgb(107 114 128); 82 | display: flex; 83 | align-items: center; 84 | gap: 0.25rem; 85 | opacity: 0; 86 | transition: opacity 0.2s ease-in-out; 87 | } 88 | 89 | .shortcutHint.visible { 90 | opacity: 1; 91 | } 92 | -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal/3.auto.txt: -------------------------------------------------------------------------------- 1 | 1. Send a message of type "prompt_received" with description saying what PROMPT has been received, e.g. "Received research request: {PROMPT}" 2 | 2. Send a message of type "prompt_analysis_started", with description indicating that we are now analyzing the research request. 3 | 3. Take the PROMPT and ask a language model to produce 3 search phrases that could help with retrieving results from search engine for the purpose of compiling a report the user asks for in the PROMPT. The search phrases should be simple and objective, e.g. "important events 1972" or "energy consumption composition in India today". Use a long prompt for the model that describes in detail what is supposed to be performed and the expected output format. Instruct the model to return the search phrases on one line each. Tell the model not to output any other text -- just the newline-separated phrases. Then, parse the output of the language model line by line and save the resulting search phrases as "phrases" for further research, skipping over empty lines. 4 | 4. Send a message of type "prompt_analysis_completed", with a description saying as much. 5 | 5. For each phrase in phrases output by step 3., perform the following: 6 | - Send a message of type "search_started", with the description indicating what search phrase we are using for the search, e.g. "Searching for phrase '{phrase}'" 7 | - Perform search with the phrase. Once the search returns some results, append their contents to CONTEXT one by one, separating them by double newlines from what is already present in the CONTEXT. 8 | 6. Send a message with type "report_building", with the description indicating that the report is being built. 9 | 7. Take CONTEXT. Call the language model, instructing it to take CONTEXT (to be appended into the LM call) and produce a deep research report on the topic requested in PROMPT. The resulting report should go into detail wherever possible, rely only on the information available in CONTEXT, address the instruction given in the PROMPT, and be formatted in Markdown. This is to be communicated in the prompt. Do not shy away from using long, detailed and descriptive prompts! Tell the model not to output any other text, just the report. The result produced by the language model is to be called REPORT. 10 | 8. Send a message with type "report_done", indicating that the report has been completed. Add "report" as a field containing the REPORT to be an additional payload to the message. 11 | 9. Output the REPORT. 12 | -------------------------------------------------------------------------------- /frontend/src/components/ResearchProgressList.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .wrapper { 18 | width: 100%; 19 | height: 400px; /* Same as max-height of container */ 20 | display: flex; 21 | flex-direction: column; 22 | } 23 | 24 | .content { 25 | width: 100%; 26 | height: 100%; 27 | opacity: 0; 28 | transform: translateY(10px); 29 | animation: fadeIn 0.3s ease-out forwards; 30 | } 31 | 32 | @keyframes fadeIn { 33 | from { 34 | opacity: 0; 35 | transform: translateY(10px); 36 | } 37 | to { 38 | opacity: 1; 39 | transform: translateY(0); 40 | } 41 | } 42 | 43 | .container { 44 | width: 100%; 45 | max-height: 400px; 46 | min-height: 0; /* Allows container to shrink below max-height */ 47 | display: flex; 48 | flex-direction: column; 49 | background-color: rgb(243 244 246); 50 | border-radius: 1rem; 51 | overflow: hidden; 52 | transition: all 0.3s ease-out; 53 | } 54 | 55 | .list { 56 | flex: 1; 57 | overflow-y: auto; 58 | scrollbar-width: none; 59 | -ms-overflow-style: none; 60 | transition: all 0.3s ease-out; 61 | } 62 | 63 | .list::-webkit-scrollbar { 64 | display: none; 65 | } 66 | 67 | .list:hover { 68 | scrollbar-width: thin; 69 | -ms-overflow-style: auto; 70 | } 71 | 72 | .list:hover::-webkit-scrollbar { 73 | display: block; 74 | width: 8px; 75 | } 76 | 77 | .list:hover::-webkit-scrollbar-track { 78 | background: rgb(229 231 235); 79 | border-radius: 4px; 80 | } 81 | 82 | .list:hover::-webkit-scrollbar-thumb { 83 | background: rgb(156 163 175); 84 | border-radius: 4px; 85 | } 86 | 87 | /* Dark mode styles */ 88 | @media (prefers-color-scheme: dark) { 89 | .container { 90 | background-color: rgb(31 41 55); 91 | } 92 | 93 | .list:hover::-webkit-scrollbar-track { 94 | background: rgb(55 65 81); 95 | } 96 | 97 | .list:hover::-webkit-scrollbar-thumb { 98 | background: rgb(107 114 128); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /frontend/src/components/ResearchProgressItem.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 'use client'; 18 | 19 | import { ArrowDownOnSquareIcon, BoltIcon, ExclamationCircleIcon, BeakerIcon, MagnifyingGlassIcon, DocumentMagnifyingGlassIcon, DocumentCheckIcon, ClipboardDocumentListIcon, ArchiveBoxIcon, Cog8ToothIcon, LightBulbIcon, DocumentTextIcon, CheckCircleIcon, ChatBubbleLeftEllipsisIcon } from '@heroicons/react/24/outline'; 20 | import { ResearchEvent } from './ResearchProgressList'; 21 | import styles from './ResearchProgressItem.module.css'; 22 | 23 | interface ResearchProgressItemProps { 24 | event: ResearchEvent; 25 | } 26 | 27 | const iconMap = { 28 | 'started': BoltIcon, 29 | 'completed': CheckCircleIcon, 30 | 'error': ExclamationCircleIcon, 31 | 32 | 'prompt_received': ArrowDownOnSquareIcon, 33 | 'prompt_analysis_started': BeakerIcon, 34 | 'prompt_analysis_completed': DocumentTextIcon, 35 | 'task_analysis_completed': DocumentTextIcon, 36 | 'topic_exploration_started': DocumentMagnifyingGlassIcon, 37 | 'topic_exploration_completed': DocumentCheckIcon, 38 | 'search_started': MagnifyingGlassIcon, 39 | 'search_result_processing_started': ClipboardDocumentListIcon, 40 | 'aggregation_started': ArchiveBoxIcon, 41 | 'research_completed': CheckCircleIcon, 42 | 'report_building': Cog8ToothIcon, 43 | 'report_processing': LightBulbIcon, 44 | 'report_done': DocumentTextIcon, 45 | 'generic': ChatBubbleLeftEllipsisIcon 46 | }; 47 | 48 | export default function ResearchProgressItem({ event }: ResearchProgressItemProps) { 49 | const Icon = event.type in iconMap ? iconMap[event.type] : ChatBubbleLeftEllipsisIcon; 50 | const iconColor = event.type === 'error' ? 'text-red-500' : 'text-gray-500'; 51 | 52 | return ( 53 |
54 |
55 | 56 |
57 |
58 |

{event.description}

59 | 60 | {new Date(event.timestamp).toLocaleTimeString()} 61 | 62 |
63 |
64 | ); 65 | } -------------------------------------------------------------------------------- /frontend/src/components/ReportViewer.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 'use client'; 18 | 19 | import { useMemo, useEffect, useRef } from 'react'; 20 | import ReactMarkdown from 'react-markdown'; 21 | import remarkGfm from 'remark-gfm'; 22 | import styles from './ReportViewer.module.css'; 23 | 24 | interface ReportViewerProps { 25 | report: string; 26 | isVisible: boolean; 27 | } 28 | 29 | export default function ReportViewer({ report, isVisible }: ReportViewerProps) { 30 | const reportRef = useRef(null); 31 | 32 | // Memoize the markdown rendering to improve performance 33 | const renderedContent = useMemo(() => { 34 | return ( 35 | 38 | {report} 39 | 40 | ); 41 | }, [report]); 42 | 43 | // Auto-scroll to the report when it becomes visible 44 | useEffect(() => { 45 | if (isVisible && reportRef.current) { 46 | // Add a small delay to ensure the animation has started 47 | const timeoutId = setTimeout(() => { 48 | // Calculate the position to scroll to, leaving a margin at the top 49 | // The gap between ReportViewer and ResearchProgressList is mt-6 (1.5rem) 50 | // We want half of that (0.75rem = 12px) between the viewport top and ReportViewer 51 | const elementPosition = reportRef.current?.getBoundingClientRect().top || 0; 52 | const offsetPosition = elementPosition + window.pageYOffset - 12; // 12px (0.75rem) margin from top 53 | 54 | window.scrollTo({ 55 | top: offsetPosition, 56 | behavior: 'smooth' 57 | }); 58 | }, 100); 59 | 60 | return () => clearTimeout(timeoutId); 61 | } 62 | }, [isVisible]); 63 | 64 | if (!isVisible) return null; 65 | 66 | return ( 67 |
68 |
69 |
70 |
71 |

Research Report

72 |
73 |
74 | {renderedContent} 75 |
76 |
77 |
78 |
79 | ); 80 | } -------------------------------------------------------------------------------- /frontend/src/types/ApplicationState.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import { ResearchEvent } from '@/components/ResearchProgressList'; 18 | 19 | export type ApplicationState = 20 | | { 21 | type: 'idle'; 22 | sessionKey: string; 23 | researchStartTimestamp: number; 24 | researchEndTimestamp: number; 25 | searchCount: number; 26 | queryCount: number; 27 | finalizationStartTimestamp: number; 28 | finalizationEndTimestamp: number; 29 | events: ResearchEvent[]; 30 | } 31 | | { 32 | type: 'researching'; 33 | sessionKey: string; 34 | researchStartTimestamp: number; 35 | researchEndTimestamp: number; 36 | searchCount: number; 37 | queryCount: number; 38 | finalizationStartTimestamp: number; 39 | finalizationEndTimestamp: number; 40 | events: ResearchEvent[]; 41 | } 42 | | { 43 | type: 'finalizing'; 44 | sessionKey: string; 45 | researchStartTimestamp: number; 46 | researchEndTimestamp: number; 47 | searchCount: number; 48 | queryCount: number; 49 | finalizationStartTimestamp: number; 50 | finalizationEndTimestamp: number; 51 | events: ResearchEvent[]; 52 | } 53 | | { 54 | type: 'stopped'; 55 | sessionKey: string; 56 | researchStartTimestamp: number; 57 | researchEndTimestamp: number; 58 | searchCount: number; 59 | queryCount: number; 60 | finalizationStartTimestamp: number; 61 | finalizationEndTimestamp: number; 62 | events: ResearchEvent[]; 63 | } 64 | | { 65 | type: 'error'; 66 | error: string; 67 | sessionKey: string; 68 | researchStartTimestamp: number; 69 | researchEndTimestamp: number; 70 | searchCount: number; 71 | queryCount: number; 72 | finalizationStartTimestamp: number; 73 | finalizationEndTimestamp: number; 74 | events: ResearchEvent[]; 75 | } 76 | | { 77 | type: 'done'; 78 | sessionKey: string; 79 | researchStartTimestamp: number; 80 | researchEndTimestamp: number; 81 | searchCount: number; 82 | queryCount: number; 83 | finalizationStartTimestamp: number; 84 | finalizationEndTimestamp: number; 85 | events: ResearchEvent[]; 86 | }; -------------------------------------------------------------------------------- /backend/frame/prompts/udr_minimal_generating/2.routine_generating.txt: -------------------------------------------------------------------------------- 1 | 1. Send a notification of type "prompt_received" with description saying what PROMPT has been received, e.g. "Received research request: {PROMPT}" 2 | 2. Send a notification of type "prompt_analysis_started", with description indicating that we are now analyzing the research request. 3 | 3. Take the PROMPT and ask a language model to produce 3 search phrases that could help with retrieving results from search engine for the purpose of compiling a report the user asks for in the PROMPT. The search phrases should be simple and objective, e.g. "important events 1972" or "energy consumption composition in India today". Use a long prompt for the model that describes in detail what is supposed to be performed and the expected output format. Instruct the model to return the search phrases on one line each. Tell the model not to output any other text -- just the newline-separated phrases. Then, parse the output of the language model line by line and save the resulting search phrases as "phrases" for further research, skipping over empty lines. 4 | 4. Send a notification of type "prompt_analysis_completed", with a description saying as much. 5 | 4.1 Send a notification of type "task_analysis_completed", informing the user that the search plan has been completed and informing them how many search phrases will be invoked, e.g. "Search planning completed. Will be searching through {len(topics)}+ terms." 6 | 5. For each phrase in phrases output by step 3., perform the following: 7 | - Send a notification of type "search_started", with the description indicating what search phrase we are using for the search, e.g. "Searching for phrase '{phrase}'" 8 | - Perform search with the phrase. 9 | - Once the search returns some results, append their contents to CONTEXT one by one, separating them by double newlines from what is already present in the CONTEXT. 10 | - Send a notification of type "search_result_processing_completed", indicating in its description that the search results for term {term} have been processed. 11 | 6. Send a notification to the user with type "research_completed", indicating that the "Research phase is now completed.". 12 | 7. Send a notification with type "report_building", with the description indicating that the report is being built. 13 | 8. Take CONTEXT. Call the language model, instructing it to take CONTEXT (to be appended into the LM call) and produce a deep research report on the topic requested in PROMPT. The resulting report should go into detail wherever possible, rely only on the information available in CONTEXT, address the instruction given in the PROMPT, and be formatted in Markdown. This is to be communicated in the prompt. Do not shy away from using long, detailed and descriptive prompts! Tell the model not to output any other text, just the report. The result produced by the language model is to be called REPORT. 14 | 9. Send a notification with type "report_done", indicating that the report has been completed. Add "report" as a field containing the REPORT to be an additional payload to the notification. 15 | 10. Output the REPORT. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Universal Deep Research (UDR) 2 | 3 | A prototype research system that combines user-defined strategies, intelligent web search, content analysis, and automated report generation using large language models. This repository contains both the backend API service and frontend web interface. 4 | 5 | As mentioned above, this is a research demonstration prototype and should not be used for production purposes. The software contains experimental features and research-grade implementations. 6 | 7 | ## Project Structure 8 | 9 | ``` 10 | / 11 | ├── backend/ # FastAPI backend service 12 | │ ├── README.md # Backend setup and configuration 13 | │ ├── main.py # FastAPI application 14 | │ ├── scan_research.py # Core research logic 15 | │ ├── frame/ # Advanced reliability framework 16 | │ └── ... 17 | ├── frontend/ # Next.js frontend application 18 | │ ├── README.md # Frontend setup and configuration 19 | │ ├── src/ # React components and pages 20 | │ └── ... 21 | └── README.md # This file 22 | ``` 23 | 24 | ## Getting Started 25 | 26 | To run the prototype, you need to start both the backend and frontend services: 27 | 28 | ### 1. Backend Setup 29 | 30 | Navigate to the backend directory and follow the setup instructions: 31 | 32 | ```bash 33 | cd backend 34 | ``` 35 | 36 | See [backend/README.md](backend/README.md) for detailed setup instructions, including: 37 | 38 | - Python environment setup 39 | - API key configuration 40 | - Server startup commands 41 | 42 | ### 2. Frontend Setup 43 | 44 | In a new terminal, navigate to the frontend directory: 45 | 46 | ```bash 47 | cd frontend 48 | ``` 49 | 50 | See [frontend/README.md](frontend/README.md) for detailed setup instructions, including: 51 | 52 | - Node.js dependencies installation 53 | - Environment configuration 54 | - Development server startup 55 | 56 | ### 3. Running the Prototype 57 | 58 | 1. **Start the backend server** (typically on port 8000): 59 | 60 | ```bash 61 | cd backend 62 | launch_server.sh 63 | ``` 64 | 65 | 2. **Start the frontend development server** (typically on port 3000): 66 | 67 | ```bash 68 | cd frontend 69 | npm run dev 70 | ``` 71 | 72 | 3. **Access the application**: 73 | Open your browser and navigate to `http://localhost:3000` or similar as output by the terminal. 74 | 75 | ## Features 76 | 77 | - **Intelligent Research**: User-configurable research strategies 78 | - **Real-time Progress**: Live updates during research and report generation 79 | - **Interactive Interface**: Modern web UI for research queries and results 80 | - **Multi-Model Support**: Configurable LLM backends 81 | 82 | ## Documentation 83 | 84 | - [Backend Documentation](backend/README.md) - API setup, configuration, and endpoints 85 | - [Frontend Documentation](frontend/README.md) - UI setup, configuration, and deployment 86 | 87 | ## Requirements 88 | 89 | - Python 3.8+ (for backend) 90 | - Node.js 18+ (for frontend) 91 | - API keys for LLM providers (e.g., NVIDIA NGC, OpenAI, etc.) 92 | - Tavily API key for web search functionality 93 | 94 | ## Development 95 | 96 | This is a research prototype demonstrating AI-powered research automation concepts. The codebase is structured for experimentation and demonstration rather than production deployment. 97 | -------------------------------------------------------------------------------- /frontend/src/components/ResearchStrategyEditor.module.css: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | .strategyContainer { 18 | position: relative; 19 | width: 100%; 20 | max-width: 42rem; 21 | } 22 | 23 | .strategyBody { 24 | position: relative; 25 | width: 100%; 26 | } 27 | 28 | .strategyTextarea { 29 | width: 100%; 30 | padding: 1rem; 31 | padding-right: 3rem; 32 | background-color: rgb(243 244 246); 33 | border-radius: 1rem; 34 | border: none; 35 | resize: none; 36 | overflow: auto; 37 | min-height: 15rem; 38 | max-height: 20rem; 39 | color: rgb(17 24 39); 40 | transition: all 0.2s ease-in-out; 41 | line-height: 1.5; 42 | } 43 | 44 | .strategyTextarea:hover { 45 | background-color: rgb(229 231 235); 46 | box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); 47 | } 48 | 49 | .strategyTextarea:focus { 50 | outline: none; 51 | box-shadow: 0 0 0 2px rgb(209 213 219); 52 | background-color: rgb(243 244 246); 53 | } 54 | 55 | .strategyTextarea::placeholder { 56 | color: rgb(107 114 128); 57 | } 58 | 59 | .strategyTextarea.disabled { 60 | background-color: rgb(229 231 235); 61 | color: rgb(156 163 175); 62 | cursor: not-allowed; 63 | } 64 | 65 | .strategyTextarea.disabled:hover { 66 | background-color: rgb(229 231 235); 67 | box-shadow: none; 68 | } 69 | 70 | .strategyFooter { 71 | display: flex; 72 | justify-content: space-between; 73 | align-items: center; 74 | margin-top: 0.5rem; 75 | width: 100%; 76 | } 77 | 78 | .shortcutHint { 79 | position: relative; 80 | font-size: 0.75rem; 81 | color: rgb(107 114 128); 82 | display: flex; 83 | align-items: center; 84 | gap: 0.25rem; 85 | opacity: 0; 86 | transition: opacity 0.2s ease-in-out; 87 | } 88 | 89 | .shortcutHint.visible { 90 | opacity: 1; 91 | } 92 | 93 | .strategyButtons { 94 | position: absolute; 95 | right: 0.5rem; 96 | bottom: 0.75rem; 97 | display: flex; 98 | gap: 0.5rem; 99 | z-index: 1; 100 | } 101 | 102 | .strategyButton { 103 | display: flex; 104 | align-items: center; 105 | justify-content: center; 106 | width: 2rem; 107 | height: 2rem; 108 | border: none; 109 | border-radius: 0.5rem; 110 | background: none; 111 | border: none; 112 | cursor: pointer; 113 | border-radius: 0.5rem; 114 | transition: all 0.2s ease-in-out; 115 | color: rgb(156 163 175); 116 | } 117 | 118 | .strategyButton:hover:not(:disabled) { 119 | background-color: rgb(229 231 235); 120 | } 121 | 122 | .strategyButton:disabled { 123 | opacity: 0.5; 124 | cursor: not-allowed; 125 | } 126 | -------------------------------------------------------------------------------- /backend/insert_license.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | import os 16 | from typing import List 17 | 18 | def add_header_to_python_files(directory_path, header_content, extensions: List[str] = [".py"]): 19 | """ 20 | Inserts a specified header at the beginning of every .py file 21 | in the given directory and its subdirectories. 22 | 23 | Args: 24 | directory_path (str): The path to the directory to process. 25 | header_content (str): The content of the header to insert. 26 | Ensure it includes newlines for proper formatting. 27 | """ 28 | for root, _, files in os.walk(directory_path): 29 | for file_name in files: 30 | if file_name == '.venv': 31 | continue 32 | for extension in extensions: 33 | if file_name.endswith(extension): 34 | file_path = os.path.join(root, file_name) 35 | try: 36 | with open(file_path, 'r+', encoding='utf-8') as f: 37 | original_content = f.read() 38 | if original_content.startswith(header_content): 39 | print(f"Header already exists in: {file_path}") 40 | continue 41 | f.seek(0) # Move cursor to the beginning of the file 42 | f.write(header_content + original_content) 43 | print(f"Header added to: {file_path}") 44 | except IOError as e: 45 | print(f"Error processing {file_path}: {e}") 46 | 47 | if __name__ == "__main__": 48 | target_directory = "../frontend" # Replace with your target directory 49 | 50 | # Define your header content here. Use triple quotes for multi-line strings. 51 | # Ensure a newline character at the end of the header for separation. 52 | custom_header = """/* 53 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 54 | * SPDX-License-Identifier: Apache-2.0 55 | * 56 | * Licensed under the Apache License, Version 2.0 (the "License"); 57 | * you may not use this file except in compliance with the License. 58 | * You may obtain a copy of the License at 59 | * 60 | * http://www.apache.org/licenses/LICENSE-2.0 61 | * 62 | * Unless required by applicable law or agreed to in writing, software 63 | * distributed under the License is distributed on an "AS IS" BASIS, 64 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | * See the License for the specific language governing permissions and 66 | * limitations under the License. 67 | */ 68 | """ 69 | 70 | add_header_to_python_files(target_directory, custom_header, extensions=[".js", ".ts", ".tsx", ".jsx", ".css"]) -------------------------------------------------------------------------------- /backend/DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | DISCLAIMER 2 | 3 | IMPORTANT NOTICE - RESEARCH DEMONSTRATION PROTOTYPE 4 | 5 | This software and all associated code, documentation, and materials (collectively, the "Software") are provided solely for research and demonstration purposes. The Software is intended exclusively as a prototype to demonstrate research concepts and methodologies in the field of artificial intelligence and automated research systems. 6 | 7 | CRITICAL LIMITATIONS AND WARNINGS: 8 | 9 | 1. RESEARCH PURPOSE ONLY: The Software is designed and intended solely for academic research, educational demonstration, and experimental purposes. It is NOT intended for production use, commercial deployment, or any real-world application. 10 | 11 | 2. NO PRODUCTION USE: Under no circumstances should this Software be deployed, used, or relied upon in any production environment, commercial application, or any context where reliability, accuracy, or safety is required. 12 | 13 | 3. EXPERIMENTAL NATURE: The Software contains experimental features, unproven methodologies, and research-grade implementations that may contain bugs, security vulnerabilities, or other issues that could cause data loss, system instability, or other problems. 14 | 15 | 4. NO WARRANTIES: THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR ACCURACY. 16 | 17 | 5. NO LIABILITY: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER NVIDIA CORPORATION, NOR THE AUTHORS, CONTRIBUTORS, OR ANY OTHER PARTIES INVOLVED IN THE CREATION, PRODUCTION, OR DELIVERY OF THE SOFTWARE SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | 19 | 6. NO SUPPORT: No technical support, maintenance, updates, or assistance is provided for this Software. Users are solely responsible for their use of the Software and any consequences thereof. 20 | 21 | 7. NO ENDORSEMENT: The inclusion of any third-party components, APIs, or services does not constitute an endorsement of those services or their providers. 22 | 23 | 8. COMPLIANCE: Users are responsible for ensuring their use of the Software complies with all applicable laws, regulations, and terms of service for any third-party services or APIs used by the Software. 24 | 25 | 9. SECURITY: The Software has not been subjected to security audits or testing suitable for production environments. Users assume all risks associated with security vulnerabilities. 26 | 27 | 10. DATA PRIVACY: The Software may process, transmit, or store data in ways that do not comply with data protection regulations. Users are responsible for ensuring compliance with applicable privacy laws. 28 | 29 | ACKNOWLEDGMENT: 30 | 31 | By using, copying, modifying, or distributing the Software, you acknowledge that you have read, understood, and agree to be bound by the terms of this disclaimer. If you do not agree to these terms, you must not use the Software. 32 | 33 | For questions regarding this disclaimer, please contact the authors through the appropriate channels established for this research project. 34 | 35 | Last updated: 07/15/2025. 36 | -------------------------------------------------------------------------------- /frontend/DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | DISCLAIMER 2 | 3 | IMPORTANT NOTICE - RESEARCH DEMONSTRATION PROTOTYPE 4 | 5 | This software and all associated code, documentation, and materials (collectively, the "Software") are provided solely for research and demonstration purposes. The Software is intended exclusively as a prototype to demonstrate research concepts and methodologies in the field of artificial intelligence and automated research systems. 6 | 7 | CRITICAL LIMITATIONS AND WARNINGS: 8 | 9 | 1. RESEARCH PURPOSE ONLY: The Software is designed and intended solely for academic research, educational demonstration, and experimental purposes. It is NOT intended for production use, commercial deployment, or any real-world application. 10 | 11 | 2. NO PRODUCTION USE: Under no circumstances should this Software be deployed, used, or relied upon in any production environment, commercial application, or any context where reliability, accuracy, or safety is required. 12 | 13 | 3. EXPERIMENTAL NATURE: The Software contains experimental features, unproven methodologies, and research-grade implementations that may contain bugs, security vulnerabilities, or other issues that could cause data loss, system instability, or other problems. 14 | 15 | 4. NO WARRANTIES: THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR ACCURACY. 16 | 17 | 5. NO LIABILITY: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER NVIDIA CORPORATION, NOR THE AUTHORS, CONTRIBUTORS, OR ANY OTHER PARTIES INVOLVED IN THE CREATION, PRODUCTION, OR DELIVERY OF THE SOFTWARE SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | 19 | 6. NO SUPPORT: No technical support, maintenance, updates, or assistance is provided for this Software. Users are solely responsible for their use of the Software and any consequences thereof. 20 | 21 | 7. NO ENDORSEMENT: The inclusion of any third-party components, APIs, or services does not constitute an endorsement of those services or their providers. 22 | 23 | 8. COMPLIANCE: Users are responsible for ensuring their use of the Software complies with all applicable laws, regulations, and terms of service for any third-party services or APIs used by the Software. 24 | 25 | 9. SECURITY: The Software has not been subjected to security audits or testing suitable for production environments. Users assume all risks associated with security vulnerabilities. 26 | 27 | 10. DATA PRIVACY: The Software may process, transmit, or store data in ways that do not comply with data protection regulations. Users are responsible for ensuring compliance with applicable privacy laws. 28 | 29 | ACKNOWLEDGMENT: 30 | 31 | By using, copying, modifying, or distributing the Software, you acknowledge that you have read, understood, and agree to be bound by the terms of this disclaimer. If you do not agree to these terms, you must not use the Software. 32 | 33 | For questions regarding this disclaimer, please contact the authors through the appropriate channels established for this research project. 34 | 35 | Last updated: 07/15/2025. 36 | -------------------------------------------------------------------------------- /frontend/src/components/PromptBar.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 'use client'; 18 | 19 | import { useState, useRef, KeyboardEvent } from 'react'; 20 | import styles from './PromptBar.module.css'; 21 | import PromptBarButton from './PromptBarButton'; 22 | import ResearchTypeSelector from './ResearchTypeSelector'; 23 | import { ApplicationState } from '@/types/ApplicationState'; 24 | 25 | interface PromptBarProps { 26 | onResearch: (query: string, strategyId: string) => void; 27 | onEditStrategy: (strategyId: string) => void; 28 | state: ApplicationState; 29 | isAStrategyBeingEdited: boolean; 30 | } 31 | 32 | export default function PromptBar({ onResearch, onEditStrategy, state, isAStrategyBeingEdited: disableStrategySelector }: PromptBarProps) { 33 | const [query, setQuery] = useState(''); 34 | const [researchStrategyId, setResearchStrategyId] = useState('default'); 35 | const textareaRef = useRef(null); 36 | const isDisabled = state.type !== 'idle' && state.type !== 'stopped' && state.type !== 'error' && state.type !== 'done' || disableStrategySelector; 37 | 38 | const handleKeyDown = (e: KeyboardEvent) => { 39 | if (e.key === 'Enter' && e.shiftKey) { 40 | e.preventDefault(); 41 | handleResearch(); 42 | } 43 | }; 44 | 45 | const handleInput = (e: React.ChangeEvent) => { 46 | setQuery(e.target.value); 47 | // Auto-resize textarea 48 | if (textareaRef.current) { 49 | textareaRef.current.style.height = 'auto'; 50 | textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; 51 | } 52 | }; 53 | 54 | const handleResearch = () => { 55 | if (query.trim() && !isDisabled) { 56 | onResearch(query, researchStrategyId); 57 | } 58 | }; 59 | 60 | return ( 61 |
62 |
63 |