Compare commits

...

No commits in common. "main" and "gh-pages" have entirely different histories.

607 changed files with 3907 additions and 135594 deletions

View file

@ -1,49 +0,0 @@
# Environment files
.env
.env.local
.env.development
.env.production
# Auth files
.drive.json
*.json
# Dependencies
node_modules/
*/node_modules/
**/node_modules/
# Python cache
__pycache__/
*/__pycache__/
**/__pycache__/
*.pyc
*.pyo
*.pyd
.Python
# Build outputs
build/
dist/
.next/
out/
# Development files
.git/
.gitignore
README.md
*.md
.vscode/
.idea/
# Logs
*.log
logs/
# OS files
.DS_Store
Thumbs.db
# Temporary files
tmp/
temp/

View file

@ -1,88 +0,0 @@
# Ingestion Configuration
# Set to true to disable Langflow ingestion and use traditional OpenRAG processor
# If unset or false, Langflow pipeline will be used (default: upload -> ingest -> delete)
DISABLE_INGEST_WITH_LANGFLOW=false
# Langflow HTTP timeout configuration (in seconds)
# For large documents (300+ pages), ingestion can take 30+ minutes
# Increase these values if you experience timeouts with very large PDFs
# Default: 2400 seconds (40 minutes) total timeout, 30 seconds connection timeout
# LANGFLOW_TIMEOUT=2400
# LANGFLOW_CONNECT_TIMEOUT=30
# make one like so https://docs.langflow.org/api-keys-and-authentication#langflow-secret-key
LANGFLOW_SECRET_KEY=
# flow ids for chat and ingestion flows
LANGFLOW_CHAT_FLOW_ID=1098eea1-6649-4e1d-aed1-b77249fb8dd0
LANGFLOW_INGEST_FLOW_ID=5488df7c-b93f-4f87-a446-b67028bc0813
LANGFLOW_URL_INGEST_FLOW_ID=72c3d17c-2dac-4a73-b48a-6518473d7830
# Ingest flow using docling
# LANGFLOW_INGEST_FLOW_ID=1402618b-e6d1-4ff2-9a11-d6ce71186915
NUDGES_FLOW_ID=ebc01d31-1976-46ce-a385-b0240327226c
# Set a strong admin password for OpenSearch; a bcrypt hash is generated at
# container startup from this value. Do not commit real secrets.
# must match the hashed password in secureconfig, must change for secure deployment!!!
# NOTE: if you set this by hand, it must be a complex password:
# The password must contain at least 8 characters, and must contain at least one uppercase letter, one lowercase letter, one digit, and one special character.
OPENSEARCH_PASSWORD=
# Path to persist OpenSearch data (indices, documents, cluster state)
# Default: ./opensearch-data
OPENSEARCH_DATA_PATH=./opensearch-data
# make here https://console.cloud.google.com/apis/credentials
GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
# Azure app registration credentials for SharePoint/OneDrive
MICROSOFT_GRAPH_OAUTH_CLIENT_ID=
MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET=
# AWS Access Key ID and Secret Access Key with access to your S3 instance
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
# OPTIONAL: dns routable from google (etc.) to handle continous ingest (something like ngrok works). This enables continous ingestion
WEBHOOK_BASE_URL=
# Model Provider API Keys
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
OLLAMA_ENDPOINT=
WATSONX_API_KEY=
WATSONX_ENDPOINT=
WATSONX_PROJECT_ID=
# LLM Provider configuration. Providers can be "anthropic", "watsonx", "ibm" or "ollama".
LLM_PROVIDER=
LLM_MODEL=
# Embedding provider configuration. Providers can be "watsonx", "ibm" or "ollama".
EMBEDDING_PROVIDER=
EMBEDDING_MODEL=
# OPTIONAL url for openrag link to langflow in the UI
LANGFLOW_PUBLIC_URL=
# OPTIONAL: Override the full docling-serve URL (e.g., for remote instances)
# If not set, auto-detects host and uses port 5001
# DOCLING_SERVE_URL=http://my-docling-server:5001
# OPTIONAL: Override host for docling service (for special networking setups)
# HOST_DOCKER_INTERNAL=host.containers.internal
# Langflow auth
LANGFLOW_AUTO_LOGIN=False
LANGFLOW_SUPERUSER=
LANGFLOW_SUPERUSER_PASSWORD=
LANGFLOW_NEW_USER_IS_ACTIVE=False
LANGFLOW_ENABLE_SUPERUSER_CLI=False
# Langfuse tracing (optional)
# Get keys from https://cloud.langfuse.com or your self-hosted instance
LANGFUSE_SECRET_KEY=
LANGFUSE_PUBLIC_KEY=
# Leave empty for Langfuse Cloud, or set for self-hosted (e.g., http://localhost:3002)
LANGFUSE_HOST=

View file

@ -1,155 +0,0 @@
name: Bug Report
description: Report a bug or unexpected behavior in OpenRAG
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report a bug! Please fill out the form below to help us understand and fix the issue.
- type: input
id: openrag-version
attributes:
label: OpenRAG Version
description: What version of OpenRAG are you using? Run `openrag --version` or check your package version.
placeholder: "e.g., 0.1.0"
validations:
required: true
- type: dropdown
id: deployment-method
attributes:
label: Deployment Method
description: How are you running OpenRAG?
options:
- uvx (uvx openrag)
- uv add (installed in project)
- Docker
- Podman
- Local development (make dev)
- Other
validations:
required: true
- type: input
id: os
attributes:
label: Operating System
description: What operating system are you using?
placeholder: "e.g., macOS 14.0, Ubuntu 22.04, Windows 11"
validations:
required: true
- type: input
id: python-version
attributes:
label: Python Version
description: What Python version are you using? Run `python --version` to check.
placeholder: "e.g., 3.13.0"
validations:
required: false
- type: dropdown
id: affected-area
attributes:
label: Affected Area
description: Which area(s) of OpenRAG does this bug affect? Select all that apply.
multiple: true
options:
- Ingestion (document processing, upload, Docling)
- Retrieval (search, OpenSearch, hybrid search)
- Chat (chat interface, conversations, AI responses)
- Knowledge Filters (partitions, document filtering)
- Settings (configuration, model providers)
- TUI (Terminal User Interface)
- Connectors (Google Drive, OneDrive, SharePoint)
- Frontend (Next.js UI, components)
- Backend/API (Python/Starlette)
- Infrastructure (Docker, OpenSearch, Langflow)
- SDK (Python or TypeScript SDK)
- Onboarding (setup wizard, initial configuration)
- Authentication (OIDC, API keys)
- Other
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Bug Description
description: A clear and concise description of what the bug is.
placeholder: Describe the bug...
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
placeholder: What should have happened?
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual Behavior
description: A clear and concise description of what actually happened.
placeholder: What actually happened?
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant Logs
description: |
Please copy and paste any relevant log output.
You can get logs using `make logs` for Docker deployments or check the terminal output.
This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: false
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context about the problem here (e.g., browser version, specific document types, model provider being used).
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please confirm the following before submitting.
options:
- label: I have searched existing issues to ensure this bug hasn't been reported before.
required: true
- label: I have provided all the requested information.
required: true

View file

@ -1,15 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: OpenRAG Documentation
url: https://docs.openr.ag/
about: Learn more about OpenRAG's features, installation, and configuration.
- name: Troubleshooting Guide
url: https://docs.openr.ag/support/troubleshoot
about: Check the troubleshooting guide for common issues and solutions.
- name: GitHub Discussions
url: https://github.com/langflow-ai/openrag/discussions
about: Ask questions and discuss ideas with the community.
- name: Contributing Guide
url: https://github.com/langflow-ai/openrag/blob/main/CONTRIBUTING.md
about: Learn how to contribute to OpenRAG development.

View file

@ -1,106 +0,0 @@
name: Documentation Issue
description: Report an issue with documentation or request new documentation
title: "[Docs]: "
labels: ["documentation"]
body:
- type: markdown
attributes:
value: |
Thanks for helping improve OpenRAG's documentation! Please provide details about the issue or your request.
- type: dropdown
id: issue-type
attributes:
label: Issue Type
description: What type of documentation issue is this?
options:
- Incorrect information
- Missing documentation
- Outdated content
- Unclear or confusing
- Typo or grammatical error
- Broken links
- Request for new documentation
- Other
validations:
required: true
- type: dropdown
id: doc-area
attributes:
label: Documentation Area
description: Which area of documentation does this relate to?
multiple: true
options:
- Getting Started / Quickstart
- Installation (uvx, Docker, Podman)
- Configuration / Settings
- Ingestion & Document Processing
- Search & Retrieval
- Chat Interface
- Knowledge Filters
- Connectors (Google Drive, OneDrive, SharePoint)
- TUI (Terminal User Interface)
- API Reference
- SDK Documentation (Python/TypeScript)
- Troubleshooting
- Contributing Guide
- Other
validations:
required: true
- type: input
id: doc-url
attributes:
label: Documentation URL
description: If applicable, provide a link to the specific documentation page.
placeholder: "https://docs.openr.ag/..."
validations:
required: false
- type: textarea
id: current-content
attributes:
label: Current Content
description: If reporting an issue, what does the documentation currently say?
placeholder: Quote or describe the current documentation content.
validations:
required: false
- type: textarea
id: issue-description
attributes:
label: Issue Description
description: Describe the problem or what documentation you'd like to see added.
placeholder: |
For issues: Explain what's wrong or confusing about the current documentation.
For requests: Describe what topic you'd like documented and why it would be helpful.
validations:
required: true
- type: textarea
id: suggested-content
attributes:
label: Suggested Content
description: If you have suggestions for how to fix or improve the documentation, please share them.
placeholder: Provide suggested text, corrections, or an outline for new documentation.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context, screenshots, or examples here.
validations:
required: false
- type: checkboxes
id: contribution
attributes:
label: Contribution
description: Would you be interested in contributing to fix this documentation issue?
options:
- label: I would be willing to submit a pull request to fix this issue.
required: false

View file

@ -1,113 +0,0 @@
name: Feature Request
description: Suggest a new feature or enhancement for OpenRAG
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a feature! Please provide as much detail as possible to help us understand your request.
- type: dropdown
id: feature-area
attributes:
label: Feature Area
description: Which area(s) of OpenRAG does this feature relate to?
multiple: true
options:
- Ingestion (document processing, upload, Docling)
- Retrieval (search, OpenSearch, hybrid search)
- Chat (chat interface, conversations, AI responses)
- Knowledge Filters (partitions, document filtering)
- Settings (configuration, model providers)
- TUI (Terminal User Interface)
- Connectors (Google Drive, OneDrive, SharePoint)
- Frontend (Next.js UI, components)
- Backend/API (Python/Starlette)
- Infrastructure (Docker, OpenSearch, Langflow)
- SDK (Python or TypeScript SDK)
- Onboarding (setup wizard, initial configuration)
- Authentication (OIDC, API keys)
- New Area
validations:
required: true
- type: textarea
id: problem-description
attributes:
label: Problem Description
description: Is your feature request related to a problem? Please describe.
placeholder: A clear and concise description of what the problem is. E.g., "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to see implemented.
placeholder: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: Describe your use case and how this feature would benefit you or others.
placeholder: |
As a [type of user], I want [goal] so that [benefit].
Example: As a developer, I want to filter documents by custom metadata so that I can organize my knowledge base more effectively.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Describe any alternative solutions or features you've considered.
placeholder: What other approaches have you thought about? Why wouldn't they work as well?
validations:
required: false
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature to your workflow?
options:
- Nice to have
- Would improve my workflow
- Critical for my use case
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context, mockups, screenshots, or examples about the feature request here.
validations:
required: false
- type: checkboxes
id: contribution
attributes:
label: Contribution
description: Would you be interested in contributing to this feature?
options:
- label: I would be willing to help implement this feature.
required: false
- label: I can help test this feature once implemented.
required: false
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please confirm the following before submitting.
options:
- label: I have searched existing issues and discussions to ensure this feature hasn't been requested before.
required: true

View file

@ -1,11 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
commit-message:
prefix: "build(deps):"
include: scope

View file

@ -1,253 +0,0 @@
name: Release + Docker Images (multi-arch)
on:
push:
branches:
- main
paths:
- 'pyproject.toml'
workflow_dispatch:
jobs:
check-version:
runs-on: ubuntu-latest
outputs:
skip_release: ${{ steps.version.outputs.skip_release }}
version: ${{ steps.version.outputs.version }}
docker_version: ${{ steps.version.outputs.docker_version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"
# Normalize version per PEP 440 for Docker tags
# e.g., "0.1.53-rc2" -> "0.1.53rc2" to match Python's importlib.metadata
DOCKER_VERSION=$(echo "$VERSION" | sed -E 's/-?(rc|alpha|beta|dev|post)/\1/g')
echo "docker_version=$DOCKER_VERSION" >> $GITHUB_OUTPUT
echo "Docker Version: $DOCKER_VERSION"
# Check if tag already exists
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists, skipping release"
echo "skip_release=true" >> $GITHUB_OUTPUT
exit 0
fi
echo "skip_release=false" >> $GITHUB_OUTPUT
# Check if version is numeric (e.g., 0.1.16) vs prerelease (e.g., 0.1.16-rc1)
if [[ "$VERSION" =~ ^[0-9.-]+$ ]]; then
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "Release type: Production"
else
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "Release type: Prerelease"
fi
build:
needs: check-version
if: needs.check-version.outputs.skip_release != 'true'
strategy:
fail-fast: false
matrix:
include:
# backend
- image: backend
file: ./Dockerfile.backend
tag: langflowai/openrag-backend
platform: linux/amd64
arch: amd64
runs-on: ubuntu-latest-16-cores
- image: backend
file: ./Dockerfile.backend
tag: langflowai/openrag-backend
platform: linux/arm64
arch: arm64
runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
# frontend
- image: frontend
file: ./Dockerfile.frontend
tag: langflowai/openrag-frontend
platform: linux/amd64
arch: amd64
runs-on: ubuntu-latest-16-cores
- image: frontend
file: ./Dockerfile.frontend
tag: langflowai/openrag-frontend
platform: linux/arm64
arch: arm64
runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
# langflow
- image: langflow
file: ./Dockerfile.langflow
tag: langflowai/openrag-langflow
platform: linux/amd64
arch: amd64
runs-on: ubuntu-latest-16-cores
- image: langflow
file: ./Dockerfile.langflow
tag: langflowai/openrag-langflow
platform: linux/arm64
arch: arm64
runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
# opensearch
- image: opensearch
file: ./Dockerfile
tag: langflowai/openrag-opensearch
platform: linux/amd64
arch: amd64
runs-on: ubuntu-latest-16-cores
- image: opensearch
file: ./Dockerfile
tag: langflowai/openrag-opensearch
platform: linux/arm64
arch: arm64
runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push ${{ matrix.image }} (${{ matrix.arch }})
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.file }}
platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ matrix.tag }}:${{ needs.check-version.outputs.docker_version }}-${{ matrix.arch }}
cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.arch }}
manifest:
needs: [build, check-version]
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' && needs.check-version.outputs.skip_release != 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Create and push multi-arch manifests
run: |
VERSION=${{ needs.check-version.outputs.docker_version }}
# Create versioned tags
docker buildx imagetools create -t langflowai/openrag-backend:$VERSION \
langflowai/openrag-backend:$VERSION-amd64 \
langflowai/openrag-backend:$VERSION-arm64
docker buildx imagetools create -t langflowai/openrag-frontend:$VERSION \
langflowai/openrag-frontend:$VERSION-amd64 \
langflowai/openrag-frontend:$VERSION-arm64
docker buildx imagetools create -t langflowai/openrag-langflow:$VERSION \
langflowai/openrag-langflow:$VERSION-amd64 \
langflowai/openrag-langflow:$VERSION-arm64
docker buildx imagetools create -t langflowai/openrag-opensearch:$VERSION \
langflowai/openrag-opensearch:$VERSION-amd64 \
langflowai/openrag-opensearch:$VERSION-arm64
# Only update latest tags if version is numeric
if [[ "$VERSION" =~ ^[0-9.-]+$ ]]; then
echo "Updating latest tags for production release: $VERSION"
docker buildx imagetools create -t langflowai/openrag-backend:latest \
langflowai/openrag-backend:$VERSION-amd64 \
langflowai/openrag-backend:$VERSION-arm64
docker buildx imagetools create -t langflowai/openrag-frontend:latest \
langflowai/openrag-frontend:$VERSION-amd64 \
langflowai/openrag-frontend:$VERSION-arm64
docker buildx imagetools create -t langflowai/openrag-langflow:latest \
langflowai/openrag-langflow:$VERSION-amd64 \
langflowai/openrag-langflow:$VERSION-arm64
docker buildx imagetools create -t langflowai/openrag-opensearch:latest \
langflowai/openrag-opensearch:$VERSION-amd64 \
langflowai/openrag-opensearch:$VERSION-arm64
else
echo "Skipping latest tags - version: $VERSION (not numeric)"
fi
build-python-packages:
needs: [manifest, check-version]
runs-on: ubuntu-latest
if: needs.check-version.outputs.skip_release != 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Build wheel and source distribution
run: |
uv build
- name: List built artifacts
run: |
ls -la dist/
echo "Built artifacts:"
for file in dist/*; do
echo " - $(basename $file) ($(stat -c%s $file | numfmt --to=iec-i)B)"
done
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: python-packages
path: dist/
retention-days: 30
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.check-version.outputs.version }}
name: Release ${{ needs.check-version.outputs.version }}
draft: false
prerelease: ${{ needs.check-version.outputs.is_prerelease }}
generate_release_notes: true
files: |
dist/*.whl
dist/*.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to PyPI
run: |
uv publish
env:
UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }}

View file

@ -1,66 +0,0 @@
name: "CodeQL"
on:
push:
branches: [ 'main' ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ 'main' ]
schedule:
- cron: '17 2 * * 1'
jobs:
analyze:
name: Analyze
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python', 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View file

@ -1,60 +0,0 @@
name: Dependency Audit
on:
schedule:
# Run Monday, Thursday at 9am UTC
- cron: '0 9 * * 1,4'
workflow_dispatch: # Allow manual trigger
jobs:
npm-audit:
name: NPM Audit
runs-on: ubuntu-latest
strategy:
matrix:
directory: ['frontend', 'docs', 'sdks/typescript']
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Run npm audit
working-directory: ${{ matrix.directory }}
run: |
echo "::group::NPM Audit for ${{ matrix.directory }}"
npm audit --audit-level=moderate || echo "::warning::NPM audit found vulnerabilities in ${{ matrix.directory }}"
echo "::endgroup::"
- name: Check for outdated packages
working-directory: ${{ matrix.directory }}
run: |
echo "::group::Outdated packages in ${{ matrix.directory }}"
npm outdated || true
echo "::endgroup::"
python-audit:
name: Python Audit
runs-on: ubuntu-latest
strategy:
matrix:
directory: ['.', 'sdks/python']
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install pip-audit
run: pip install pip-audit
- name: Run pip-audit
working-directory: ${{ matrix.directory }}
run: |
echo "::group::Python Audit for ${{ matrix.directory }}"
pip-audit --desc || echo "::warning::pip-audit found vulnerabilities in ${{ matrix.directory }}"
echo "::endgroup::"

View file

@ -1,266 +0,0 @@
name: Pull Request Docs Draft
on:
pull_request:
branches:
- '**'
paths:
- 'docs/**'
- '.github/workflows/deploy-docs-draft.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-deploy:
runs-on: ubuntu-latest
if: "! github.event.pull_request.head.repo.fork"
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.20.0
cache: npm
cache-dependency-path: ./docs/package-lock.json
- name: Validate Branch Names
run: |
# Check if branch names contain invalid characters. Only alphanumeric, _, -, ., and / are allowed.
validate_branch_name() {
local branch_name="$1"
if [[ ! "$branch_name" =~ ^[a-zA-Z0-9/_\.-]+$ ]]; then
echo "Error: Branch name contains invalid characters. Only alphanumeric, _, -, ., and / are allowed."
exit 1
fi
}
validate_branch_name "${{ github.event.pull_request.head.ref }}"
- name: Extract Branch Names
id: extract_branch
run: |
# Extract and transform branch names
extract_branch() {
local input_branch="$1"
# Check if input_branch starts with "refs/heads/"
if [[ "$input_branch" == refs/heads/* ]]; then
# Remove "refs/heads/" prefix safely using parameter expansion
branch_name="${input_branch#refs/heads/}"
echo "$branch_name"
else
echo "$input_branch"
fi
}
# Transform branch names in form of `refs/heads/main` to `main`
draft_branch=$(extract_branch "${{ github.event.pull_request.head.ref }}")
# Replace / with - in the draft branch name to use as a directory name
draft_directory=$(echo "$draft_branch" | tr / -)
# Safe echo to $GITHUB_OUTPUT
{
echo "draft_branch=$draft_branch"
echo "draft_directory=$draft_directory"
} >> "$GITHUB_OUTPUT"
- name: Set Draft URL
id: draft_url
if: success()
run: |
echo "url=${{ vars.DOCS_DRAFT_BASE_URL }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/index.html" >> $GITHUB_OUTPUT
- name: Install dependencies
run: cd docs && npm install
- name: Build website
if: success()
run: |
set -o pipefail
cd docs
npm run build |& tee $GITHUB_WORKSPACE/build.log
env:
BASE_URL: /langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}
FORCE_COLOR: 0 # Disable color output
# SEGMENT_PUBLIC_WRITE_KEY: ${{ vars.DOCS_DRAFT_SEGMENT_PUBLIC_WRITE_KEY }}
- name: Check Build Result
id: buildLogFail
if: failure()
run: |
MULTILINE_LOG=$(cat $GITHUB_WORKSPACE/build.log)
echo "BUILD_FAILURE<<EOF" >> $GITHUB_ENV
echo $MULTILINE_LOG >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Hide Previous Build Comments
if: ${{ github.event.pull_request.number && (success() || failure()) }}
run: |
set -e
# Get all comments on the PR that match our build comments
comments=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \
--jq '.[] | select(.body | test("Build failure! :x:|Build successful! :white_check_mark:")) | .node_id')
# Minimize each matching comment using GraphQL API
if [[ -n "$comments" ]]; then
echo "Found previous build comments to hide"
while IFS= read -r comment_id; do
if [[ -n "$comment_id" ]]; then
echo "Minimizing comment: $comment_id"
gh api graphql \
--field id="$comment_id" \
--field classifier="OUTDATED" \
--raw-field query='
mutation($id: ID!, $classifier: ReportedContentClassifiers!) {
minimizeComment(input: { subjectId: $id, classifier: $classifier }) {
minimizedComment {
isMinimized
}
}
}' || echo "Failed to minimize comment $comment_id, continuing..."
echo
fi
done <<< "$comments"
else
echo "No previous build comments found to hide"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Assemble Build Success Comment
if: success()
run: |
build_success_comment="Build successful! :white_check_mark:"
build_success_comment+="\nDeploying docs draft."
echo "BUILD_SUCCESS_COMMENT<<EOF" >> $GITHUB_ENV
echo -e "$build_success_comment" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Create Build Success Comment
if: success()
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: "${{ env.BUILD_SUCCESS_COMMENT }}"
reactions: rocket
- name: Create Build Failure Comment
if: failure()
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Build failure! :x:
> ${{ env.BUILD_FAILURE }}
reactions: confused
- name: Find Comment
id: fc
if: success()
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: Build successful!
direction: last
- name: Configure AWS CLI
if: success()
run: |
aws configure set aws_access_key_id ${{ secrets.DOCS_AWS_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.DOCS_AWS_SECRET_ACCESS_KEY }}
aws configure set region us-west-2
- name: Check for New Assets
run: |
set -o pipefail
echo "Checking for new assets." |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 sync docs/build/assets/ s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/assets/ --size-only --dryrun --no-progress" | tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 sync docs/build/assets/ "s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/assets/" --size-only --dryrun --no-progress | tee $GITHUB_WORKSPACE/assets.log
- name: Determine Standard or Full Publish
id: check_full_publish
run: |
# Determine if a full publish is required because of new assets.
if grep -qE '(upload:|delete:)' "$GITHUB_WORKSPACE/assets.log"; then
echo "New assets. Perform full publish: true" | tee -a "$GITHUB_WORKSPACE/deploy.log"
echo "perform_full_publish=true" >> "$GITHUB_OUTPUT"
else
echo "No new assets. Perform full publish: false" | tee -a "$GITHUB_WORKSPACE/deploy.log"
echo "perform_full_publish=false" >> "$GITHUB_OUTPUT"
fi
- name: Deploy to S3
if: success()
run: |
set -o pipefail
cd docs
mkdir langflow-drafts
mv build langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}
cd langflow-drafts
# Records the repository that originally triggered the build so we can post back
# comments upon clean up of a stale draft if it still has an open pull request.
echo "${{ github.event.repository.full_name }}" > ${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository
s3_params=(
# Hide upload progress for a cleaner sync log
--no-progress
--delete
--exclude "*"
--include "${{ steps.extract_branch.outputs.draft_directory }}/*"
)
if [[ "${{ steps.check_full_publish.outputs.perform_full_publish }}" == "false" ]]; then
s3_params+=(--size-only)
fi
echo "Deploying draft to S3." |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 sync . s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts ${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 sync . "s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts" "${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
# Update .github_source_repository file metadata to mark last modified time of the draft.
# This will allow us to later determine if a draft is stale and needs to be cleaned up.
echo "Marking last modified time of the draft." |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 cp --metadata '{\"touched\": \"now\"}' \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository" \
|& tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 cp --metadata '{ "touched": "now" }' \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
|& tee -a $GITHUB_WORKSPACE/deploy.log
- name: Invalidate CloudFront Cache
if: success()
run: |
invalidation_batch="{ \"Paths\": { \"Quantity\": 1, \"Items\": [\"/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/*\"] }, \"CallerReference\": \"langflow-docs-draft-files-$(date +%s)\" }"
echo $invalidation_batch | jq . |& tee -a "$GITHUB_WORKSPACE/deploy.log"
echo "Creating invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
invalidation_id=$(aws cloudfront create-invalidation --distribution-id "${{ vars.DOCS_DRAFT_CLOUD_FRONT_DISTRIBUTION_ID }}" --invalidation-batch "$invalidation_batch" --query 'Invalidation.Id' --output text |& tee -a "$GITHUB_WORKSPACE/deploy.log")
echo "Awaiting invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
aws cloudfront wait invalidation-completed --distribution-id "${{ vars.DOCS_DRAFT_CLOUD_FRONT_DISTRIBUTION_ID }}" --id "$invalidation_id" |& tee -a "$GITHUB_WORKSPACE/deploy.log"
echo "Invalidation complete." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
- name: Update Comment
if: ${{ steps.fc.outputs.comment-id != '' }}
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
body: |
Deploy successful! [View draft](${{ steps.draft_url.outputs.url }})
reactions: hooray
- name: Upload Deploy Log
uses: actions/upload-artifact@v4
if: always()
with:
name: deploy.log
path: ${{ github.workspace }}/deploy.log

View file

@ -1,42 +0,0 @@
name: Deploy to GitHub Pages
on:
push:
branches:
- main
paths:
- 'docs/**'
workflow_dispatch:
jobs:
deploy:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.20.0
cache: npm
cache-dependency-path: ./docs/package-lock.json
- name: Install dependencies
run: cd docs && npm install
- name: Build website
run: cd docs && npm run build
# env:
# SEGMENT_PUBLIC_WRITE_KEY: ${{ vars.DOCS_PROD_SEGMENT_PUBLIC_WRITE_KEY }}
# Popular action to deploy to GitHub Pages:
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Build output to publish to the `gh-pages` branch:
publish_dir: ./docs/build
# The following lines assign commit authorship to the official
# GH-Actions bot for deploys to `gh-pages` branch:
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
# The GH actions bot is used by default if you didn't specify the two fields.
# You can swap them out with your own user credentials.

View file

@ -1,59 +0,0 @@
name: Publish Python SDK
on:
push:
branches:
- main
paths:
- 'sdks/python/pyproject.toml'
workflow_dispatch:
jobs:
publish:
name: Publish to PyPI
runs-on: ubuntu-latest
defaults:
run:
working-directory: sdks/python
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep -Po '(?<=^version = ")[^"]*' pyproject.toml)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Check if version already published
id: check
run: |
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://pypi.org/pypi/openrag-sdk/${{ steps.version.outputs.version }}/json)
if [ "$HTTP_STATUS" = "200" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Build package
if: steps.check.outputs.exists == 'false'
run: uv build
- name: Publish to PyPI
if: steps.check.outputs.exists == 'false'
run: uv publish
env:
UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }}
- name: Skip publish (version exists)
if: steps.check.outputs.exists == 'true'
run: echo "Version ${{ steps.version.outputs.version }} already exists on PyPI, skipping publish"

View file

@ -1,64 +0,0 @@
name: Publish TypeScript SDK
on:
push:
branches:
- main
paths:
- 'sdks/typescript/package.json'
workflow_dispatch:
jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
defaults:
run:
working-directory: sdks/typescript
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Update npm to latest
run: npm install -g npm@latest
- name: Extract version from package.json
id: version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Check if version already published
id: check
run: |
if npm view openrag-sdk@${{ steps.version.outputs.version }} version 2>/dev/null; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Install dependencies
if: steps.check.outputs.exists == 'false'
run: npm ci
- name: Build
if: steps.check.outputs.exists == 'false'
run: npm run build
- name: Publish to npm
if: steps.check.outputs.exists == 'false'
run: npm publish --access public --provenance
- name: Skip publish (version exists)
if: steps.check.outputs.exists == 'true'
run: echo "Version ${{ steps.version.outputs.version }} already exists on npm, skipping publish"

View file

@ -1,102 +0,0 @@
name: Integration Tests
on:
pull_request:
paths:
- 'src/**.py'
- 'tests/**.py'
- 'pyproject.toml'
- 'uv.lock'
- 'sdks/**'
- '.github/workflows/test-integration.yml'
workflow_dispatch:
inputs:
use_local_images:
description: 'Build images locally instead of pulling from DockerHub'
required: false
type: boolean
default: true
jobs:
tests:
runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb]
env:
# Prefer repository/environment variable first, then secret, then a sane fallback
OPENSEARCH_PASSWORD: ${{ vars.OPENSEARCH_PASSWORD || secrets.OPENSEARCH_PASSWORD || 'OpenRag#2025!' }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LANGFLOW_AUTO_LOGIN: "True"
LANGFLOW_NEW_USER_IS_ACTIVE: "True"
LANGFLOW_ENABLE_SUPERUSER_CLI: "True"
LANGFLOW_CHAT_FLOW_ID: ${{ vars.LANGFLOW_CHAT_FLOW_ID || '1098eea1-6649-4e1d-aed1-b77249fb8dd0' }}
LANGFLOW_INGEST_FLOW_ID: ${{ vars.LANGFLOW_INGEST_FLOW_ID || '5488df7c-b93f-4f87-a446-b67028bc0813' }}
NUDGES_FLOW_ID: ${{ vars.NUDGES_FLOW_ID || 'ebc01d31-1976-46ce-a385-b0240327226c' }}
steps:
- run: df -h
- name: Cleanup Docker cache
run: |
docker system prune -af || true
docker builder prune -af || true
docker-compose -f docker-compose.yml down -v --remove-orphans || true
- name: Cleanup root-owned files (OpenSearch data, config)
run: |
for i in 1 2 3; do
docker run --rm -v $(pwd):/work alpine sh -c "rm -rf /work/opensearch-data /work/config" && break
echo "Attempt $i failed, retrying in 5s..."
sleep 5
done || true
- run: df -h
- name: Checkout
uses: actions/checkout@v4
- name: Verify workspace
run: |
echo "Current directory: $(pwd)"
echo "Workspace: ${GITHUB_WORKSPACE}"
ls -la
- name: Set up UV
uses: astral-sh/setup-uv@v3
with:
version: latest
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Python version
run: uv python install 3.13
- name: Install dependencies
run: uv sync
- name: Run integration tests
env:
OPENSEARCH_HOST: localhost
OPENSEARCH_PORT: 9200
OPENSEARCH_USERNAME: admin
OPENSEARCH_PASSWORD: ${{ env.OPENSEARCH_PASSWORD }}
LOG_LEVEL: DEBUG
# Force no-auth mode so tests bypass OAuth
GOOGLE_OAUTH_CLIENT_ID: ""
GOOGLE_OAUTH_CLIENT_SECRET: ""
# Disable startup ingest noise unless a test enables it
DISABLE_STARTUP_INGEST: "true"
run: |
# For PRs, always build locally since we're testing new code
# For workflow_dispatch, use the input (defaults to true)
USE_LOCAL="${{ inputs.use_local_images }}"
if [ "${{ github.event_name }}" == "pull_request" ] || [ "$USE_LOCAL" != "false" ]; then
echo "Running tests with locally built images..."
make test-ci-local
else
echo "Running tests with DockerHub images..."
make test-ci
fi
echo "Keys directory after tests:"
ls -la keys/ || echo "No keys directory"

View file

@ -1,52 +0,0 @@
name: Update uv.lock on version bump
on:
push:
branches:
- main
paths:
- 'pyproject.toml'
workflow_dispatch:
jobs:
update-lock:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Update uv.lock
run: uv sync
- name: Check for changes
id: changes
run: |
if git diff --quiet uv.lock; then
echo "changed=false" >> $GITHUB_OUTPUT
echo "No changes to uv.lock"
else
echo "changed=true" >> $GITHUB_OUTPUT
echo "uv.lock has been updated"
fi
- name: Commit and push uv.lock
if: steps.changes.outputs.changed == 'true'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add uv.lock
git commit -m "chore: update uv.lock after version bump [skip ci]"
git push

36
.gitignore vendored
View file

@ -1,36 +0,0 @@
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv
.env
# RSA keys for JWT signing
*.pem
.idea/
1001*.pdf
*.json
!**/package.json
!**/package-lock.json
!**/tsconfig.json
!flows/*.json
!src/tui/_assets/flows/*.json
!src/tui/_assets/flows/components/*.json
!frontend/*.json
.DS_Store
config/
.docling.pid
# OpenSearch data directory
opensearch-data/
node_modules

View file

@ -1,7 +0,0 @@
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
args: ["--baseline", ".secrets.baseline", "--exclude-lines", "code_hash"]

View file

@ -1 +0,0 @@
3.13

View file

@ -1,180 +0,0 @@
{
"version": "1.5.0",
"plugins_used": [
{
"name": "ArtifactoryDetector"
},
{
"name": "AWSKeyDetector"
},
{
"name": "AzureStorageKeyDetector"
},
{
"name": "Base64HighEntropyString",
"limit": 4.5
},
{
"name": "BasicAuthDetector"
},
{
"name": "CloudantDetector"
},
{
"name": "DiscordBotTokenDetector"
},
{
"name": "GitHubTokenDetector"
},
{
"name": "GitLabTokenDetector"
},
{
"name": "HexHighEntropyString",
"limit": 3.0
},
{
"name": "IbmCloudIamDetector"
},
{
"name": "IbmCosHmacDetector"
},
{
"name": "IPPublicDetector"
},
{
"name": "JwtTokenDetector"
},
{
"name": "KeywordDetector",
"keyword_exclude": ""
},
{
"name": "MailchimpDetector"
},
{
"name": "NpmDetector"
},
{
"name": "OpenAIDetector"
},
{
"name": "PrivateKeyDetector"
},
{
"name": "PypiTokenDetector"
},
{
"name": "SendGridDetector"
},
{
"name": "SlackDetector"
},
{
"name": "SoftlayerDetector"
},
{
"name": "SquareOAuthDetector"
},
{
"name": "StripeDetector"
},
{
"name": "TelegramBotTokenDetector"
},
{
"name": "TwilioKeyDetector"
}
],
"filters_used": [
{
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
},
{
"path": "detect_secrets.filters.common.is_baseline_file",
"filename": ".secrets.baseline"
},
{
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
"min_level": 2
},
{
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
},
{
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
},
{
"path": "detect_secrets.filters.heuristic.is_lock_file"
},
{
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
},
{
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
},
{
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
},
{
"path": "detect_secrets.filters.heuristic.is_sequential_string"
},
{
"path": "detect_secrets.filters.heuristic.is_swagger_file"
},
{
"path": "detect_secrets.filters.heuristic.is_templated_secret"
},
{
"path": "detect_secrets.filters.regex.should_exclude_file",
"pattern": [
"flows/.*\\.json$"
]
},
{
"path": "detect_secrets.filters.regex.should_exclude_line",
"pattern": [
"code_hash"
]
}
],
"results": {
"docs/docs/_partial-integrate-chat.mdx": [
{
"type": "Secret Keyword",
"filename": "docs/docs/_partial-integrate-chat.mdx",
"hashed_secret": "e42fd8b9ad15d8fa5f4718cad7cf19b522807996",
"is_verified": false,
"line_number": 30
}
],
"src/main.py": [
{
"type": "Base64 High Entropy String",
"filename": "src/main.py",
"hashed_secret": "131a83e9ef8660d7dd0771da7ce5954d9ea801ee",
"is_verified": false,
"line_number": 404
}
],
"src/models/processors.py": [
{
"type": "Base64 High Entropy String",
"filename": "src/models/processors.py",
"hashed_secret": "131a83e9ef8660d7dd0771da7ce5954d9ea801ee",
"is_verified": false,
"line_number": 763
}
],
"src/services/langflow_file_service.py": [
{
"type": "Base64 High Entropy String",
"filename": "src/services/langflow_file_service.py",
"hashed_secret": "131a83e9ef8660d7dd0771da7ce5954d9ea801ee",
"is_verified": false,
"line_number": 97
}
]
},
"generated_at": "2025-12-09T20:33:13Z"
}

25
404.html Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,317 +0,0 @@
# Contributing to OpenRAG
Thank you for your interest in contributing to OpenRAG! This guide will help you set up your development environment and understand the development workflow.
## 🛠️ Development Setup
### Prerequisites
- Docker or Podman with Compose installed
- Make (for development commands)
- Python 3.13+ with uv package manager
- Node.js 18+ and npm
### Set up OpenRAG for development
1. Set up your development environment.
```bash
# Clone and setup environment
git clone https://github.com/langflow-ai/openrag.git
cd openrag
make setup # Creates .env and installs dependencies
```
2. Configure the `.env` file with your API keys and credentials.
```bash
# Required
OPENAI_API_KEY=your_openai_api_key
OPENSEARCH_PASSWORD=your_secure_password
LANGFLOW_SUPERUSER=admin
LANGFLOW_SUPERUSER_PASSWORD=your_secure_password
LANGFLOW_CHAT_FLOW_ID=your_chat_flow_id
LANGFLOW_INGEST_FLOW_ID=your_ingest_flow_id
NUDGES_FLOW_ID=your_nudges_flow_id
```
For extended configuration, including ingestion and optional variables, see [docs/reference/configuration.mdx](docs/docs/reference/configuration.mdx).
3. Start OpenRAG.
```bash
# Full stack with GPU support
make dev
# Or CPU only
make dev-cpu
```
Access the services:
- **Frontend**: http://localhost:3000
- **Backend API**: http://localhost:8000
- **Langflow**: http://localhost:7860
- **OpenSearch**: http://localhost:9200
- **OpenSearch Dashboards**: http://localhost:5601
## 🔧 Development Commands
All development tasks are managed through the Makefile. Run `make help` to see all available commands.
### Environment Management
```bash
# Setup development environment
make setup # Initial setup: creates .env, installs dependencies
# Start development environments
make dev # Full stack with GPU support
make dev-cpu # Full stack with CPU only
make infra # Infrastructure only (for local development)
# Container management
make stop # Stop all containers
make restart # Restart all containers
make clean # Stop and remove containers/volumes
make status # Show container status
make health # Check service health
```
### Local Development Workflow
For faster development iteration, run infrastructure in Docker and backend/frontend locally:
```bash
# Terminal 1: Start infrastructure
make infra
# Terminal 2: Run backend locally
make backend
# Terminal 3: Run frontend locally
make frontend
```
This setup provides:
- Faster code reloading
- Direct access to logs and debugging
- Easier testing and iteration
### Dependency Management
```bash
make install # Install all dependencies
make install-be # Install backend dependencies (uv)
make install-fe # Install frontend dependencies (npm)
```
### Building and Testing
```bash
# Build Docker images
make build # Build all images
make build-be # Build backend image only
make build-fe # Build frontend image only
# Testing and quality
make test # Run backend tests
make lint # Run linting checks
```
### Debugging
```bash
# View logs
make logs # All container logs
make logs-be # Backend logs only
make logs-fe # Frontend logs only
make logs-lf # Langflow logs only
make logs-os # OpenSearch logs only
# Shell access
make shell-be # Shell into backend container
make shell-lf # Shell into langflow container
make shell-os # Shell into opensearch container
```
### Database Operations
```bash
# Reset OpenSearch indices
make db-reset # Delete and recreate indices
```
### Flow Management
```bash
# Upload flow to Langflow
make flow-upload FLOW_FILE=path/to/flow.json
```
## 🏗️ Architecture Overview
### Backend (Python/Starlette)
- **API Layer**: RESTful endpoints in `src/api/`
- **Services**: Business logic in `src/services/`
- **Models**: Data models and processors in `src/models/`
- **Connectors**: External service integrations in `src/connectors/`
- **Configuration**: Settings management in `src/config/`
### Frontend (Next.js/React)
- **Pages**: Next.js app router in `frontend/src/app/`
- **Components**: Reusable UI components in `frontend/src/components/`
- **Contexts**: State management in `frontend/src/contexts/`
- **Hooks**: Custom React hooks in `frontend/hooks/`
### Infrastructure
- **OpenSearch**: Vector database and search engine
- **Langflow**: Visual flow builder for LLM workflows
- **Docker**: Containerization and orchestration
## 🧪 Testing
### Backend Tests
```bash
make test # Run all backend tests
uv run pytest # Direct pytest execution
uv run pytest -v # Verbose test output
```
### Frontend Tests
```bash
cd frontend && npm test # Run frontend tests
cd frontend && npm run lint # Frontend linting
```
## 📝 Code Style
### Backend
- Follow PEP 8 style guidelines
- Use type hints where appropriate
- Document functions and classes with docstrings
- Use structured logging with `structlog`
### Frontend
- Follow React/Next.js best practices
- Use TypeScript for type safety
- Follow the established component structure
- Use Tailwind CSS for styling
## 🔍 Debugging Tips
### Backend Debugging
```bash
# Enable debug logging
export LOG_LEVEL=DEBUG
# Run backend locally for debugging
make infra && make backend
# Check OpenSearch indices
curl -X GET "http://localhost:9200/_cat/indices?v" \
-u admin:$(grep OPENSEARCH_PASSWORD .env | cut -d= -f2)
```
### Frontend Debugging
```bash
# Run with detailed logs
cd frontend && npm run dev
# Build and analyze bundle
cd frontend && npm run build
```
### Container Debugging
```bash
# Check container status
make status
# View real-time logs
make logs
# Shell into containers
make shell-be # Backend container
make shell-lf # Langflow container
```
## 🚀 Deployment Testing
### Local Testing
```bash
# Test full stack deployment
make clean && make dev
# Test CPU-only deployment
make clean && make dev-cpu
```
### Performance Testing
```bash
# Monitor resource usage
docker stats
# Check service health
make health
```
## 📚 Development Resources
### Key Files
- `src/main.py` - Backend application entry point
- `src/config/settings.py` - Configuration management
- `frontend/src/app/layout.tsx` - Frontend root layout
- `docker-compose.yml` - Container orchestration
- `Makefile` - Development commands
### Documentation
- API documentation: Available at `http://localhost:8000/docs` when backend is running
- Component Storybook: (if implemented) at `http://localhost:6006`
- OpenSearch: `http://localhost:5601` (Dashboards)
- Langflow: `http://localhost:7860`
## 🐛 Common Issues
### Port Conflicts
Ensure these ports are available:
- 3000 (Frontend)
- 7860 (Langflow)
- 8000 (Backend)
- 9200 (OpenSearch)
- 5601 (OpenSearch Dashboards)
### Memory Issues
- Use `make dev-cpu` for CPU-only mode
- Increase Docker memory allocation
- Podman on macOS: increase the VM memory if needed
```bash
podman machine stop
podman machine rm
podman machine init --memory 8192 # 8 GB example
podman machine start
```
### Environment Issues
```bash
# Reset environment
make clean
cp .env.example .env # Reconfigure as needed
make setup
```
## 📋 Pull Request Guidelines
1. **Fork and Branch**: Create a feature branch from `main`
2. **Test**: Ensure all tests pass with `make test` and `make lint`
3. **Documentation**: Update relevant documentation
4. **Commit Messages**: Use clear, descriptive commit messages
5. **PR Description**: Explain changes and include testing instructions
## 🤝 Getting Help
- Check existing issues and discussions
- Use `make status` and `make health` for debugging
- Review logs with `make logs`
- Join our community discussions
Thank you for contributing to OpenRAG! 🚀

View file

@ -1,138 +0,0 @@
########################################
# Stage 1: Upstream OpenSearch with plugins
########################################
FROM opensearchproject/opensearch:3.2.0 AS upstream_opensearch
# Remove plugins
RUN opensearch-plugin remove opensearch-neural-search || true && \
opensearch-plugin remove opensearch-knn || true && \
# removing this one due to Netty CVE-2025-58056, can bring it back in the future
opensearch-plugin remove opensearch-security-analytics || true
# Prepare jvector plugin artifacts
RUN mkdir -p /tmp/opensearch-jvector-plugin && \
curl -L -s https://github.com/opensearch-project/opensearch-jvector/releases/download/3.2.0.0/artifacts.tar.gz \
| tar zxvf - -C /tmp/opensearch-jvector-plugin
# Prepare neural-search plugin
RUN mkdir -p /tmp/opensearch-neural-search && \
curl -L -s https://storage.googleapis.com/opensearch-jvector/opensearch-neural-search-3.2.0.0-20251029200300.zip \
> /tmp/opensearch-neural-search/plugin.zip
# Install additional plugins
RUN opensearch-plugin install --batch file:///tmp/opensearch-jvector-plugin/repository/org/opensearch/plugin/opensearch-jvector-plugin/3.2.0.0/opensearch-jvector-plugin-3.2.0.0.zip && \
opensearch-plugin install --batch file:///tmp/opensearch-neural-search/plugin.zip && \
opensearch-plugin install --batch repository-gcs && \
opensearch-plugin install --batch repository-azure && \
# opensearch-plugin install --batch repository-s3 && \
opensearch-plugin install --batch https://github.com/opensearch-project/opensearch-prometheus-exporter/releases/download/3.2.0.0/prometheus-exporter-3.2.0.0.zip
# Apply Netty patch
COPY patch-netty.sh /tmp/
RUN whoami && bash /tmp/patch-netty.sh
# Set permissions for OpenShift compatibility before copying
RUN chmod -R g=u /usr/share/opensearch
########################################
# Stage 2: UBI9 runtime image
########################################
FROM registry.access.redhat.com/ubi9/ubi:latest
USER root
# Update packages and install required tools
# TODO bring back iostat somehow? sysstat isn't in ubi
# TODO bring back 'perf' package, but what did we need it for?
RUN dnf update -y && \
dnf install -y --allowerasing \
less procps-ng findutils sudo curl tar gzip shadow-utils which && \
dnf clean all
# Create opensearch user and group
ARG UID=1000
ARG GID=1000
ARG OPENSEARCH_HOME=/usr/share/opensearch
WORKDIR $OPENSEARCH_HOME
RUN groupadd -g $GID opensearch && \
adduser -u $UID -g $GID -d $OPENSEARCH_HOME opensearch
# Grant the opensearch user sudo privileges (passwordless sudo)
RUN usermod -aG wheel opensearch && \
echo "opensearch ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Copy OpenSearch from the upstream stage
COPY --from=upstream_opensearch --chown=$UID:0 $OPENSEARCH_HOME $OPENSEARCH_HOME
ARG OPENSEARCH_VERSION=3.2.0
########################################
# Async-profiler (multi-arch like your original)
########################################
ARG TARGETARCH
RUN if [ "$TARGETARCH" = "amd64" ]; then \
export ASYNC_PROFILER_URL=https://github.com/async-profiler/async-profiler/releases/download/v4.0/async-profiler-4.0-linux-x64.tar.gz; \
elif [ "$TARGETARCH" = "arm64" ]; then \
export ASYNC_PROFILER_URL=https://github.com/async-profiler/async-profiler/releases/download/v4.0/async-profiler-4.0-linux-arm64.tar.gz; \
else \
echo "Unsupported architecture: $TARGETARCH" && exit 1; \
fi && \
mkdir /opt/async-profiler && \
curl -s -L $ASYNC_PROFILER_URL | tar zxvf - --strip-components=1 -C /opt/async-profiler && \
chown -R opensearch:opensearch /opt/async-profiler
# Create profiling script (as in your original Dockerfile)
RUN echo "#!/bin/bash" > /usr/share/opensearch/profile.sh && \
echo "export PATH=\$PATH:/opt/async-profiler/bin" >> /usr/share/opensearch/profile.sh && \
echo "echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid >/dev/null" >> /usr/share/opensearch/profile.sh && \
echo "echo 0 | sudo tee /proc/sys/kernel/kptr_restrict >/dev/null" >> /usr/share/opensearch/profile.sh && \
echo "asprof \$@" >> /usr/share/opensearch/profile.sh && \
chmod 777 /usr/share/opensearch/profile.sh
########################################
# Security config (OIDC/DLS) and setup script
########################################
# Copy OIDC and DLS security configuration (as root, like before)
COPY securityconfig/ /usr/share/opensearch/securityconfig/
RUN chown -R opensearch:opensearch /usr/share/opensearch/securityconfig/
# Create a script to apply security configuration after OpenSearch starts
RUN echo '#!/bin/bash' > /usr/share/opensearch/setup-security.sh && \
echo 'echo "Waiting for OpenSearch to start..."' >> /usr/share/opensearch/setup-security.sh && \
echo 'PASSWORD=${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-${OPENSEARCH_PASSWORD}}' >> /usr/share/opensearch/setup-security.sh && \
echo 'if [ -z "$PASSWORD" ]; then echo "[ERROR] OPENSEARCH_INITIAL_ADMIN_PASSWORD or OPENSEARCH_PASSWORD must be set"; exit 1; fi' >> /usr/share/opensearch/setup-security.sh && \
echo 'until curl -s -k -u admin:$PASSWORD https://localhost:9200; do sleep 1; done' >> /usr/share/opensearch/setup-security.sh && \
echo 'echo "Generating admin hash from configured password..."' >> /usr/share/opensearch/setup-security.sh && \
echo 'HASH=$(/usr/share/opensearch/plugins/opensearch-security/tools/hash.sh -p "$PASSWORD")' >> /usr/share/opensearch/setup-security.sh && \
echo 'if [ -z "$HASH" ]; then echo "[ERROR] Failed to generate admin hash"; exit 1; fi' >> /usr/share/opensearch/setup-security.sh && \
echo 'sed -i "s|^ hash: \".*\"| hash: \"$HASH\"|" /usr/share/opensearch/securityconfig/internal_users.yml' >> /usr/share/opensearch/setup-security.sh && \
echo 'echo "Updated internal_users.yml with runtime-generated admin hash"' >> /usr/share/opensearch/setup-security.sh && \
echo 'echo "Applying OIDC and DLS security configuration..."' >> /usr/share/opensearch/setup-security.sh && \
echo '/usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \' >> /usr/share/opensearch/setup-security.sh && \
echo ' -cd /usr/share/opensearch/securityconfig \' >> /usr/share/opensearch/setup-security.sh && \
echo ' -icl -nhnv \' >> /usr/share/opensearch/setup-security.sh && \
echo ' -cacert /usr/share/opensearch/config/root-ca.pem \' >> /usr/share/opensearch/setup-security.sh && \
echo ' -cert /usr/share/opensearch/config/kirk.pem \' >> /usr/share/opensearch/setup-security.sh && \
echo ' -key /usr/share/opensearch/config/kirk-key.pem' >> /usr/share/opensearch/setup-security.sh && \
echo 'echo "Security configuration applied successfully"' >> /usr/share/opensearch/setup-security.sh && \
chmod +x /usr/share/opensearch/setup-security.sh
########################################
# Final runtime settings
########################################
USER opensearch
WORKDIR $OPENSEARCH_HOME
ENV JAVA_HOME=$OPENSEARCH_HOME/jdk
ENV PATH=$PATH:$JAVA_HOME/bin:$OPENSEARCH_HOME/bin
# Expose ports
EXPOSE 9200 9300 9600 9650
ENTRYPOINT ["./opensearch-docker-entrypoint.sh"]
CMD ["opensearch"]

View file

@ -1,51 +0,0 @@
FROM python:3.13-slim
# Install curl for uv installation and openssl for RSA key generation
# Also install git for potential dependencies and build-essential for native compilations
RUN apt-get update && apt-get install -y \
curl \
openssl \
git \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Install uv
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:$PATH"
# Set working directory
WORKDIR /app
# Copy Python dependencies
COPY pyproject.toml uv.lock ./
RUN uv sync
# Copy sample document and warmup script for docling
COPY openrag-documents/warmup_ocr.pdf ./
COPY warm_up_docling.py ./
RUN uv run docling-tools models download
RUN uv run python - <<'PY'
import pathlib, easyocr
cache = pathlib.Path("/root/.EasyOCR/model")
cache.mkdir(parents=True, exist_ok=True)
# Prewarm the detector + recog for Doclings default langs
easyocr.Reader(['fr','de','es','en'],
download_enabled=True,
model_storage_directory=str(cache))
print("EasyOCR cache ready at", cache)
PY
# RUN uv run python warm_up_docling.py && rm warm_up_docling.py warmup_ocr.pdf
#ENV EASYOCR_MODULE_PATH=~/.cache/docling/models/EasyOcr/
# Copy Python source and flows
COPY src/ ./src/
COPY flows/ ./flows/
# Expose backend port
EXPOSE 8000
# Start backend in foreground
CMD ["uv", "run", "python", "src/main.py"]

View file

@ -1,20 +0,0 @@
FROM node:20.20.0-slim
# Set working directory
WORKDIR /app
# Copy frontend dependencies
COPY frontend/package*.json ./
RUN npm install
# Copy frontend source
COPY frontend/ ./
# Build frontend
RUN npm run build
# Expose frontend port
EXPOSE 3000
# Start frontend in foreground
CMD ["npm", "start"]

View file

@ -1,5 +0,0 @@
FROM langflowai/langflow-nightly:1.7.0.dev21
EXPOSE 7860
CMD ["langflow", "run", "--host", "0.0.0.0", "--port", "7860"]

201
LICENSE
View file

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 IBM
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1 +0,0 @@
recursive-include src/tui/_assets *

459
Makefile
View file

@ -1,459 +0,0 @@
# OpenRAG Development Makefile
# Provides easy commands for development workflow
# Load variables from .env if present so `make` commands pick them up
# Strip quotes from values to avoid issues with tools that don't handle them like python-dotenv does
ifneq (,$(wildcard .env))
include .env
export $(shell sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=.*/\1/p' .env)
# Strip single quotes from all exported variables
$(foreach var,$(shell sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=.*/\1/p' .env),$(eval $(var):=$(shell echo $($(var)) | sed "s/^'//;s/'$$//")))
endif
.PHONY: help dev dev-cpu dev-local infra stop clean build logs shell-backend shell-frontend install \
test test-integration test-ci test-ci-local test-sdk \
backend frontend install-be install-fe build-be build-fe logs-be logs-fe logs-lf logs-os \
shell-be shell-lf shell-os restart status health db-reset flow-upload quick setup
# Default target
help:
@echo "OpenRAG Development Commands"
@echo ""
@echo "Development:"
@echo " dev - Start full stack with GPU support (docker compose)"
@echo " dev-cpu - Start full stack with CPU only (docker compose)"
@echo " dev-local - Start infrastructure only, run backend/frontend locally"
@echo " infra - Start infrastructure services only (alias for dev-local)"
@echo " stop - Stop all containers"
@echo " restart - Restart all containers"
@echo ""
@echo "Local Development:"
@echo " backend - Run backend locally (requires infrastructure)"
@echo " frontend - Run frontend locally"
@echo " install - Install all dependencies"
@echo " install-be - Install backend dependencies (uv)"
@echo " install-fe - Install frontend dependencies (npm)"
@echo ""
@echo "Utilities:"
@echo " build - Build all Docker images"
@echo " clean - Stop containers and remove volumes"
@echo " logs - Show logs from all containers"
@echo " logs-be - Show backend container logs"
@echo " logs-lf - Show langflow container logs"
@echo " shell-be - Shell into backend container"
@echo " shell-lf - Shell into langflow container"
@echo ""
@echo "Testing:"
@echo " test - Run all backend tests"
@echo " test-integration - Run integration tests (requires infra)"
@echo " test-ci - Start infra, run integration + SDK tests, tear down (uses DockerHub images)"
@echo " test-ci-local - Same as test-ci but builds all images locally"
@echo " test-sdk - Run SDK integration tests (requires running OpenRAG at localhost:3000)"
@echo " lint - Run linting checks"
@echo ""
# Development environments
# Use centralized env file from TUI if it exists, otherwise fall back to local .env
OPENRAG_ENV_FILE := $(shell if [ -f ~/.openrag/tui/.env ]; then echo "--env-file ~/.openrag/tui/.env"; fi)
dev:
@echo "🚀 Starting OpenRAG with GPU support..."
docker compose $(OPENRAG_ENV_FILE) -f docker-compose.yml -f docker-compose.gpu.yml up -d
@echo "✅ Services started!"
@echo " Backend: http://localhost:8000"
@echo " Frontend: http://localhost:3000"
@echo " Langflow: http://localhost:7860"
@echo " OpenSearch: http://localhost:9200"
@echo " Dashboards: http://localhost:5601"
dev-cpu:
@echo "🚀 Starting OpenRAG with CPU only..."
docker compose $(OPENRAG_ENV_FILE) up -d
@echo "✅ Services started!"
@echo " Backend: http://localhost:8000"
@echo " Frontend: http://localhost:3000"
@echo " Langflow: http://localhost:7860"
@echo " OpenSearch: http://localhost:9200"
@echo " Dashboards: http://localhost:5601"
dev-local:
@echo "🔧 Starting infrastructure only (for local development)..."
docker compose $(OPENRAG_ENV_FILE) up -d opensearch dashboards langflow
@echo "✅ Infrastructure started!"
@echo " Langflow: http://localhost:7860"
@echo " OpenSearch: http://localhost:9200"
@echo " Dashboards: http://localhost:5601"
@echo ""
@echo "Now run 'make backend' and 'make frontend' in separate terminals"
infra:
@echo "🔧 Starting infrastructure services only..."
docker compose $(OPENRAG_ENV_FILE) up -d opensearch dashboards langflow
@echo "✅ Infrastructure services started!"
@echo " Langflow: http://localhost:7860"
@echo " OpenSearch: http://localhost:9200"
@echo " Dashboards: http://localhost:5601"
infra-cpu:
@echo "🔧 Starting infrastructure services only..."
docker compose $(OPENRAG_ENV_FILE) up -d opensearch dashboards langflow
@echo "✅ Infrastructure services started!"
@echo " Langflow: http://localhost:7860"
@echo " OpenSearch: http://localhost:9200"
@echo " Dashboards: http://localhost:5601"
# Container management
stop:
@echo "🛑 Stopping all containers..."
docker compose $(OPENRAG_ENV_FILE) down
restart: stop dev
clean: stop
@echo "🧹 Cleaning up containers and volumes..."
docker compose $(OPENRAG_ENV_FILE) down -v --remove-orphans
docker system prune -f
# Local development
backend:
@echo "🐍 Starting backend locally..."
@if [ ! -f .env ]; then echo "⚠️ .env file not found. Copy .env.example to .env first"; exit 1; fi
uv run python src/main.py
frontend:
@echo "⚛️ Starting frontend locally..."
@if [ ! -d "frontend/node_modules" ]; then echo "📦 Installing frontend dependencies first..."; cd frontend && npm install; fi
cd frontend && npx next dev
# Installation
install: install-be install-fe
@echo "✅ All dependencies installed!"
install-be:
@echo "📦 Installing backend dependencies..."
uv sync --extra torch-cu128
install-fe:
@echo "📦 Installing frontend dependencies..."
cd frontend && npm install
# Building
build:
@echo "Building all Docker images locally..."
docker build -t langflowai/openrag-opensearch:latest -f Dockerfile .
docker build -t langflowai/openrag-backend:latest -f Dockerfile.backend .
docker build -t langflowai/openrag-frontend:latest -f Dockerfile.frontend .
docker build -t langflowai/openrag-langflow:latest -f Dockerfile.langflow .
build-be:
@echo "Building backend image..."
docker build -t langflowai/openrag-backend:latest -f Dockerfile.backend .
build-fe:
@echo "Building frontend image..."
docker build -t langflowai/openrag-frontend:latest -f Dockerfile.frontend .
# Logging and debugging
logs:
@echo "📋 Showing all container logs..."
docker compose $(OPENRAG_ENV_FILE) logs -f
logs-be:
@echo "📋 Showing backend logs..."
docker compose $(OPENRAG_ENV_FILE) logs -f openrag-backend
logs-fe:
@echo "📋 Showing frontend logs..."
docker compose $(OPENRAG_ENV_FILE) logs -f openrag-frontend
logs-lf:
@echo "📋 Showing langflow logs..."
docker compose $(OPENRAG_ENV_FILE) logs -f langflow
logs-os:
@echo "📋 Showing opensearch logs..."
docker compose $(OPENRAG_ENV_FILE) logs -f opensearch
# Shell access
shell-be:
@echo "🐚 Opening shell in backend container..."
docker compose $(OPENRAG_ENV_FILE) exec openrag-backend /bin/bash
shell-lf:
@echo "🐚 Opening shell in langflow container..."
docker compose $(OPENRAG_ENV_FILE) exec langflow /bin/bash
shell-os:
@echo "🐚 Opening shell in opensearch container..."
docker compose $(OPENRAG_ENV_FILE) exec opensearch /bin/bash
# Testing and quality
test:
@echo "🧪 Running all backend tests..."
uv run pytest tests/ -v
test-integration:
@echo "🧪 Running integration tests (requires infrastructure)..."
@echo "💡 Make sure to run 'make infra' first!"
uv run pytest tests/integration/ -v
# CI-friendly integration test target: brings up infra, waits, runs tests, tears down
test-ci:
@set -e; \
echo "Installing test dependencies..."; \
uv sync --group dev; \
if [ ! -f keys/private_key.pem ]; then \
echo "Generating RSA keys for JWT signing..."; \
uv run python -c "from src.main import generate_jwt_keys; generate_jwt_keys()"; \
else \
echo "RSA keys already exist, ensuring correct permissions..."; \
chmod 600 keys/private_key.pem 2>/dev/null || true; \
chmod 644 keys/public_key.pem 2>/dev/null || true; \
fi; \
echo "Cleaning up old containers and volumes..."; \
docker compose down -v 2>/dev/null || true; \
echo "Pulling latest images..."; \
docker compose pull; \
echo "Building OpenSearch image override..."; \
docker build --no-cache -t langflowai/openrag-opensearch:latest -f Dockerfile .; \
echo "Starting infra (OpenSearch + Dashboards + Langflow + Backend + Frontend) with CPU containers"; \
docker compose up -d opensearch dashboards langflow openrag-backend openrag-frontend; \
echo "Starting docling-serve..."; \
DOCLING_ENDPOINT=$$(uv run python scripts/docling_ctl.py start --port 5001 | grep "Endpoint:" | awk '{print $$2}'); \
echo "Docling-serve started at $$DOCLING_ENDPOINT"; \
echo "Waiting for backend OIDC endpoint..."; \
for i in $$(seq 1 60); do \
docker exec openrag-backend curl -s http://localhost:8000/.well-known/openid-configuration >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Waiting for OpenSearch security config to be fully applied..."; \
for i in $$(seq 1 60); do \
if docker logs os 2>&1 | grep -q "Security configuration applied successfully"; then \
echo "✓ Security configuration applied"; \
break; \
fi; \
sleep 2; \
done; \
echo "Verifying OIDC authenticator is active in OpenSearch..."; \
AUTHC_CONFIG=$$(curl -k -s -u admin:$${OPENSEARCH_PASSWORD} https://localhost:9200/_opendistro/_security/api/securityconfig 2>/dev/null); \
if echo "$$AUTHC_CONFIG" | grep -q "openid_auth_domain"; then \
echo "✓ OIDC authenticator configured"; \
echo "$$AUTHC_CONFIG" | grep -A 5 "openid_auth_domain"; \
else \
echo "✗ OIDC authenticator NOT found in security config!"; \
echo "Security config:"; \
echo "$$AUTHC_CONFIG" | head -50; \
exit 1; \
fi; \
echo "Waiting for Langflow..."; \
for i in $$(seq 1 60); do \
curl -s http://localhost:7860/ >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Waiting for docling-serve at $$DOCLING_ENDPOINT..."; \
for i in $$(seq 1 60); do \
curl -s $${DOCLING_ENDPOINT}/health >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Running integration tests"; \
LOG_LEVEL=$${LOG_LEVEL:-DEBUG} \
GOOGLE_OAUTH_CLIENT_ID="" \
GOOGLE_OAUTH_CLIENT_SECRET="" \
OPENSEARCH_HOST=localhost OPENSEARCH_PORT=9200 \
OPENSEARCH_USERNAME=admin OPENSEARCH_PASSWORD=$${OPENSEARCH_PASSWORD} \
DISABLE_STARTUP_INGEST=$${DISABLE_STARTUP_INGEST:-true} \
uv run pytest tests/integration -vv -s -o log_cli=true --log-cli-level=DEBUG; \
TEST_RESULT=$$?; \
echo ""; \
echo "Waiting for frontend at http://localhost:3000..."; \
for i in $$(seq 1 60); do \
curl -s http://localhost:3000/ >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Running Python SDK integration tests"; \
cd sdks/python && \
uv sync --extra dev && \
OPENRAG_URL=http://localhost:3000 uv run pytest tests/test_integration.py -vv -s || TEST_RESULT=1; \
cd ../..; \
echo "Running TypeScript SDK integration tests"; \
cd sdks/typescript && \
npm install && npm run build && \
OPENRAG_URL=http://localhost:3000 npm test || TEST_RESULT=1; \
cd ../..; \
echo ""; \
echo "=== Post-test JWT diagnostics ==="; \
echo "Generating test JWT token..."; \
TEST_TOKEN=$$(uv run python -c "from src.session_manager import SessionManager, AnonymousUser; sm = SessionManager('test'); print(sm.create_jwt_token(AnonymousUser()))" 2>/dev/null || echo ""); \
if [ -n "$$TEST_TOKEN" ]; then \
echo "Testing JWT against OpenSearch..."; \
HTTP_CODE=$$(curl -k -s -w "%{http_code}" -o /tmp/os_diag.txt -H "Authorization: Bearer $$TEST_TOKEN" -H "Content-Type: application/json" https://localhost:9200/documents/_search -d '{"query":{"match_all":{}}}' 2>&1); \
echo "HTTP $$HTTP_CODE: $$(cat /tmp/os_diag.txt | head -c 150)"; \
fi; \
echo "================================="; \
echo ""; \
echo "Tearing down infra"; \
uv run python scripts/docling_ctl.py stop || true; \
docker compose down -v 2>/dev/null || true; \
exit $$TEST_RESULT
# CI-friendly integration test target with local builds: builds all images, brings up infra, waits, runs tests, tears down
test-ci-local:
@set -e; \
echo "Installing test dependencies..."; \
uv sync --group dev; \
if [ ! -f keys/private_key.pem ]; then \
echo "Generating RSA keys for JWT signing..."; \
uv run python -c "from src.main import generate_jwt_keys; generate_jwt_keys()"; \
else \
echo "RSA keys already exist, ensuring correct permissions..."; \
chmod 600 keys/private_key.pem 2>/dev/null || true; \
chmod 644 keys/public_key.pem 2>/dev/null || true; \
fi; \
echo "Cleaning up old containers and volumes..."; \
docker compose down -v 2>/dev/null || true; \
echo "Building all images locally..."; \
docker build -t langflowai/openrag-opensearch:latest -f Dockerfile .; \
docker build -t langflowai/openrag-backend:latest -f Dockerfile.backend .; \
docker build -t langflowai/openrag-frontend:latest -f Dockerfile.frontend .; \
docker build -t langflowai/openrag-langflow:latest -f Dockerfile.langflow .; \
echo "Starting infra (OpenSearch + Dashboards + Langflow + Backend + Frontend) with CPU containers"; \
docker compose up -d opensearch dashboards langflow openrag-backend openrag-frontend; \
echo "Starting docling-serve..."; \
DOCLING_ENDPOINT=$$(uv run python scripts/docling_ctl.py start --port 5001 | grep "Endpoint:" | awk '{print $$2}'); \
echo "Docling-serve started at $$DOCLING_ENDPOINT"; \
echo "Waiting for backend OIDC endpoint..."; \
for i in $$(seq 1 60); do \
docker exec openrag-backend curl -s http://localhost:8000/.well-known/openid-configuration >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Waiting for OpenSearch security config to be fully applied..."; \
for i in $$(seq 1 60); do \
if docker logs os 2>&1 | grep -q "Security configuration applied successfully"; then \
echo "✓ Security configuration applied"; \
break; \
fi; \
sleep 2; \
done; \
echo "Verifying OIDC authenticator is active in OpenSearch..."; \
AUTHC_CONFIG=$$(curl -k -s -u admin:$${OPENSEARCH_PASSWORD} https://localhost:9200/_opendistro/_security/api/securityconfig 2>/dev/null); \
if echo "$$AUTHC_CONFIG" | grep -q "openid_auth_domain"; then \
echo "✓ OIDC authenticator configured"; \
echo "$$AUTHC_CONFIG" | grep -A 5 "openid_auth_domain"; \
else \
echo "✗ OIDC authenticator NOT found in security config!"; \
echo "Security config:"; \
echo "$$AUTHC_CONFIG" | head -50; \
exit 1; \
fi; \
echo "Waiting for Langflow..."; \
for i in $$(seq 1 60); do \
curl -s http://localhost:7860/ >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Waiting for docling-serve at $$DOCLING_ENDPOINT..."; \
for i in $$(seq 1 60); do \
curl -s $${DOCLING_ENDPOINT}/health >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Running integration tests"; \
LOG_LEVEL=$${LOG_LEVEL:-DEBUG} \
GOOGLE_OAUTH_CLIENT_ID="" \
GOOGLE_OAUTH_CLIENT_SECRET="" \
OPENSEARCH_HOST=localhost OPENSEARCH_PORT=9200 \
OPENSEARCH_USERNAME=admin OPENSEARCH_PASSWORD=$${OPENSEARCH_PASSWORD} \
DISABLE_STARTUP_INGEST=$${DISABLE_STARTUP_INGEST:-true} \
uv run pytest tests/integration -vv -s -o log_cli=true --log-cli-level=DEBUG; \
TEST_RESULT=$$?; \
echo ""; \
echo "Waiting for frontend at http://localhost:3000..."; \
for i in $$(seq 1 60); do \
curl -s http://localhost:3000/ >/dev/null 2>&1 && break || sleep 2; \
done; \
echo "Running Python SDK integration tests"; \
cd sdks/python && \
uv sync --extra dev && \
OPENRAG_URL=http://localhost:3000 uv run pytest tests/test_integration.py -vv -s || TEST_RESULT=1; \
cd ../..; \
echo "Running TypeScript SDK integration tests"; \
cd sdks/typescript && \
npm install && npm run build && \
OPENRAG_URL=http://localhost:3000 npm test || TEST_RESULT=1; \
cd ../..; \
echo ""; \
echo "=== Post-test JWT diagnostics ==="; \
echo "Generating test JWT token..."; \
TEST_TOKEN=$$(uv run python -c "from src.session_manager import SessionManager, AnonymousUser; sm = SessionManager('test'); print(sm.create_jwt_token(AnonymousUser()))" 2>/dev/null || echo ""); \
if [ -n "$$TEST_TOKEN" ]; then \
echo "Testing JWT against OpenSearch..."; \
HTTP_CODE=$$(curl -k -s -w "%{http_code}" -o /tmp/os_diag.txt -H "Authorization: Bearer $$TEST_TOKEN" -H "Content-Type: application/json" https://localhost:9200/documents/_search -d '{"query":{"match_all":{}}}' 2>&1); \
echo "HTTP $$HTTP_CODE: $$(cat /tmp/os_diag.txt | head -c 150)"; \
fi; \
echo "================================="; \
echo ""; \
if [ $$TEST_RESULT -ne 0 ]; then \
echo "=== Tests failed, dumping container logs ==="; \
echo ""; \
echo "=== Langflow logs (last 500 lines) ==="; \
docker logs langflow 2>&1 | tail -500 || echo "Could not get Langflow logs"; \
echo ""; \
echo "=== Backend logs (last 200 lines) ==="; \
docker logs openrag-backend 2>&1 | tail -200 || echo "Could not get backend logs"; \
echo ""; \
fi; \
echo "Tearing down infra"; \
uv run python scripts/docling_ctl.py stop || true; \
docker compose down -v 2>/dev/null || true; \
exit $$TEST_RESULT
# SDK integration tests (requires running OpenRAG instance)
test-sdk:
@echo "Running SDK integration tests..."
@echo "Make sure OpenRAG is running at localhost:3000 (make up)"
@echo ""
@echo "Running Python SDK tests..."
cd sdks/python && uv sync --extra dev && OPENRAG_URL=http://localhost:3000 uv run pytest tests/test_integration.py -vv -s
@echo ""
@echo "Running TypeScript SDK tests..."
cd sdks/typescript && npm install && npm run build && OPENRAG_URL=http://localhost:3000 npm test
lint:
@echo "🔍 Running linting checks..."
cd frontend && npm run lint
@echo "Frontend linting complete"
# Service status
status:
@echo "📊 Container status:"
@docker compose $(OPENRAG_ENV_FILE) ps 2>/dev/null || echo "No containers running"
health:
@echo "🏥 Health check:"
@echo "Backend: $$(curl -s http://localhost:8000/health 2>/dev/null || echo 'Not responding')"
@echo "Langflow: $$(curl -s http://localhost:7860/health 2>/dev/null || echo 'Not responding')"
@echo "OpenSearch: $$(curl -s -k -u admin:$${OPENSEARCH_PASSWORD} https://localhost:9200 2>/dev/null | jq -r .tagline 2>/dev/null || echo 'Not responding')"
# Database operations
db-reset:
@echo "🗄️ Resetting OpenSearch indices..."
curl -X DELETE "http://localhost:9200/documents" -u admin:$${OPENSEARCH_PASSWORD} || true
curl -X DELETE "http://localhost:9200/knowledge_filters" -u admin:$${OPENSEARCH_PASSWORD} || true
@echo "Indices reset. Restart backend to recreate."
clear-os-data:
@echo "🧹 Clearing OpenSearch data directory..."
@uv run python scripts/clear_opensearch_data.py
# Flow management
flow-upload:
@echo "📁 Uploading flow to Langflow..."
@if [ -z "$(FLOW_FILE)" ]; then echo "Usage: make flow-upload FLOW_FILE=path/to/flow.json"; exit 1; fi
curl -X POST "http://localhost:7860/api/v1/flows" \
-H "Content-Type: application/json" \
-d @$(FLOW_FILE)
# Quick development shortcuts
quick: dev-local
@echo "🚀 Quick start: infrastructure running!"
@echo "Run these in separate terminals:"
@echo " make backend"
@echo " make frontend"
# Environment setup
setup:
@echo "⚙️ Setting up development environment..."
@if [ ! -f .env ]; then cp .env.example .env && echo "📝 Created .env from template"; fi
@$(MAKE) install
@echo "✅ Setup complete! Run 'make dev' to start."

View file

@ -1,34 +0,0 @@
<div align="center">
# OpenRAG
<div align="center">
<a href="https://github.com/langflow-ai/langflow"><img src="https://img.shields.io/badge/Langflow-1C1C1E?style=flat&logo=langflow" alt="Langflow"></a>
&nbsp;&nbsp;
<a href="https://github.com/opensearch-project/OpenSearch"><img src="https://img.shields.io/badge/OpenSearch-005EB8?style=flat&logo=opensearch&logoColor=white" alt="OpenSearch"></a>
&nbsp;&nbsp;
<a href="https://github.com/docling-project/docling"><img src="https://img.shields.io/badge/Docling-000000?style=flat" alt="Langflow"></a>
&nbsp;&nbsp;
</div>
OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations. Users can upload, process, and query documents through a chat interface backed by large language models and semantic search capabilities. The system utilizes Langflow for document ingestion, retrieval workflows, and intelligent nudges, providing a seamless RAG experience. Built with [Starlette](https://github.com/Kludex/starlette) and [Next.js](https://github.com/vercel/next.js). Powered by [OpenSearch](https://github.com/opensearch-project/OpenSearch), [Langflow](https://github.com/langflow-ai/langflow), and [Docling](https://github.com/docling-project/docling).
<a href="https://deepwiki.com/langflow-ai/openrag"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
## Install OpenRAG
To get started with OpenRAG, see the installation guides in the OpenRAG documentation:
* [Quickstart](https://docs.openr.ag/quickstart)
* [Install the OpenRAG Python package](https://docs.openr.ag/install-options)
* [Deploy self-managed services with Docker or Podman](https://docs.openr.ag/docker)
## Development
For developers who want to [contribute to OpenRAG](https://docs.openr.ag/support/contribute) or set up a development environment, see [CONTRIBUTING.md](CONTRIBUTING.md).
## Troubleshooting
For assistance with OpenRAG, see [Troubleshoot OpenRAG](https://docs.openr.ag/support/troubleshoot) and visit the [Discussions page](https://github.com/langflow-ai/openrag/discussions).
To report a bug or submit a feature request, visit the [Issues page](https://github.com/langflow-ai/openrag/issues).

View file

@ -1,64 +0,0 @@
# OpenRAG security policy and responsible disclosure
## Security policy
This security policy applies to all public projects under the langflow-ai organization on GitHub. We prioritize security and continuously work to safeguard our systems. However, vulnerabilities can still exist. If you identify a security issue, please report it to us so we can address it promptly.
### Security and bug fix versions
- Fixes are released either as part of the next minor version (e.g., 1.3.0 → 1.4.0) or as an on-demand patch version (e.g., 1.3.0 → 1.3.1)
- Security fixes are given priority and might be enough to cause a new version to be released
## Report a vulnerability
We encourage responsible disclosure of security vulnerabilities. If you find or suspect a security issue, please discreetly report it to us so we can address it promptly:
### Submit a report
Go to the [OpenRAG Security page](https://github.com/langflow-ai/openrag/security), and then click **Report a vulnerability** to start a private conversation between you and the repository's maintainers.
Provide as many specific details as possible to help us reproduce and fix the issue quickly, including the following:
- Steps to reproduce the issue
- Potential impact or concerns
- Any suggested fixes
Your report is kept confidential, and these details aren't shared without your consent.
### Response timeline
We will acknowledge your report within 5 business days.
We will provide an estimated resolution timeline.
We will keep you updated on our progress.
### Disclosure guidelines
- Don't publicly disclose vulnerabilities until we have assessed, resolved, and notified affected users.
- If you plan to present your research (e.g., at a conference or in a blog), share a draft with us at least 30 days in advance for review.
- Disclosures must not include the following:
- Data from any OpenRAG customer projects
- OpenRAG user/customer information
- Details about OpenRAG employees, contractors, or partners
We appreciate your efforts in helping us maintain a secure platform, and we look forward to working together to resolve any issues responsibly.
## Known vulnerabilities
The following known vulnerabilities are for the OpenRAG codebase.
This list doesn't include vulnerabilities within OpenRAG dependencies like OpenSearch and Langflow.
For Langflow vulnerabilities, see the [Langflow SECURITY.md](https://github.com/langflow-ai/langflow/blob/main/SECURITY.md).
There are no known vulnerabilities exclusive to the OpenRAG application at this time.
## Security configuration guidelines
### Start the Langflow server with authentication enabled
It is recommended that you set a Langflow password (`LANGFLOW_SUPERUSER_PASSWORD`) so the Langflow server starts with authentication enabled and the `langflow superuser` command disabled.
You can set this password when you install OpenRAG, or you can [edit the OpenRAG `.env` file and redeploy the OpenRAG containers](https://docs.openr.ag/reference/configuration#set-environment-variables).
For more information, see [OpenRAG's Langflow settings reference](https://docs.openr.ag/reference/configuration#langflow-settings).

95
agents/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because one or more lines are too long

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View file

Before

Width:  |  Height:  |  Size: 1 MiB

After

Width:  |  Height:  |  Size: 1 MiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[1e3],{1e3:(e,a,s)=>{s.d(a,{createRadarServices:()=>c.f});var c=s(7846);s(7960)}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,9 @@
/*!
Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable
Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com)
Licensed under The MIT License (http://opensource.org/licenses/MIT)
*/
/*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */
/*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[2237],{2237:(e,t,n)=>{n.r(t),n.d(t,{default:()=>h});n(6540);var o=n(1312),i=n(5500),s=n(2765),a=n(3363),r=n(4848);function h(){const e=(0,o.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.be,{title:e}),(0,r.jsx)(s.A,{children:(0,r.jsx)(a.A,{})})]})}},3363:(e,t,n)=>{n.d(t,{A:()=>r});n(6540);var o=n(4164),i=n(1312),s=n(1107),a=n(4848);function r({className:e}){return(0,a.jsx)("main",{className:(0,o.A)("container margin-vert--xl",e),children:(0,a.jsx)("div",{className:"row",children:(0,a.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,a.jsx)(s.A,{as:"h1",className:"hero__title",children:(0,a.jsx)(i.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,a.jsx)("p",{children:(0,a.jsx)(i.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,a.jsx)("p",{children:(0,a.jsx)(i.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
/*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[2325],{2325:(e,a,c)=>{c.d(a,{createPacketServices:()=>s.$});var s=c(1477);c(7960)}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[3490],{3490:(e,a,s)=>{s.d(a,{createInfoServices:()=>c.v});var c=s(1885);s(7960)}}]);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[3815],{3815:(r,s,a)=>{a.d(s,{diagram:()=>o});var e=a(1746),l=(a(2501),a(9625),a(1152),a(45),a(5164),a(8698),a(5894),a(3245),a(2387),a(92),a(3226),a(7633),a(797)),o={parser:e._$,get db(){return new e.NM},renderer:e.Lh,styles:e.tM,init:(0,l.K2)(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")}}}]);

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[416],{416:(s,a,o)=>{o.r(a)}}]);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,6 @@
/**
* @license lucide-react v0.555.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[4250],{1869:(a,e,s)=>{s.d(e,{createGitGraphServices:()=>c.b});var c=s(7539);s(7960)}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[4802],{4802:(e,r,a)=>{a.d(r,{diagram:()=>o});var t=a(4616),s=(a(9625),a(1152),a(45),a(5164),a(8698),a(5894),a(3245),a(2387),a(92),a(3226),a(7633),a(797)),o={parser:t.Zk,get db(){return new t.u4(2)},renderer:t.q7,styles:t.tM,init:(0,s.K2)(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")}}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[5901],{5901:(e,a,s)=>{s.d(a,{createTreemapServices:()=>c.d});var c=s(1633);s(7960)}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[9647],{7121:(e,s,r)=>{r.r(s),r.d(s,{default:()=>d});r(6540);var a=r(4164),c=r(7559),o=r(5500),n=r(2831),u=r(2765),l=r(4848);function d(e){return(0,l.jsx)(o.e3,{className:(0,a.A)(c.G.wrapper.docsPages),children:(0,l.jsx)(u.A,{children:(0,n.v)(e.route.routes)})})}}}]);

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[617],{617:(e,a,s)=>{s.d(a,{createPieServices:()=>c.f});var c=s(9150);s(7960)}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[6366],{6366:(e,c,a)=>{a.d(c,{createArchitectureServices:()=>r.S});var r=a(8980);a(7960)}}]);

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[6567],{5871:(t,e,a)=>{function r(t,e){t.accDescr&&e.setAccDescription?.(t.accDescr),t.accTitle&&e.setAccTitle?.(t.accTitle),t.title&&e.setDiagramTitle?.(t.title)}a.d(e,{S:()=>r}),(0,a(797).K2)(r,"populateCommonDb")},8948:(t,e,a)=>{a.d(e,{diagram:()=>m});var r=a(3590),i=a(5871),o=a(3226),n=a(7633),s=a(797),l=a(8731),c=n.UI.packet,d=class{constructor(){this.packet=[],this.setAccTitle=n.SV,this.getAccTitle=n.iN,this.setDiagramTitle=n.ke,this.getDiagramTitle=n.ab,this.getAccDescription=n.m7,this.setAccDescription=n.EI}static{(0,s.K2)(this,"PacketDB")}getConfig(){const t=(0,o.$t)({...c,...(0,n.zj)().packet});return t.showBits&&(t.paddingY+=10),t}getPacket(){return this.packet}pushWord(t){t.length>0&&this.packet.push(t)}clear(){(0,n.IU)(),this.packet=[]}},p=(0,s.K2)((t,e)=>{(0,i.S)(t,e);let a=-1,r=[],o=1;const{bitsPerRow:n}=e.getConfig();for(let{start:i,end:l,bits:c,label:d}of t.blocks){if(void 0!==i&&void 0!==l&&l<i)throw new Error(`Packet block ${i} - ${l} is invalid. End must be greater than start.`);if(i??=a+1,i!==a+1)throw new Error(`Packet block ${i} - ${l??i} is not contiguous. It should start from ${a+1}.`);if(0===c)throw new Error(`Packet block ${i} is invalid. Cannot have a zero bit field.`);for(l??=i+(c??1)-1,c??=l-i+1,a=l,s.Rm.debug(`Packet block ${i} - ${a} with label ${d}`);r.length<=n+1&&e.getPacket().length<1e4;){const[t,a]=b({start:i,end:l,bits:c,label:d},o,n);if(r.push(t),t.end+1===o*n&&(e.pushWord(r),r=[],o++),!a)break;({start:i,end:l,bits:c,label:d}=a)}}e.pushWord(r)},"populate"),b=(0,s.K2)((t,e,a)=>{if(void 0===t.start)throw new Error("start should have been set during first phase");if(void 0===t.end)throw new Error("end should have been set during first phase");if(t.start>t.end)throw new Error(`Block start ${t.start} is greater than block end ${t.end}.`);if(t.end+1<=e*a)return[t,void 0];const r=e*a-1,i=e*a;return[{start:t.start,end:r,label:t.label,bits:r-t.start},{start:i,end:t.end,label:t.label,bits:t.end-i}]},"getNextFittingBlock"),h={parser:{yy:void 0},parse:(0,s.K2)(async t=>{const e=await(0,l.qg)("packet",t),a=h.parser?.yy;if(!(a instanceof d))throw new Error("parser.parser?.yy was not a PacketDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues.");s.Rm.debug(e),p(e,a)},"parse")},k=(0,s.K2)((t,e,a,i)=>{const o=i.db,s=o.getConfig(),{rowHeight:l,paddingY:c,bitWidth:d,bitsPerRow:p}=s,b=o.getPacket(),h=o.getDiagramTitle(),k=l+c,u=k*(b.length+1)-(h?0:l),f=d*p+2,w=(0,r.D)(e);w.attr("viewbox",`0 0 ${f} ${u}`),(0,n.a$)(w,u,f,s.useMaxWidth);for(const[r,n]of b.entries())g(w,n,r,s);w.append("text").text(h).attr("x",f/2).attr("y",u-k/2).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("class","packetTitle")},"draw"),g=(0,s.K2)((t,e,a,{rowHeight:r,paddingX:i,paddingY:o,bitWidth:n,bitsPerRow:s,showBits:l})=>{const c=t.append("g"),d=a*(r+o)+o;for(const p of e){const t=p.start%s*n+1,e=(p.end-p.start+1)*n-i;if(c.append("rect").attr("x",t).attr("y",d).attr("width",e).attr("height",r).attr("class","packetBlock"),c.append("text").attr("x",t+e/2).attr("y",d+r/2).attr("class","packetLabel").attr("dominant-baseline","middle").attr("text-anchor","middle").text(p.label),!l)continue;const a=p.end===p.start,o=d-2;c.append("text").attr("x",t+(a?e/2:0)).attr("y",o).attr("class","packetByte start").attr("dominant-baseline","auto").attr("text-anchor",a?"middle":"start").text(p.start),a||c.append("text").attr("x",t+e).attr("y",o).attr("class","packetByte end").attr("dominant-baseline","auto").attr("text-anchor","end").text(p.end)}},"drawWord"),u={draw:k},f={byteFontSize:"10px",startByteColor:"black",endByteColor:"black",labelColor:"black",labelFontSize:"12px",titleColor:"black",titleFontSize:"14px",blockStrokeColor:"black",blockStrokeWidth:"1",blockFillColor:"#efefef"},w=(0,s.K2)(({packet:t}={})=>{const e=(0,o.$t)(f,t);return`\n\t.packetByte {\n\t\tfont-size: ${e.byteFontSize};\n\t}\n\t.packetByte.start {\n\t\tfill: ${e.startByteColor};\n\t}\n\t.packetByte.end {\n\t\tfill: ${e.endByteColor};\n\t}\n\t.packetLabel {\n\t\tfill: ${e.labelColor};\n\t\tfont-size: ${e.labelFontSize};\n\t}\n\t.packetTitle {\n\t\tfill: ${e.titleColor};\n\t\tfont-size: ${e.titleFontSize};\n\t}\n\t.packetBlock {\n\t\tstroke: ${e.blockStrokeColor};\n\t\tstroke-width: ${e.blockStrokeWidth};\n\t\tfill: ${e.blockFillColor};\n\t}\n\t`},"styles"),m={parser:h,get db(){return new d},renderer:u,styles:w}}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(globalThis.webpackChunkopenrag_docs=globalThis.webpackChunkopenrag_docs||[]).push([[7465],{7465:(e,a,r)=>{r.d(a,{diagram:()=>p});var n=r(9264),s=r(3590),t=r(7633),o=r(797),i=r(8731),d={parse:(0,o.K2)(async e=>{const a=await(0,i.qg)("info",e);o.Rm.debug(a)},"parse")},g={version:n.n.version+""},p={parser:d,db:{getVersion:(0,o.K2)(()=>g.version,"getVersion")},renderer:{draw:(0,o.K2)((e,a,r)=>{o.Rm.debug("rendering info diagram\n"+e);const n=(0,s.D)(a);(0,t.a$)(n,100,400,!0);n.append("g").append("text").attr("x",100).attr("y",40).attr("class","version").attr("font-size",32).style("text-anchor","middle").text(`v${r}`)},"draw")}}}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more