Compare commits
15 Commits
fix/cors-h
...
main
| Author | SHA1 | Date |
|---|---|---|
|
|
959eef5e91 | |
|
|
fc872ff6e3 | |
|
|
478ca299d1 | |
|
|
cb525148e3 | |
|
|
8d6d615f2f | |
|
|
6593ab561a | |
|
|
24730cf757 | |
|
|
bdfdc9eecd | |
|
|
52177f7546 | |
|
|
b045694992 | |
|
|
62730a9486 | |
|
|
c22ef5a6e1 | |
|
|
f8fcffa4b6 | |
|
|
3c053c6eed | |
|
|
fd03122aa3 |
|
|
@ -12,15 +12,6 @@ on:
|
|||
- '.github/workflows/claude*.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dockerfile:
|
||||
description: 'Dockerfile to test'
|
||||
required: true
|
||||
default: 'both'
|
||||
type: choice
|
||||
options:
|
||||
- both
|
||||
- regular
|
||||
- single
|
||||
platform:
|
||||
description: 'Platform to build'
|
||||
required: true
|
||||
|
|
@ -43,7 +34,7 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Extract version from pyproject.toml
|
||||
id: version
|
||||
run: |
|
||||
|
|
@ -51,10 +42,9 @@ jobs:
|
|||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Extracted version: $VERSION"
|
||||
|
||||
test-build-regular:
|
||||
test-build:
|
||||
needs: extract-version
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.inputs.dockerfile == 'regular' || github.event.inputs.dockerfile == 'both' || github.event_name != 'workflow_dispatch'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -66,18 +56,18 @@ jobs:
|
|||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache-dev
|
||||
key: ${{ runner.os }}-buildx-dev-regular-${{ github.sha }}
|
||||
key: ${{ runner.os }}-buildx-dev-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-dev-regular-
|
||||
${{ runner.os }}-buildx-dev-
|
||||
|
||||
- name: Build regular image (test only)
|
||||
- name: Build image (test only)
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: ${{ github.event.inputs.platform || 'linux/amd64' }}
|
||||
push: false
|
||||
tags: ${{ env.IMAGE_NAME }}:${{ needs.extract-version.outputs.version }}-dev-regular
|
||||
tags: ${{ env.IMAGE_NAME }}:${{ needs.extract-version.outputs.version }}-dev
|
||||
cache-from: type=local,src=/tmp/.buildx-cache-dev
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-dev-new,mode=max
|
||||
|
||||
|
|
@ -86,43 +76,8 @@ jobs:
|
|||
rm -rf /tmp/.buildx-cache-dev
|
||||
mv /tmp/.buildx-cache-dev-new /tmp/.buildx-cache-dev
|
||||
|
||||
test-build-single:
|
||||
needs: extract-version
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.inputs.dockerfile == 'single' || github.event.inputs.dockerfile == 'both' || github.event_name != 'workflow_dispatch'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache-dev-single
|
||||
key: ${{ runner.os }}-buildx-dev-single-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-dev-single-
|
||||
|
||||
- name: Build single-container image (test only)
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.single
|
||||
platforms: ${{ github.event.inputs.platform || 'linux/amd64' }}
|
||||
push: false
|
||||
tags: ${{ env.IMAGE_NAME }}:${{ needs.extract-version.outputs.version }}-dev-single
|
||||
cache-from: type=local,src=/tmp/.buildx-cache-dev-single
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-dev-single-new,mode=max
|
||||
|
||||
- name: Move cache
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache-dev-single
|
||||
mv /tmp/.buildx-cache-dev-single-new /tmp/.buildx-cache-dev-single
|
||||
|
||||
summary:
|
||||
needs: [extract-version, test-build-regular, test-build-single]
|
||||
needs: [extract-version, test-build]
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
steps:
|
||||
|
|
@ -131,27 +86,18 @@ jobs:
|
|||
echo "## Development Build Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Version:** ${{ needs.extract-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Platform:** ${{ github.event.inputs.platform || 'linux/amd64' }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Dockerfile:** ${{ github.event.inputs.dockerfile || 'both' }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### Results:" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
if [[ "${{ needs.test-build-regular.result }}" == "success" ]]; then
|
||||
echo "✅ **Regular Dockerfile:** Build successful" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-build-regular.result }}" == "skipped" ]]; then
|
||||
echo "⏭️ **Regular Dockerfile:** Skipped" >> $GITHUB_STEP_SUMMARY
|
||||
if [[ "${{ needs.test-build.result }}" == "success" ]]; then
|
||||
echo "✅ **Dockerfile:** Build successful" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-build.result }}" == "skipped" ]]; then
|
||||
echo "⏭️ **Dockerfile:** Skipped" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "❌ **Regular Dockerfile:** Build failed" >> $GITHUB_STEP_SUMMARY
|
||||
echo "❌ **Dockerfile:** Build failed" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-build-single.result }}" == "success" ]]; then
|
||||
echo "✅ **Single Dockerfile:** Build successful" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-build-single.result }}" == "skipped" ]]; then
|
||||
echo "⏭️ **Single Dockerfile:** Skipped" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "❌ **Single Dockerfile:** Build failed" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### Notes:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- This is a development build (no images pushed to registry)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- For production releases, use the 'Build and Release' workflow" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- For production releases, use the 'Build and Release' workflow" >> $GITHUB_STEP_SUMMARY
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ name: Claude Code Review
|
|||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
types: [opened, synchronize, ready_for_review, reopened]
|
||||
# Optional: Only run on specific file changes
|
||||
# paths:
|
||||
# - "src/**/*.ts"
|
||||
|
|
@ -17,14 +17,14 @@ jobs:
|
|||
# github.event.pull_request.user.login == 'external-contributor' ||
|
||||
# github.event.pull_request.user.login == 'new-developer' ||
|
||||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -33,43 +33,12 @@ jobs:
|
|||
|
||||
- name: Run Claude Code Review
|
||||
id: claude-review
|
||||
uses: anthropics/claude-code-action@beta
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
|
||||
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
|
||||
# model: "claude-opus-4-20250514"
|
||||
|
||||
# Direct prompt for automated review (no @claude mention needed)
|
||||
direct_prompt: |
|
||||
Please review this pull request and provide feedback on:
|
||||
- Code quality and best practices
|
||||
- Potential bugs or issues
|
||||
- Performance considerations
|
||||
- Security concerns
|
||||
- Test coverage
|
||||
|
||||
Be constructive and helpful in your feedback.
|
||||
|
||||
# Optional: Customize review based on file types
|
||||
# direct_prompt: |
|
||||
# Review this PR focusing on:
|
||||
# - For TypeScript files: Type safety and proper interface usage
|
||||
# - For API endpoints: Security, input validation, and error handling
|
||||
# - For React components: Performance, accessibility, and best practices
|
||||
# - For tests: Coverage, edge cases, and test quality
|
||||
|
||||
# Optional: Different prompts for different authors
|
||||
# direct_prompt: |
|
||||
# ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' &&
|
||||
# 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' ||
|
||||
# 'Please provide a thorough code review focusing on our coding standards and best practices.' }}
|
||||
|
||||
# Optional: Add specific tools for running tests or linting
|
||||
# allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
|
||||
|
||||
# Optional: Skip review for certain conditions
|
||||
# if: |
|
||||
# !contains(github.event.pull_request.title, '[skip-review]') &&
|
||||
# !contains(github.event.pull_request.title, '[WIP]')
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
||||
plugins: 'code-review@claude-code-plugins'
|
||||
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ jobs:
|
|||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
actions: read # Required for Claude to read CI results on PRs
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -31,29 +32,19 @@ jobs:
|
|||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@beta
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
|
||||
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
|
||||
# model: "claude-opus-4-20250514"
|
||||
|
||||
# Optional: Customize the trigger phrase (default: @claude)
|
||||
# trigger_phrase: "/claude"
|
||||
|
||||
# Optional: Trigger when specific user is assigned to an issue
|
||||
# assignee_trigger: "claude-bot"
|
||||
|
||||
# Optional: Allow Claude to run specific commands
|
||||
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
|
||||
|
||||
# Optional: Add custom instructions for Claude to customize its behavior for your project
|
||||
# custom_instructions: |
|
||||
# Follow our coding standards
|
||||
# Ensure all new code has tests
|
||||
# Use TypeScript for new files
|
||||
|
||||
# Optional: Custom environment variables for Claude
|
||||
# claude_env: |
|
||||
# NODE_ENV: test
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
# This is an optional setting that allows Claude to read CI results on PRs
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
|
||||
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||
|
||||
# Optional: Add claude_args to customize behavior and configuration
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||
|
||||
|
|
|
|||
|
|
@ -98,16 +98,16 @@ async def create_model(model_data: ModelCreate):
|
|||
detail=f"Invalid model type. Must be one of: {valid_types}"
|
||||
)
|
||||
|
||||
# Check for duplicate model name under the same provider (case-insensitive)
|
||||
# Check for duplicate model name under the same provider and type (case-insensitive)
|
||||
from open_notebook.database.repository import repo_query
|
||||
existing = await repo_query(
|
||||
"SELECT * FROM model WHERE string::lowercase(provider) = $provider AND string::lowercase(name) = $name LIMIT 1",
|
||||
{"provider": model_data.provider.lower(), "name": model_data.name.lower()}
|
||||
"SELECT * FROM model WHERE string::lowercase(provider) = $provider AND string::lowercase(name) = $name AND string::lowercase(type) = $type LIMIT 1",
|
||||
{"provider": model_data.provider.lower(), "name": model_data.name.lower(), "type": model_data.type.lower()}
|
||||
)
|
||||
if existing:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Model '{model_data.name}' already exists for provider '{model_data.provider}'"
|
||||
detail=f"Model '{model_data.name}' already exists for provider '{model_data.provider}' with type '{model_data.type}'"
|
||||
)
|
||||
|
||||
new_model = Model(
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ Create a new folder `open-notebook` and add this file:
|
|||
services:
|
||||
surrealdb:
|
||||
image: surrealdb/surrealdb:v2
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 memory
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 rocksdb:/mydata/mydatabase.db
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./surreal_data:/mydata
|
||||
|
||||
open_notebook:
|
||||
image: lfnovo/open_notebook:v1-latest
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ Create a new folder `open-notebook-local` and add this file:
|
|||
services:
|
||||
surrealdb:
|
||||
image: surrealdb/surrealdb:v2
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 memory
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 rocksdb:/mydata/mydatabase.db
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./surreal_data:/mydata
|
||||
|
||||
open_notebook:
|
||||
image: lfnovo/open_notebook:v1-latest-single
|
||||
|
|
@ -68,6 +70,7 @@ services:
|
|||
# Optional: set GPU support if available
|
||||
- OLLAMA_NUM_GPU=0
|
||||
restart: always
|
||||
|
||||
```
|
||||
|
||||
**That's it!** No API keys, no secrets, completely private.
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ Create a new folder `open-notebook` and add this file:
|
|||
services:
|
||||
surrealdb:
|
||||
image: surrealdb/surrealdb:v2
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 memory
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 rocksdb:/mydata/mydatabase.db
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./surreal_data:/mydata
|
||||
|
||||
open_notebook:
|
||||
image: lfnovo/open_notebook:v1-latest
|
||||
|
|
@ -48,6 +50,7 @@ services:
|
|||
depends_on:
|
||||
- surrealdb
|
||||
restart: always
|
||||
|
||||
```
|
||||
|
||||
**Edit the file:**
|
||||
|
|
|
|||
|
|
@ -36,11 +36,11 @@ Create a folder `open-notebook` and add this file:
|
|||
services:
|
||||
surrealdb:
|
||||
image: surrealdb/surrealdb:v2
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 memory
|
||||
command: start --user root --pass password --bind 0.0.0.0:8000 rocksdb:/mydata/mydatabase.db
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- surreal_data:/mydata
|
||||
- ./surreal_data:/mydata
|
||||
|
||||
open_notebook:
|
||||
image: lfnovo/open_notebook:v1-latest
|
||||
|
|
@ -66,8 +66,6 @@ services:
|
|||
- surrealdb
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
surreal_data:
|
||||
```
|
||||
|
||||
**Edit the file:**
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ const nextConfig: NextConfig = {
|
|||
output: "standalone",
|
||||
|
||||
// Experimental features
|
||||
// Type assertion needed: proxyClientMaxBodySize is valid in Next.js 15 but types lag behind
|
||||
experimental: {
|
||||
// Increase proxy body size limit for file uploads (default is 10MB)
|
||||
// This allows larger files to be uploaded through the /api/* rewrite proxy to FastAPI
|
||||
proxyClientMaxBodySize: '100mb',
|
||||
},
|
||||
} as NextConfig['experimental'],
|
||||
|
||||
// API Rewrites: Proxy /api/* requests to FastAPI backend
|
||||
// This simplifies reverse proxy configuration - users only need to proxy to port 8502
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class TestModelCreation:
|
|||
assert response.status_code == 400
|
||||
assert (
|
||||
response.json()["detail"]
|
||||
== "Model 'gpt-4' already exists for provider 'openai'"
|
||||
== "Model 'gpt-4' already exists for provider 'openai' with type 'language'"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -70,7 +70,7 @@ class TestModelCreation:
|
|||
assert response.status_code == 400
|
||||
assert (
|
||||
response.json()["detail"]
|
||||
== "Model 'GPT-4' already exists for provider 'OpenAI'"
|
||||
== "Model 'GPT-4' already exists for provider 'OpenAI' with type 'language'"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -95,6 +95,28 @@ class TestModelCreation:
|
|||
# Should succeed because provider is different
|
||||
assert response.status_code == 200
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("open_notebook.database.repository.repo_query")
|
||||
async def test_create_same_model_name_different_type(
|
||||
self, mock_repo_query, client
|
||||
):
|
||||
"""Test that creating a model with same name but different type is allowed."""
|
||||
from open_notebook.ai.models import Model
|
||||
|
||||
# Mock repo_query to return empty (no duplicate found for different type)
|
||||
mock_repo_query.return_value = []
|
||||
|
||||
# Patch the save method on the Model class
|
||||
with patch.object(Model, "save", new_callable=AsyncMock) as mock_save:
|
||||
# Attempt to create same model name with different type (embedding instead of language)
|
||||
response = client.post(
|
||||
"/api/models",
|
||||
json={"name": "gpt-4", "provider": "openai", "type": "embedding"},
|
||||
)
|
||||
|
||||
# Should succeed because type is different
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
class TestModelsProviderAvailability:
|
||||
"""Test suite for Models Provider Availability endpoint."""
|
||||
|
|
|
|||
Loading…
Reference in New Issue