mirror of
https://github.com/Monadical-SAS/cubbi.git
synced 2025-12-20 20:29:06 +00:00
fix(langfuse): fix goose langfuse integration (wrong env variables)
This commit is contained in:
@@ -229,8 +229,9 @@ logging:
|
|||||||
- type: fluentd
|
- type: fluentd
|
||||||
url: http://fluentd.example.com:24224
|
url: http://fluentd.example.com:24224
|
||||||
- type: langfuse
|
- type: langfuse
|
||||||
url: https://api.langfuse.com
|
url: https://cloud.langfuse.com
|
||||||
apiKey: ${LANGFUSE_API_KEY}
|
public_key: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY}
|
||||||
|
secret_key: ${LANGFUSE_INIT_PROJECT_SECRET_KEY}
|
||||||
|
|
||||||
drivers:
|
drivers:
|
||||||
- name: goose
|
- name: goose
|
||||||
@@ -277,6 +278,43 @@ The MC Service implements log collection and forwarding:
|
|||||||
|
|
||||||
## Project Management
|
## Project Management
|
||||||
|
|
||||||
|
### Persistent Project Configuration
|
||||||
|
|
||||||
|
MC provides persistent storage for project-specific configurations that need to survive container restarts. This is implemented through a dedicated volume mount and symlink system:
|
||||||
|
|
||||||
|
1. **Configuration Storage**:
|
||||||
|
- Each project has a dedicated configuration directory on the host at `~/.mc/projects/<project-hash>/config`
|
||||||
|
- For projects specified by URL, the hash is derived from the repository URL
|
||||||
|
- For local projects, the hash is derived from the absolute path of the local directory
|
||||||
|
- This directory is mounted into the container at `/mc-config`
|
||||||
|
|
||||||
|
2. **Driver Configuration**:
|
||||||
|
- Each driver can specify configuration files/directories that should persist across sessions
|
||||||
|
- These are defined in the driver's `mc-driver.yaml` file in the `persistent_configs` section
|
||||||
|
- Example for Goose driver:
|
||||||
|
```yaml
|
||||||
|
persistent_configs:
|
||||||
|
- source: "/app/.goose" # Path in container
|
||||||
|
target: "/mc-config/goose" # Path in persistent storage
|
||||||
|
type: "directory" # directory or file
|
||||||
|
description: "Goose memory and configuration"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Automatic Symlinking**:
|
||||||
|
- During container initialization, the system:
|
||||||
|
- Creates all target directories in the persistent storage
|
||||||
|
- Creates symlinks from the source paths to the target paths
|
||||||
|
- This makes the persistence transparent to the application
|
||||||
|
|
||||||
|
4. **Environment Variables**:
|
||||||
|
- Container has access to configuration location via environment variables:
|
||||||
|
```
|
||||||
|
MC_CONFIG_DIR=/mc-config
|
||||||
|
MC_DRIVER_CONFIG_DIR=/mc-config/<driver-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
This ensures that important configurations like Goose's memory store, authentication tokens, and other state information persist between container sessions while maintaining isolation between different projects.
|
||||||
|
|
||||||
### Adding Projects
|
### Adding Projects
|
||||||
|
|
||||||
Users can add projects with associated credentials:
|
Users can add projects with associated credentials:
|
||||||
@@ -415,6 +453,12 @@ ports:
|
|||||||
volumes:
|
volumes:
|
||||||
- mountPath: /app
|
- mountPath: /app
|
||||||
description: Application directory
|
description: Application directory
|
||||||
|
|
||||||
|
persistent_configs:
|
||||||
|
- source: "/app/.goose"
|
||||||
|
target: "/mc-config/goose"
|
||||||
|
type: "directory"
|
||||||
|
description: "Goose memory and configuration"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example Built-in Drivers
|
### Example Built-in Drivers
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ This driver provides a containerized environment for running [Goose](https://goo
|
|||||||
| Variable | Description | Required |
|
| Variable | Description | Required |
|
||||||
|----------|-------------|----------|
|
|----------|-------------|----------|
|
||||||
| `MCP_HOST` | MCP server host | Yes |
|
| `MCP_HOST` | MCP server host | Yes |
|
||||||
| `GOOSE_API_KEY` | Goose API key | Yes |
|
| `LANGFUSE_INIT_PROJECT_PUBLIC_KEY` | Langfuse public key | No |
|
||||||
| `GOOSE_ID` | Goose instance ID | No |
|
| `LANGFUSE_INIT_PROJECT_SECRET_KEY` | Langfuse secret key | No |
|
||||||
| `LANGFUSE_PUBLIC_KEY` | Langfuse public key | No |
|
| `LANGFUSE_URL` | Langfuse API URL | No |
|
||||||
| `LANGFUSE_SECRET_KEY` | Langfuse secret key | No |
|
|
||||||
| `LANGFUSE_HOST` | Langfuse API host | No |
|
|
||||||
| `MC_PROJECT_URL` | Project repository URL | No |
|
| `MC_PROJECT_URL` | Project repository URL | No |
|
||||||
| `MC_GIT_SSH_KEY` | SSH key for Git authentication | No |
|
| `MC_GIT_SSH_KEY` | SSH key for Git authentication | No |
|
||||||
| `MC_GIT_TOKEN` | Token for Git authentication | No |
|
| `MC_GIT_TOKEN` | Token for Git authentication | No |
|
||||||
|
|||||||
@@ -13,29 +13,20 @@ environment:
|
|||||||
required: true
|
required: true
|
||||||
default: http://localhost:8000
|
default: http://localhost:8000
|
||||||
|
|
||||||
- name: GOOSE_API_KEY
|
- name: LANGFUSE_INIT_PROJECT_PUBLIC_KEY
|
||||||
description: Goose API key
|
|
||||||
required: true
|
|
||||||
sensitive: true
|
|
||||||
|
|
||||||
- name: GOOSE_ID
|
|
||||||
description: Goose instance ID
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- name: LANGFUSE_PUBLIC_KEY
|
|
||||||
description: Langfuse public key
|
description: Langfuse public key
|
||||||
required: false
|
required: false
|
||||||
sensitive: true
|
sensitive: true
|
||||||
|
|
||||||
- name: LANGFUSE_SECRET_KEY
|
- name: LANGFUSE_INIT_PROJECT_SECRET_KEY
|
||||||
description: Langfuse secret key
|
description: Langfuse secret key
|
||||||
required: false
|
required: false
|
||||||
sensitive: true
|
sensitive: true
|
||||||
|
|
||||||
- name: LANGFUSE_HOST
|
- name: LANGFUSE_URL
|
||||||
description: Langfuse API host
|
description: Langfuse API URL
|
||||||
required: false
|
required: false
|
||||||
default: https://api.langfuse.com
|
default: https://cloud.langfuse.com
|
||||||
|
|
||||||
# Project environment variables
|
# Project environment variables
|
||||||
- name: MC_PROJECT_URL
|
- name: MC_PROJECT_URL
|
||||||
@@ -63,4 +54,10 @@ ports:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- mountPath: /app
|
- mountPath: /app
|
||||||
description: Application directory
|
description: Application directory
|
||||||
|
|
||||||
|
persistent_configs:
|
||||||
|
- source: "/app/.goose"
|
||||||
|
target: "/mc-config/goose"
|
||||||
|
type: "directory"
|
||||||
|
description: "Goose memory and configuration"
|
||||||
@@ -8,6 +8,26 @@ exec > >(tee -a /init.log) 2>&1
|
|||||||
echo "=== MC Initialization started at $(date) ==="
|
echo "=== MC Initialization started at $(date) ==="
|
||||||
echo "INIT_COMPLETE=false" > /init.status
|
echo "INIT_COMPLETE=false" > /init.status
|
||||||
|
|
||||||
|
# Set up persistent configuration symlinks
|
||||||
|
if [ -n "$MC_CONFIG_DIR" ] && [ -d "$MC_CONFIG_DIR" ]; then
|
||||||
|
echo "Setting up persistent configuration in $MC_CONFIG_DIR"
|
||||||
|
|
||||||
|
# Create Goose configuration directory
|
||||||
|
mkdir -p "$MC_CONFIG_DIR/goose"
|
||||||
|
|
||||||
|
# Create symlink for Goose directory
|
||||||
|
if [ -d "/app" ]; then
|
||||||
|
# Make sure .goose directory exists in the target
|
||||||
|
mkdir -p "$MC_CONFIG_DIR/goose"
|
||||||
|
|
||||||
|
# Create the symlink
|
||||||
|
echo "Creating symlink for Goose configuration: /app/.goose -> $MC_CONFIG_DIR/goose"
|
||||||
|
ln -sf "$MC_CONFIG_DIR/goose" "/app/.goose"
|
||||||
|
else
|
||||||
|
echo "Warning: /app directory does not exist yet, symlinks will be created after project initialization"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Project initialization
|
# Project initialization
|
||||||
if [ -n "$MC_PROJECT_URL" ]; then
|
if [ -n "$MC_PROJECT_URL" ]; then
|
||||||
echo "Initializing project: $MC_PROJECT_URL"
|
echo "Initializing project: $MC_PROJECT_URL"
|
||||||
@@ -36,13 +56,21 @@ if [ -n "$MC_PROJECT_URL" ]; then
|
|||||||
if [ -f "/app/.mc/init.sh" ]; then
|
if [ -f "/app/.mc/init.sh" ]; then
|
||||||
bash /app/.mc/init.sh
|
bash /app/.mc/init.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Set up symlinks after project is cloned (if MC_CONFIG_DIR exists)
|
||||||
|
if [ -n "$MC_CONFIG_DIR" ] && [ -d "$MC_CONFIG_DIR" ]; then
|
||||||
|
echo "Setting up persistent configuration symlinks after project clone"
|
||||||
|
|
||||||
|
# Create Goose configuration directory
|
||||||
|
mkdir -p "$MC_CONFIG_DIR/goose"
|
||||||
|
|
||||||
|
# Create symlink for Goose directory
|
||||||
|
echo "Creating symlink for Goose configuration: /app/.goose -> $MC_CONFIG_DIR/goose"
|
||||||
|
ln -sf "$MC_CONFIG_DIR/goose" "/app/.goose"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set up Goose API key if provided
|
# Goose uses self-hosted instance, no API key required
|
||||||
if [ -n "$GOOSE_API_KEY" ]; then
|
|
||||||
echo "Setting up Goose API key"
|
|
||||||
export GOOSE_API_KEY="$GOOSE_API_KEY"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set up MCP connection if provided
|
# Set up MCP connection if provided
|
||||||
if [ -n "$MCP_HOST" ]; then
|
if [ -n "$MCP_HOST" ]; then
|
||||||
@@ -51,11 +79,11 @@ if [ -n "$MCP_HOST" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Set up Langfuse logging if credentials are provided
|
# Set up Langfuse logging if credentials are provided
|
||||||
if [ -n "$LANGFUSE_SECRET_KEY" ] && [ -n "$LANGFUSE_PUBLIC_KEY" ]; then
|
if [ -n "$LANGFUSE_INIT_PROJECT_SECRET_KEY" ] && [ -n "$LANGFUSE_INIT_PROJECT_PUBLIC_KEY" ]; then
|
||||||
echo "Setting up Langfuse logging"
|
echo "Setting up Langfuse logging"
|
||||||
export LANGFUSE_SECRET_KEY="$LANGFUSE_SECRET_KEY"
|
export LANGFUSE_INIT_PROJECT_SECRET_KEY="$LANGFUSE_INIT_PROJECT_SECRET_KEY"
|
||||||
export LANGFUSE_PUBLIC_KEY="$LANGFUSE_PUBLIC_KEY"
|
export LANGFUSE_INIT_PROJECT_PUBLIC_KEY="$LANGFUSE_INIT_PROJECT_PUBLIC_KEY"
|
||||||
export LANGFUSE_HOST="${LANGFUSE_HOST:-https://api.langfuse.com}"
|
export LANGFUSE_URL="${LANGFUSE_URL:-https://cloud.langfuse.com}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "MC driver initialization complete"
|
echo "MC driver initialization complete"
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
import docker
|
import docker
|
||||||
|
import hashlib
|
||||||
|
import pathlib
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
from docker.errors import DockerException, ImageNotFound
|
from docker.errors import DockerException, ImageNotFound
|
||||||
@@ -32,6 +34,38 @@ class ContainerManager:
|
|||||||
"""Generate a unique session ID"""
|
"""Generate a unique session ID"""
|
||||||
return str(uuid.uuid4())[:8]
|
return str(uuid.uuid4())[:8]
|
||||||
|
|
||||||
|
def _get_project_config_path(self, project: Optional[str] = None) -> pathlib.Path:
|
||||||
|
"""Get the path to the project configuration directory
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project: Optional project repository URL. If None, uses current directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path to the project configuration directory
|
||||||
|
"""
|
||||||
|
# Get home directory for the MC config
|
||||||
|
mc_home = pathlib.Path.home() / ".mc"
|
||||||
|
|
||||||
|
# If no project URL is provided, use the current directory path
|
||||||
|
if not project:
|
||||||
|
# Use current working directory as project identifier
|
||||||
|
project_id = os.getcwd()
|
||||||
|
else:
|
||||||
|
# Use project URL as identifier
|
||||||
|
project_id = project
|
||||||
|
|
||||||
|
# Create a hash of the project ID to use as directory name
|
||||||
|
project_hash = hashlib.md5(project_id.encode()).hexdigest()
|
||||||
|
|
||||||
|
# Create the project config directory path
|
||||||
|
config_path = mc_home / "projects" / project_hash / "config"
|
||||||
|
|
||||||
|
# Create the directory if it doesn't exist
|
||||||
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
config_path.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
return config_path
|
||||||
|
|
||||||
def list_sessions(self) -> List[Session]:
|
def list_sessions(self) -> List[Session]:
|
||||||
"""List all active MC sessions"""
|
"""List all active MC sessions"""
|
||||||
sessions = []
|
sessions = []
|
||||||
@@ -124,7 +158,14 @@ class ContainerManager:
|
|||||||
env_vars["MC_PROJECT_URL"] = project
|
env_vars["MC_PROJECT_URL"] = project
|
||||||
|
|
||||||
# Pass API keys from host environment to container for local development
|
# Pass API keys from host environment to container for local development
|
||||||
api_keys = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "OPENROUTER_API_KEY"]
|
api_keys = [
|
||||||
|
"OPENAI_API_KEY",
|
||||||
|
"ANTHROPIC_API_KEY",
|
||||||
|
"OPENROUTER_API_KEY",
|
||||||
|
"LANGFUSE_INIT_PROJECT_PUBLIC_KEY",
|
||||||
|
"LANGFUSE_INIT_PROJECT_SECRET_KEY",
|
||||||
|
"LANGFUSE_URL",
|
||||||
|
]
|
||||||
for key in api_keys:
|
for key in api_keys:
|
||||||
if key in os.environ and key not in env_vars:
|
if key in os.environ and key not in env_vars:
|
||||||
env_vars[key] = os.environ[key]
|
env_vars[key] = os.environ[key]
|
||||||
@@ -150,6 +191,36 @@ class ContainerManager:
|
|||||||
f"Project URL provided - container will clone {project} into /app during initialization"
|
f"Project URL provided - container will clone {project} into /app during initialization"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Set up persistent project configuration
|
||||||
|
project_config_path = self._get_project_config_path(project)
|
||||||
|
print(f"Using project configuration directory: {project_config_path}")
|
||||||
|
|
||||||
|
# Mount the project configuration directory
|
||||||
|
volumes[str(project_config_path)] = {"bind": "/mc-config", "mode": "rw"}
|
||||||
|
|
||||||
|
# Add environment variables for config path
|
||||||
|
env_vars["MC_CONFIG_DIR"] = "/mc-config"
|
||||||
|
env_vars["MC_DRIVER_CONFIG_DIR"] = f"/mc-config/{driver_name}"
|
||||||
|
|
||||||
|
# Create driver-specific config directories
|
||||||
|
if driver.persistent_configs:
|
||||||
|
print("Setting up persistent configuration directories:")
|
||||||
|
for config in driver.persistent_configs:
|
||||||
|
# Get target directory path on host
|
||||||
|
target_dir = project_config_path / config.target.lstrip(
|
||||||
|
"/mc-config/"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create directory if it's a directory type config
|
||||||
|
if config.type == "directory":
|
||||||
|
target_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
print(f" - Created directory: {target_dir}")
|
||||||
|
|
||||||
|
# For files, make sure parent directory exists
|
||||||
|
elif config.type == "file":
|
||||||
|
target_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
# File will be created by the container if needed
|
||||||
|
|
||||||
# Create container
|
# Create container
|
||||||
container = self.client.containers.create(
|
container = self.client.containers.create(
|
||||||
image=driver.image,
|
image=driver.image,
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ class DriverEnvironmentVariable(BaseModel):
|
|||||||
sensitive: bool = False
|
sensitive: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class PersistentConfig(BaseModel):
|
||||||
|
source: str
|
||||||
|
target: str
|
||||||
|
type: str # "directory" or "file"
|
||||||
|
description: str = ""
|
||||||
|
|
||||||
|
|
||||||
class Driver(BaseModel):
|
class Driver(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
description: str
|
description: str
|
||||||
@@ -27,6 +34,7 @@ class Driver(BaseModel):
|
|||||||
environment: List[DriverEnvironmentVariable] = []
|
environment: List[DriverEnvironmentVariable] = []
|
||||||
ports: List[int] = []
|
ports: List[int] = []
|
||||||
volumes: List[Dict[str, str]] = []
|
volumes: List[Dict[str, str]] = []
|
||||||
|
persistent_configs: List[PersistentConfig] = []
|
||||||
|
|
||||||
|
|
||||||
class Session(BaseModel):
|
class Session(BaseModel):
|
||||||
|
|||||||
Reference in New Issue
Block a user