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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
DESCOPE_PROJECT_ID=
ANTHROPIC_API_KEY=
LANGSMITH_API_KEY=
LANGSMITH_ENDPOINT=https://eu.api.smith.langchain.com
AUTH_TRUST_HOST=true
AUTH_DESCOPE_ID=
AUTH_DESCOPE_SECRET=
AUTH_SECRET=# Generate with `npx auth`. Read more: https://cli.authjs.dev
PUBLIC_LANGCHAIN_API_KEY=
PUBLIC_LANGGRAPH_API_URL=http://127.0.0.1:2024
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.env
__pycache__/
.langgraph_api/

# moon
.moon/cache
.moon/docker
5 changes: 5 additions & 0 deletions .moon/tasks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# https://moonrepo.dev/docs/config/tasks
$schema: "https://moonrepo.dev/schemas/tasks.json"

taskOptions:
envFile: .env
11 changes: 11 additions & 0 deletions .moon/toolchain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# https://moonrepo.dev/docs/config/toolchain
$schema: "https://moonrepo.dev/schemas/toolchain.json"

python:
version: "3.12"
packageManager: "uv"

node:
version: "24"
packageManager: "pnpm"
inferTasksFromScripts: true
12 changes: 12 additions & 0 deletions .moon/workspace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# https://moonrepo.dev/docs/config/workspace
$schema: "./cache/schemas/workspace.json"

# extends: './shared/workspace.yml'

projects:
- "apps/*"
- "packages/*"

vcs:
manager: "git"
defaultBranch: "main"
1 change: 1 addition & 0 deletions .prototools
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
moon = "1.38.5"
1 change: 0 additions & 1 deletion .python-version

This file was deleted.

73 changes: 19 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,35 @@ Opinionated SvelteKit/Flowbite based LLM frontend for LangGraph server.

## Prerequisites

- Python 3.12
- Node.js 24 LTS
- [uv](https://docs.astral.sh/uv/) (Python package manager)
- pnpm (Node.js package manager)
- [Install moonrepo](https://moonrepo.dev/docs/install), which installs all other dependencies:

* Python 3.12
* Node.js 24 LTS
* [uv](https://docs.astral.sh/uv/) (Python package manager)
* pnpm (Node.js package manager)

## Configuration

Both the frontend and backend require environment variables to be configured. Copy the example files and update them with your values:

### Backend Environment Variables
### Environment Variables

Copy the example file:
```bash
cd apps/backend
cp .env.example .env
```

Configure the following variables in `apps/backend/.env`:
#### Backend
Configure the following variables in `.env`:

- `DESCOPE_PROJECT_ID` - Your Descope project ID for authentication
- `ANTHROPIC_API_KEY` - Your Anthropic API key for Claude integration
- `LANGSMITH_API_KEY` - Your LangSmith API key for tracing (optional)
- `LANGSMITH_ENDPOINT` - LangSmith endpoint URL (defaults to EU region)

### Frontend Environment Variables

Copy the example file:
```bash
cd apps/frontend
cp .env.example .env
```
#### Frontend

Configure the following variables in `apps/frontend/.env`:
Configure the following variables in `.env`:

- `AUTH_TRUST_HOST=true` - Enable auth trust host for development
- `AUTH_DESCOPE_ID` - Your Descope project ID
Expand All @@ -54,43 +50,23 @@ Configure the following variables in `apps/frontend/.env`:

## Getting Started

### Backend Setup

Navigate to the backend directory and install dependencies:

```bash
cd apps/backend
uv sync
```
### Start dev servers

Start the development server:
The following command ensures dependencies are installed and starts dev servers for frontend and backend, with hot reload:

```bash
uv run langgraph dev
moon :dev
```

### Frontend Setup
### Run local checks

Navigate to the frontend directory and install dependencies:
Run all checks (linting, type checking, formatting):

```bash
cd apps/frontend
pnpm install
moon check --all
```

Start the development server:

```bash
npm run dev
```

Or open the app in a new browser tab:

```bash
npm run dev -- --open
```

## Development
## Tooling

### Backend Development

Expand All @@ -108,17 +84,6 @@ The frontend is built with modern web technologies:
- Playwright for end-to-end testing
- Vitest for unit testing

#### Available Scripts

- `npm run dev` - Start development server
- `npm run build` - Build for production
- `npm run preview` - Preview production build
- `npm run test` - Run all tests
- `npm run test:unit` - Run unit tests
- `npm run test:e2e` - Run end-to-end tests
- `npm run lint` - Lint code
- `npm run format` - Format code

## Production

### Frontend Build
Expand Down Expand Up @@ -147,4 +112,4 @@ svelte-langgraph/
│ ├── messages/ # Internationalization files
│ └── e2e/ # End-to-end tests
└── README.md
```
```
21 changes: 21 additions & 0 deletions apps/backend/moon.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# https://moonrepo.dev/docs/config/project
$schema: "https://moonrepo.dev/schemas/project.json"

language: python
stack: backend
type: application

tasks:
format:
command: "ruff format"
lint:
command: "ruff check"
lint-fix:
extends: lint
args: "--fix"
local: true
typecheck:
command: "pyright"
dev:
command: "langgraph dev --no-browser"
preset: "watcher"
9 changes: 4 additions & 5 deletions apps/backend/src/auth.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import logging
import os
# import os

from descope import AuthException
from langgraph_sdk import Auth
from langgraph_sdk.auth.types import MinimalUserDict

from descope import DescopeClient
# from descope import DescopeClient

logger = logging.getLogger(__name__)

descope_client = DescopeClient(project_id=os.getenv("DESCOPE_PROJECT_ID", ""))
# descope_client = DescopeClient(project_id=os.getenv("DESCOPE_PROJECT_ID", ""))

# The "Auth" object is a container that LangGraph will use to mark our authentication function
auth = Auth()
Expand Down Expand Up @@ -54,7 +53,7 @@ async def get_current_user(authorization: str | None) -> MinimalUserDict:
# permissions=claims["permissions"],
# )

return user
# return user


@auth.on
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/src/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ def make_graph(config: RunnableConfig) -> CompiledStateGraph:
async def main():
load_dotenv()

agent = make_graph()

config = RunnableConfig(configurable={"thread_id": "1"})

agent = make_graph(config)

user_input = input(f"{INITIAL_MESSAGE}\n")

while True:
Expand Down
7 changes: 5 additions & 2 deletions apps/frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# sv

Svelte frontend project.

## Getting started

### Requirements
* pnpm
* Node 24 LTS

- pnpm
- Node 24 LTS

### Install deps

```bash
pnpm install
```
Expand Down
6 changes: 6 additions & 0 deletions apps/frontend/moon.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# https://moonrepo.dev/docs/config/project
$schema: 'https://moonrepo.dev/schemas/project.json'

language: typescript
stack: frontend
type: application
20 changes: 9 additions & 11 deletions apps/frontend/src/app.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
<!doctype html>
<html lang="%paraglide.lang%">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>

<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>

<body data-sveltekit-preload-data="hover" class="bg-white dark:bg-gray-800">
<div style="display: contents">%sveltekit.body%</div>
</body>

<body data-sveltekit-preload-data="hover" class="bg-white dark:bg-gray-800">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
5 changes: 2 additions & 3 deletions apps/frontend/src/app.tailwind.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "tailwindcss";
@import 'tailwindcss';

@plugin '@tailwindcss/forms';
@plugin '@tailwindcss/typography';
Expand Down Expand Up @@ -36,9 +36,8 @@
@source '../node_modules/flowbite-svelte-blocks/dist';

@layer base {

/* disable chrome cancel button */
input[type="search"]::-webkit-search-cancel-button {
input[type='search']::-webkit-search-cancel-button {
display: none;
}
}
8 changes: 4 additions & 4 deletions apps/frontend/src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SvelteKitAuth } from "@auth/sveltekit"
import Descope from "@auth/sveltekit/providers/descope"
import { SvelteKitAuth } from '@auth/sveltekit';
import Descope from '@auth/sveltekit/providers/descope';

export const { handle, signIn, signOut } = SvelteKitAuth({
providers: [Descope],
})
providers: [Descope]
});
2 changes: 1 addition & 1 deletion apps/frontend/src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';
import { paraglideMiddleware } from '$lib/paraglide/server';
import { handle as handleAuth } from "./auth";
import { handle as handleAuth } from './auth';

const handleParaglide: Handle = ({ event, resolve }) =>
paraglideMiddleware(event.request, ({ request, locale }) => {
Expand Down
10 changes: 5 additions & 5 deletions apps/frontend/src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { LayoutServerLoad } from "./$types"
import type { LayoutServerLoad } from './$types';

export const load: LayoutServerLoad = async (event) => {
const session = await event.locals.auth()
const session = await event.locals.auth();

return {
session,
}
}
session
};
};
Loading