Skip to content

Commit ab1a825

Browse files
authored
Merge branch 'main' into feat/password-transit-encryption
2 parents cbd442c + 57bedc8 commit ab1a825

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+474
-420
lines changed

.cursor/rules/github-issue-operation.mdc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ alwaysApply: false
1414

1515
(i.e., https://github.com/telepace/nexus)
1616

17-
- The language chosen for raising an issue: Chinese-
17+
- The language chosen for raising an issue: Chinese, Concise content
1818
- Before writing the issue content, use mcp's thinking in combination with the current repository code and implementation to think about what the solution to the task is.
1919
- Be careful not to be too AI in your tone.
2020
- Pay attention to choosing the appropriate labels and types. And select the latest Milestone(OR v0.1)
2121
- Assign tasks. If it is a simple UI-related task, assign it to @Neo-Neooo, and if it is a complex task, deployment, cicd, assign it to @cubxxw. If both the front-end and back-end are involved, it only needs to be assigned to @cubxxw
2222
- If possible, describe the design drawings or architecture drawings using mermaid code blocks as much as possible
2323
- No need for my confirmation. Just execute directly
24+
- Issue should not provide the task cycle
25+
- The acceptance criteria must be supplemented. For example, it is allowed only after passing the xxx test
2426

2527
**Postgres db operation Logic:**
2628

.github/workflows/test-backend.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,10 @@ jobs:
6666
- name: Install dependencies
6767
run: docker compose --project-name $STACK_NAME run --rm backend uv pip install -e .
6868
- name: Migrate DB
69-
run: docker compose --project-name $STACK_NAME run --rm -e TESTING=true -e TEST_MODE=true backend uv run bash scripts/prestart.sh
69+
run: docker compose --project-name $STACK_NAME run --rm backend uv run bash scripts/prestart.sh
7070
working-directory: backend
7171

7272
- name: Run tests
73-
<<<<<<< HEAD
7473
run: |
7574
# Set test environment variables to ensure consistency
7675
export TESTING=true
@@ -79,21 +78,11 @@ jobs:
7978
8079
docker compose --project-name $STACK_NAME run --rm backend uv run bash scripts/tests-start.sh "Coverage for ${{ github.sha }}"
8180
working-directory: backend
82-
<<<<<<< HEAD
8381
timeout-minutes: 20
84-
=======
85-
env:
86-
TESTING: "true"
87-
TEST_MODE: "true"
88-
>>>>>>> 0a834ae (chore: update test-backend workflow to enable testing environment variables)
89-
=======
90-
run: docker compose --project-name $STACK_NAME run --rm -e TESTING=true -e TEST_MODE=true backend uv run bash scripts/tests-start.sh "Coverage for ${{ github.sha }}"
91-
working-directory: backend
92-
>>>>>>> 1d6b4c6 (chore: improve test scripts for CI environment detection)
9382
- run: docker compose --project-name $STACK_NAME down -v --remove-orphans
9483
- name: Store coverage files
9584
uses: actions/upload-artifact@v4
9685
with:
9786
name: coverage-html
9887
path: backend/htmlcov
99-
include-hidden-files: true
88+
include-hidden-files: true

backend/app/api/routes/llm_service.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
# Helper function to prepare headers for LiteLLM
2020
def _get_litellm_headers(api_key: str | None = None) -> dict:
21+
"""Prepare headers for LiteLLM, including authorization if an API key is provided."""
2122
headers = {"Content-Type": "application/json"}
2223
if api_key: # If a specific API key is provided in the request
2324
headers["Authorization"] = f"Bearer {api_key}"
@@ -35,6 +36,22 @@ async def _forward_request_to_litellm(
3536
headers: dict | None = None,
3637
stream: bool = False
3738
):
39+
"""Asynchronously forwards a request to the LiteLLM proxy.
40+
41+
This function constructs the full URL by joining the base URL from settings
42+
with the provided endpoint path. It handles both streaming and non-streaming
43+
requests. If an HTTP status error occurs, it parses the response to extract an
44+
appropriate error message and raises an HTTPException. Network errors are
45+
caught and raised as a 503 Service Unavailable exception.
46+
47+
Args:
48+
client (httpx.AsyncClient): The asynchronous HTTP client to use for making requests.
49+
method (str): The HTTP method to use (e.g., 'GET', 'POST').
50+
endpoint_path (str): The path of the endpoint to which the request is sent.
51+
data (dict | None?): JSON data to be sent in the request body. Defaults to None.
52+
headers (dict | None?): Headers to include with the request. Defaults to None.
53+
stream (bool?): If True, the response will be streamed. Defaults to False.
54+
"""
3855
try:
3956
# Ensure proper URL joining without double slashes
4057
base_url = str(settings.LITELLM_PROXY_URL).rstrip('/')
@@ -72,6 +89,7 @@ async def _forward_request_to_litellm(
7289
async def create_completion(
7390
request_data: CompletionRequest = Body(...),
7491
):
92+
"""Handles creation of completions based on request data."""
7593
async with httpx.AsyncClient(timeout=300.0) as client: # Increased timeout for LLMs
7694
litellm_endpoint = "/chat/completions" # Common LiteLLM endpoint for chat models
7795

@@ -87,6 +105,7 @@ async def create_completion(
87105
)
88106

89107
async def event_generator():
108+
"""Generates decoded chunks from a response stream."""
90109
async for chunk in response_stream.aiter_bytes():
91110
if chunk:
92111
# LiteLLM streaming chunks are typically SSE formatted like:
@@ -141,6 +160,7 @@ async def event_generator():
141160
async def create_embedding(
142161
request_data: EmbeddingRequest = Body(...),
143162
):
163+
"""Handles the creation of embeddings by forwarding a request to LiteLLM."""
144164
async with httpx.AsyncClient(timeout=60.0) as client: # Standard timeout for embeddings
145165
litellm_endpoint = "/embeddings" # Common LiteLLM endpoint
146166
payload = request_data.model_dump(exclude_none=True)

backend/scripts/test.sh

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,7 @@ BACKEND_DIR="$( cd "$SCRIPT_DIR/.." && pwd )"
1212

1313
echo "🧪 Running backend tests with coverage..."
1414

15-
<<<<<<< HEAD
1615
# Make sure we're using the test database
17-
=======
18-
# 检测 CI 环境
19-
CI_ENV=${CI:-false}
20-
21-
# 检查环境变量是否已正确设置
22-
if [ "$TESTING" != "true" ] || [ "$TEST_MODE" != "true" ]; then
23-
if [ "$CI_ENV" = "true" ]; then
24-
echo "⚠️ CI 环境检测到,自动设置测试环境变量"
25-
export TESTING=true
26-
export TEST_MODE=true
27-
else
28-
echo "❌ 错误:必须同时设置 TESTING=true 和 TEST_MODE=true 环境变量才能运行测试"
29-
echo "当前环境变量:TESTING=$TESTING, TEST_MODE=$TEST_MODE"
30-
exit 1
31-
fi
32-
fi
33-
34-
# 确保设置测试环境变量
35-
>>>>>>> 1d6b4c6 (chore: improve test scripts for CI environment detection)
3616
export TESTING=true
3717

3818
# Enter backend directory
@@ -114,4 +94,4 @@ else
11494
echo "📊 Generating partial coverage report..."
11595
coverage report --show-missing || true
11696
exit 1
117-
fi
97+
fi

backend/scripts/tests-start.sh

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,6 @@ cd "$BACKEND_DIR"
1717

1818
# 检测 CI 环境
1919
CI_ENV=${CI:-false}
20-
<<<<<<< HEAD
21-
=======
22-
23-
# 检查环境变量是否已正确设置
24-
if [ "$TESTING" != "true" ] || [ "$TEST_MODE" != "true" ]; then
25-
if [ "$CI_ENV" = "true" ]; then
26-
echo "⚠️ CI 环境检测到,自动设置测试环境变量"
27-
export TESTING=true
28-
export TEST_MODE=true
29-
else
30-
echo "❌ 错误:必须同时设置 TESTING=true 和 TEST_MODE=true 环境变量才能运行测试"
31-
echo "当前环境变量:TESTING=$TESTING, TEST_MODE=$TEST_MODE"
32-
exit 1
33-
fi
34-
fi
35-
>>>>>>> 1d6b4c6 (chore: improve test scripts for CI environment detection)
3620

3721
# 确保设置测试环境变量
3822
export TESTING=true
@@ -121,4 +105,4 @@ TESTING=true TEST_MODE=true bash "$SCRIPT_DIR/test.sh" "$@" || {
121105
exit 1
122106
}
123107

124-
echo "✅ All tests completed successfully"
108+
echo "✅ All tests completed successfully"

extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"test": "playwright test",
1919
"test:debug": "playwright test --debug",
2020
"test:ui": "playwright test --ui",
21-
"test:e2e": "playwright test tests/e2e",
21+
"test:e2e": "playwright test",
2222
"test:coverage": "playwright test --coverage",
2323
"build:tailwind": "tailwindcss -i ./styles/globals.css -o ./styles/tailwind.css",
2424
"dev:with-tailwind": "concurrently \"npm run build:tailwind -- --watch\" \"npm run dev:local\"",

extension/playwright.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { defineConfig, devices } from '@playwright/test';
22
import path from 'path';
33

44
export default defineConfig({
5-
testDir: './tests/e2e',
5+
testDir: ['./tests/e2e', './e2e'],
66
fullyParallel: false,
77
forbidOnly: !!process.env.CI,
88
retries: process.env.CI ? 2 : 1,

frontend/components/layout/AddContentModal.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
AlertDialogAction,
1818
AlertDialogCancel,
1919
AlertDialogContent,
20+
AlertDialogDescription,
2021
AlertDialogFooter,
2122
AlertDialogHeader,
2223
AlertDialogTitle,
@@ -199,6 +200,9 @@ export const AddContentModal: FC<AddContentModalProps> = ({
199200
<X className="h-4 w-4" />
200201
</Button>
201202
</AlertDialogHeader>
203+
<AlertDialogDescription>
204+
Use this modal to add new content by pasting a URL, typing text, or uploading a file.
205+
</AlertDialogDescription>
202206

203207
<div className="space-y-6 py-4">
204208
{/* 主拖放区域 */}

frontend/jest.config.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const config: Config = {
123123
// resetModules: false,
124124

125125
// A path to a custom resolver
126-
resolver: "<rootDir>/jest.resolver.js",
126+
// resolver: "<rootDir>/jest.resolver.js",
127127

128128
// Automatically restore mock state and implementation before every test
129129
// restoreMocks: false,
@@ -162,18 +162,16 @@ const config: Config = {
162162
// testLocationInResults: false,
163163

164164
// The glob patterns Jest uses to detect test files
165-
// testMatch: [
166-
// "**/__tests__/**/*.[jt]s?(x)",
167-
// "**/?(*.)+(spec|test).[tj]s?(x)"
168-
// ],
165+
testMatch: [
166+
"**/__tests__/**/*.[jt]s?(x)",
167+
"**/?(*.)+(spec|test).[tj]s?(x)"
168+
],
169169

170170
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
171171
testPathIgnorePatterns: [
172172
"/node_modules/",
173173
"/.next/",
174-
"/.next/types/",
175174
"/tests/e2e/", // 排除Playwright e2e测试
176-
".*\\.spec\\.ts$", // 排除Playwright测试文件
177175
],
178176

179177
// The regexp pattern or array of patterns that Jest uses to detect test files

frontend/jest.setup.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
11
import "@testing-library/jest-dom";
22
import React from "react";
33

4+
// Keep a reference to the original window.location object
5+
const originalLocation = window.location;
6+
7+
beforeAll(() => {
8+
delete window.location;
9+
window.location = Object.defineProperties(
10+
{},
11+
{
12+
...Object.getOwnPropertyDescriptors(originalLocation),
13+
href: {
14+
configurable: true,
15+
writable: true, // Ensure it's writable
16+
value: 'http://localhost', // Initial mock value
17+
},
18+
assign: {
19+
configurable: true,
20+
value: jest.fn(),
21+
},
22+
replace: {
23+
configurable: true,
24+
value: jest.fn(),
25+
},
26+
pathname: {
27+
configurable: true,
28+
writable: true,
29+
value: '/',
30+
},
31+
search: {
32+
configurable: true,
33+
writable: true,
34+
value: '',
35+
},
36+
},
37+
);
38+
});
39+
40+
afterAll(() => {
41+
// Restore the original window.location object
42+
window.location = originalLocation;
43+
});
44+
45+
beforeEach(() => {
46+
// Clear mock calls between tests
47+
if (window.location.assign.mockClear) {
48+
window.location.assign.mockClear();
49+
}
50+
if (window.location.replace.mockClear) {
51+
window.location.replace.mockClear();
52+
}
53+
// Reset href to its initial mock value or a specific default for each test if needed
54+
window.location.href = 'http://localhost';
55+
window.location.pathname = '/';
56+
window.location.search = '';
57+
});
58+
459
// Add fetch mock for tests
560
global.fetch = jest.fn().mockImplementation((input, init) => {
661
// Basic mock data

0 commit comments

Comments
 (0)