From 8b1398db69e36e51347d80889a3de206070c12f0 Mon Sep 17 00:00:00 2001 From: EgonBot Date: Thu, 26 Feb 2026 21:39:23 +0000 Subject: [PATCH 01/44] docs: add implementation proposals for Egon (SSE) and Bubba (webhooks) --- docs/proposals/bubba-webhook-notifications.md | 86 +++++++++++++++++++ docs/proposals/egon-sse-progress-streaming.md | 65 ++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 docs/proposals/bubba-webhook-notifications.md create mode 100644 docs/proposals/egon-sse-progress-streaming.md diff --git a/docs/proposals/bubba-webhook-notifications.md b/docs/proposals/bubba-webhook-notifications.md new file mode 100644 index 00000000..a25970cc --- /dev/null +++ b/docs/proposals/bubba-webhook-notifications.md @@ -0,0 +1,86 @@ +# Webhook Notifications — Implementation Plan + +**Assignee:** Bubba +**Feature:** 5.2 from MCP Interface Roadmap +**Target:** PlanExeOrg/PlanExe repository + +## Problem + +Users must poll `plan_status` to know when a plan completes. This is inefficient for long-running plans and doesn't support CI/CD integrations. + +## Proposed Solution + +Add optional `webhook_url` parameter to `plan_create`. When the plan transitions to `completed` or `failed`, POST a JSON payload to that URL. + +## Technical Scope + +### Files to Modify + +| File | Changes | +|------|---------| +| `mcp_cloud/schemas.py` | Add `webhook_url: Optional[str]` to `PlanCreateInput` | +| `mcp_cloud/handlers.py` | Pass `webhook_url` to plan creation; trigger webhook on completion | +| `worker_plan/worker_plan_api.py` | Emit event when plan completes (for webhook dispatch) | +| `mcp_cloud/webhooks.py` | NEW: Handle async webhook delivery with retry logic | + +### Schema Change + +```python +class PlanCreateInput(BaseModel): + prompt: str + model_profile: Optional[str] = "baseline" + user_api_key: Optional[str] = None + webhook_url: Optional[str] = None # NEW +``` + +### Payload POSTed to webhook_url + +```json +{ + "plan_id": "uuid", + "state": "completed", + "progress_percentage": 100, + "created_at": "2026-02-26T12:00:00Z", + "completed_at": "2026-02-26T12:15:00Z", + "result": { ... }, + "error": null +} +``` + +### Implementation Steps + +1. **Add schema:** Include `webhook_url` in `PlanCreateInput` +2. **Store webhook:** Persist `webhook_url` in `plan_metadata` column +3. **Emit event:** In worker, call webhook dispatcher when plan reaches terminal state +4. **Create dispatcher:** `webhooks.py` with POST + retry (3 attempts, exponential backoff) +5. **Log results:** Record webhook delivery status in `plan_metadata` +6. **Test:** Create plan with webhook_url, verify POST received + +### Security Considerations + +- Validate `webhook_url` is HTTPS (or localhost for dev) +- Add `webhook_secret` header for receiver validation +- Rate limit webhook dispatch to prevent abuse + +### Edge Cases + +- If webhook URL unreachable: log error, don't fail the plan +- If plan is stopped via `plan_stop`: optionally send "cancelled" state +- If user provides invalid URL: fail at plan creation with validation error + +## Success Criteria + +- `plan_create` accepts `webhook_url` parameter +- Plan completion triggers POST to URL within 30 seconds +- Retry logic handles transient failures (3 retries, exponential backoff) +- Webhook delivery status logged for debugging + +## Effort Estimate + +~4–5 hours +PR type: implementation (not docs-only) + +## Notes + +- This can be done in parallel with Egon's SSE work (different files, no conflicts) +- Bubba should coordinate with Simon on whether webhook secrets are needed diff --git a/docs/proposals/egon-sse-progress-streaming.md b/docs/proposals/egon-sse-progress-streaming.md new file mode 100644 index 00000000..237f0fb3 --- /dev/null +++ b/docs/proposals/egon-sse-progress-streaming.md @@ -0,0 +1,65 @@ +# SSE Progress Streaming — Implementation Plan + +**Assignee:** Egon +**Feature:** 5.1 from MCP Interface Roadmap +**Target:** PlanExeOrg/PlanExe repository + +## Problem + +Users running long plans (10–20 minutes) get zero feedback until completion. They see only `"state": "processing"` with no visibility into what the agent is doing. + +## Proposed Solution + +Add a `log_lines` array to the `plan_status` response containing the last N lines of agent stdout/stderr (tail). This gives users live feedback without polling complexity. + +## Technical Scope + +### Files to Modify + +| File | Changes | +|------|---------| +| `mcp_cloud/schemas.py` | Add `log_lines: list[str]` to `PlanStatusOutput` schema | +| `mcp_cloud/handlers.py` | Populate `log_lines` from agent output in `handle_plan_status` | +| `mcp_cloud/db_queries.py` | Possibly add helper to fetch tail from agent output table | +| `worker_plan/worker_plan_api.py` | Ensure agent stdout/stderr is captured to DB | + +### Schema Change + +```python +class PlanStatusOutput(BaseModel): + plan_id: UUID + state: PlanState + progress_percentage: float + created_at: datetime + updated_at: datetime + prompt_excerpt: str + result: Optional[dict] = None + error: Optional[dict] = None + log_lines: list[str] = [] # NEW: last 50 lines of agent output +``` + +### Implementation Steps + +1. **Verify output capture:** Confirm where agent stdout/stderr is stored (likely `agent_output` table or similar) +2. **Add DB query:** Create `_get_plan_log_tail(plan_id, lines=50)` in `db_queries.py` +3. **Update schema:** Add `log_lines` field to `PlanStatusOutput` +4. **Wire handler:** In `handle_plan_status`, fetch tail and populate field +5. **Test:** Verify field appears in `plan_status` response for running and completed plans + +### Edge Cases + +- If no output exists yet: return empty array `[]` +- If output is shorter than 50 lines: return all available +- Truncate individual lines at 500 chars to prevent huge payloads + +## Success Criteria + +- `plan_status` returns `log_lines: ["...", "..."]` with last 50 lines +- Works for both `processing` and `completed` states +- No performance impact on `plan_status` call (<50ms extra) +- Documented in MCP interface spec + +## Effort Estimate + +~2–3 hours +PR type: implementation (not docs-only) From f34b7f644f064b2cf77eb4074eef9d142f0f51e0 Mon Sep 17 00:00:00 2001 From: Simon Strandgaard Date: Tue, 10 Feb 2026 00:02:02 +0100 Subject: [PATCH 02/44] Nicer home.planexe.org theme --- frontend_multi_user/src/app.py | 26 +- frontend_multi_user/templates/base.html | 207 +++++++++--- frontend_multi_user/templates/index.html | 409 ++++++++++++++++++++++- 3 files changed, 593 insertions(+), 49 deletions(-) diff --git a/frontend_multi_user/src/app.py b/frontend_multi_user/src/app.py index ac57ce52..470cdf4e 100644 --- a/frontend_multi_user/src/app.py +++ b/frontend_multi_user/src/app.py @@ -706,7 +706,31 @@ def inject_current_user_name(): @self.app.route('/') def index(): - return render_template('index.html') + user = None + recent_tasks: list[TaskItem] = [] + is_admin = False + if current_user.is_authenticated: + is_admin = current_user.is_admin + if not is_admin: + try: + user_uuid = uuid.UUID(str(current_user.id)) + user = self.db.session.get(UserAccount, user_uuid) + if user: + recent_tasks = ( + TaskItem.query + .filter_by(user_id=str(user.id)) + .order_by(TaskItem.timestamp_created.desc()) + .limit(5) + .all() + ) + except Exception: + logger.debug("Could not load dashboard data", exc_info=True) + return render_template( + 'index.html', + user=user, + recent_tasks=recent_tasks, + is_admin=is_admin, + ) @self.app.route('/healthcheck') def healthcheck(): diff --git a/frontend_multi_user/templates/base.html b/frontend_multi_user/templates/base.html index a119e436..3c5cf139 100644 --- a/frontend_multi_user/templates/base.html +++ b/frontend_multi_user/templates/base.html @@ -7,86 +7,201 @@ {% block head %}{% endblock %} -
-
- PlanExe -