fix: register task_request handler and fix Docker 403 errors on macOS (#86)

This commit is contained in:
Alexander Whitestone
2026-02-28 07:39:31 -05:00
committed by GitHub
parent da5745db48
commit add3f7a07a
4 changed files with 96 additions and 0 deletions

View File

@@ -46,6 +46,11 @@ RUN mkdir -p /app/data
# ── Non-root user for production ─────────────────────────────────────────────
RUN groupadd -r timmy && useradd -r -g timmy -d /app -s /sbin/nologin timmy \
&& chown -R timmy:timmy /app
# Ensure static/ and data/ are world-readable so bind-mounted files
# from the macOS host remain accessible when running as the timmy user.
# Docker Desktop for Mac bind mounts inherit host permissions, which may
# not include the container's timmy UID — chmod o+rX fixes 403 errors.
RUN chmod -R o+rX /app/static /app/data
USER timmy
# ── Environment ──────────────────────────────────────────────────────────────

View File

@@ -22,6 +22,12 @@ services:
build: .
image: timmy-time:latest
container_name: timmy-dashboard
# Run as root in the dev compose because bind-mounted host files
# (./src, ./static) may not be readable by the image's non-root
# "timmy" user — this is the #1 cause of 403 errors on macOS.
# Production (docker-compose.prod.yml) uses no bind mounts and
# correctly runs as the Dockerfile's non-root USER.
user: "0:0"
ports:
- "8000:8000"
volumes:

View File

@@ -231,11 +231,53 @@ async def _task_processor_loop() -> None:
"""Handler for bug_report tasks - acknowledge and mark completed."""
return f"Bug report acknowledged: {task.title}"
def handle_task_request(task):
"""Handler for task_request tasks — user-queued work items from chat."""
try:
now = datetime.now()
context = (
f"[System: Current date/time is {now.strftime('%A, %B %d, %Y at %I:%M %p')}]\n"
f"[System: You have been assigned a task from the queue. "
f"Complete it and provide your response.]\n\n"
f"Task: {task.title}\n"
)
if task.description and task.description != task.title:
context += f"Details: {task.description}\n"
response = timmy_chat(context)
# Push response to user via WebSocket
try:
from infrastructure.ws_manager.handler import ws_manager
asyncio.create_task(
ws_manager.broadcast(
"timmy_response",
{
"task_id": task.id,
"response": response,
},
)
)
except Exception as e:
logger.debug("Failed to push response via WS: %s", e)
return response
except Exception as e:
logger.error("Task request failed: %s", e)
try:
from infrastructure.error_capture import capture_error
capture_error(e, source="task_request_handler")
except Exception:
pass
return f"Error: {str(e)}"
# Register handlers
task_processor.register_handler("chat_response", handle_chat_response)
task_processor.register_handler("thought", handle_thought)
task_processor.register_handler("internal", handle_thought)
task_processor.register_handler("bug_report", handle_bug_report)
task_processor.register_handler("task_request", handle_task_request)
# ── Reconcile zombie tasks from previous crash ──
zombie_count = task_processor.reconcile_zombie_tasks()

View File

@@ -876,6 +876,49 @@ class TestTaskProcessor:
refreshed = get_task(task.id)
assert refreshed.status == TaskStatus.APPROVED
@pytest.mark.asyncio
async def test_task_request_type_has_handler(self):
"""task_request tasks are processed (not backlogged) when a handler is registered.
Regression test: previously task_request had no handler, causing all
user-queued tasks from chat to be immediately backlogged.
"""
from swarm.task_processor import TaskProcessor
from swarm.task_queue.models import create_task, get_task, TaskStatus
tp = TaskProcessor("task-request-test")
tp.register_handler("task_request", lambda task: f"Completed: {task.title}")
task = create_task(
title="Refactor the login module",
description="Create a task to refactor the login module",
task_type="task_request",
assigned_to="task-request-test",
created_by="user",
)
result = await tp.process_single_task(task)
assert result is not None
refreshed = get_task(task.id)
assert refreshed.status == TaskStatus.COMPLETED
assert "Refactor" in refreshed.result
def test_chat_queue_request_creates_task_request_type(self, client):
"""Chat messages that match queue patterns create task_request tasks."""
from swarm.task_queue.models import list_tasks
client.post(
"/agents/timmy/chat",
data={"message": "Add refactor the login module to the task queue"},
)
tasks = list_tasks(assigned_to="timmy")
task_request_tasks = [t for t in tasks if t.task_type == "task_request"]
assert len(task_request_tasks) >= 1
assert any("login" in t.title.lower() or "refactor" in t.title.lower()
for t in task_request_tasks)
# ── Backlog Route Tests ─────────────────────────────────────────────────