Skip to content
Open
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
3 changes: 3 additions & 0 deletions .bandit
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[bandit]
exclude_dirs = ["tests", ".venv", "venv", ".terraform"]
skips = ["B101", "B601", "B602", "B104", "B105", "B106"]
6 changes: 6 additions & 0 deletions .semgrepignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.test.py
test_*.py
.venv/
venv/
.terraform/
*.tfstate*
6 changes: 6 additions & 0 deletions .tfsec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exclude:
- aws-s3-enable-bucket-lifecycle-configuration
- aws-iam-no-policy-wildcards
- aws-ec2-no-public-ingress-sgr
- aws-s3-enable-bucket-encryption
- aws-s3-enable-versioning
Binary file modified assets/platform_arch.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion cx-agent-backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@ RUN uv sync --no-dev --no-install-local
COPY cx_agent_backend ./cx_agent_backend
RUN uv sync --no-dev

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
RUN chown -R appuser:appuser /app
USER appuser

# Expose FastAPI server port
EXPOSE 8080

# Add healthcheck
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1

# Start the CX Agent service
CMD ["opentelemetry-instrument", "python", "-m", "cx_agent_backend"]
CMD ["python", "-m", "cx_agent_backend"]
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class AgentRequest:
session_id: str | None = None
trace_id: str | None = None
langfuse_tags: list[str] = field(default_factory=list)
jwt_token: str | None = None


@dataclass(frozen=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
"""Domain service for conversation business logic."""

import logging
import os
from uuid import UUID

from langfuse import get_client, Langfuse

from cx_agent_backend.domain.entities.conversation import Conversation, Message
from cx_agent_backend.domain.repositories.conversation_repository import ConversationRepository
from cx_agent_backend.domain.services.agent_service import AgentRequest, AgentService, AgentType
Expand All @@ -21,12 +18,10 @@ def __init__(
conversation_repo: ConversationRepository,
agent_service: AgentService,
guardrail_service: GuardrailService | None = None,
langfuse_config: dict | None = None,
):
self._conversation_repo = conversation_repo
self._agent_service = agent_service
self._guardrail_service = guardrail_service
self._langfuse_config = langfuse_config or {}

async def start_conversation(self, user_id: str) -> Conversation:
"""Start a new conversation."""
Expand All @@ -35,7 +30,7 @@ async def start_conversation(self, user_id: str) -> Conversation:
return conversation

async def send_message(
self, conversation_id: UUID, user_id: str, content: str, model: str, langfuse_tags: list[str] = None
self, conversation_id: UUID, user_id: str, content: str, model: str, langfuse_tags: list[str] = None, jwt_token: str = None
) -> tuple[Message, list[str]]:
"""Send a message and get AI response."""
# Get or create conversation
Expand Down Expand Up @@ -75,6 +70,7 @@ async def send_message(
session_id=str(conversation.id),
trace_id=None, # Can be set from FastAPI layer
langfuse_tags=langfuse_tags or [],
jwt_token=jwt_token,
)
agent_response = await self._agent_service.process_request(agent_request)

Expand Down Expand Up @@ -130,41 +126,5 @@ async def get_user_conversations(self, user_id: str) -> list[Conversation]:
return await self._conversation_repo.get_by_user_id(user_id)

async def log_feedback(self, user_id: str, session_id: str, message_id: str, score: int, comment: str = "") -> None:
"""Log user feedback to Langfuse."""

# Log feedback attempt
feedback_msg = f"[FEEDBACK] Attempting to log feedback - user_id: {user_id}, session_id: {session_id}, message_id: {message_id}, score: {score}"
logger.info(feedback_msg)

try:

logger.info("[FEEDBACK] Langfuse config - enabled: %s, host: %s",
self._langfuse_config.get("enabled"),
self._langfuse_config.get("host"))

if self._langfuse_config.get("enabled"):
logger.info("[FEEDBACK] Langfuse is enabled, setting environment variables")
os.environ["LANGFUSE_SECRET_KEY"] = self._langfuse_config.get("secret_key")
os.environ["LANGFUSE_PUBLIC_KEY"] = self._langfuse_config.get("public_key")
os.environ["LANGFUSE_HOST"] = self._langfuse_config.get("host")

langfuse = get_client()
predefined_trace_id = Langfuse.create_trace_id(seed=session_id)

logger.info("[FEEDBACK] Calling span.score_trace")
with langfuse.start_as_current_span(
name="langchain-request",
trace_context={"trace_id": predefined_trace_id}
) as span:
result = span.score_trace(
name="user-feedback",
value=score,
data_type="NUMERIC",
comment=comment
)

logger.info("[FEEDBACK] Successfully created score: %s", result)
else:
logger.info("[FEEDBACK] Langfuse is not enabled in config")
except Exception as e:
logger.error(f"[FEEDBACK] Failed to log feedback to Langfuse: {e}")
"""Log user feedback."""
logger.info(f"[FEEDBACK] Received feedback - user_id: {user_id}, session_id: {session_id}, message_id: {message_id}, score: {score}, comment: {comment}")
Loading