Skip to content

feat: research agents — report-output agent category, workbench, and full D5 absorption - #527

Merged
MrParamecium merged 9 commits into
mainfrom
feat/research-agents
Sep 23, 2026
Merged

MrParamecium merged 9 commits into
mainfrom
feat/research-agents

Conversation

@MrParamecium

Copy link
Copy Markdown
Collaborator

What this does

Completes the research-agent integration (design N2/PR2, deferred from #488): Account Management (Grant Pool + accounts) and Activity join Providers on /admin's research surface — and, the user-facing half, report-output agents get a first-class home in Community and My Agents with a dedicated workbench.

Also completes the D5 end state: the whole administrator layer now lives on one page behind one gate, and the legacy /app?view=admin console is unreachable (both entry paths redirect).

The two delivery paths (teacher-approved)

  1. Download to local — completed runs render in a report view with Markdown / DOCX / PDF / Evidence JSON downloads.
  2. Email subscription — "Email me when the report is ready" on submit; completion email via the existing Brevo sender (link-only v1; periodic re-run subscriptions are designed and deferred pending billing/semantics decisions).

Changes

Research agents (user-facing)

  • marketplace.json: two research templates (Lin-Feihan's Shell Company Screening + Due Diligence) on a new research shelf, pointing at their external FastAPI service and public GitHub repos.
  • Community gains a Research Agents shelf whose cards show agent facts (runtime, output formats, repo pill) instead of equity curves; Add routes to the research add endpoint (no runtime copy, no cash allocation).
  • My Agents gains a Research Agents shelf; cloned agents open the research workbench: a form rendered dynamically from the agent's manifest schema, submit, 10s status polling, a safe minimal Markdown renderer, and artifact downloads.
  • Backend /api/v1/research/*: add/remove, manifest proxy (short cache), run submission proxying to the agent service per the N2/PR2 contract (X-Service-Token, 4端点), status polling that completes runs server-side, per-user report/artifact storage (sqlite; Render FS is ephemeral), completion email hook.

Absorption (D5 end state)

  • admin.html gains the Grant Pool + account management (#account) and Grant Activity (#activity) sections; admin-credits.js ports via the shell's request()/write(); the retired window.API bridge pattern is avoided by design.
  • /app?view=admin&adminTab=… → 307 to /admin#account|#providers|#activity (Render origin) plus a client-side boot redirect (Vercel serves /app statically). Legacy console code stays one release, unreachable.

Local-dev + ops fixes found during verification

  • Local console autologin: ATL_LOCAL_AUTOLOGIN_EMAIL (launchd-only env) + loopback check resolves the seeded admin in get_current_user, covering both no-cookie and stale-cookie shapes; boot probes /me unconditionally on loopback hostnames.
  • Cache-Control: no-cache for dashboard HTML/JS/CSS — browsers heuristic-cached FileResponses and Chrome kept a pre-change app.js alive.
  • Ticker perf: the marquee repeat estimate evaluated left-to-right and once built ~380k DOM nodes; now 42 tiles.
  • admin-console.css (extracted component styles) + Cache-Control + route-contract registration for all new routes.

Verification

  • Full backend suite green (4392+ tests) on every stacked state; route contract registers all new routes; catalog guards rescoped for research rows (external service, no ATL-owned model).
  • Browser end-to-end against the contract stub: Community discover → add → My Agents shelf → workbench form → run → report → downloads; guest never sees the console; analytics routes unchanged.

Follow-ups (explicitly deferred)

  • Real-service swap when Lin-Feihan delivers the deployed URL (one config line per template).
  • Email send verified with a real inbox (needs Brevo key in the environment; hook is wired).
  • Periodic re-run subscriptions (v2) after billing/semantics confirmation.
  • Legacy console code deletion after one release.

…kbench

Completes loop L2+L3 of the research-agent integration (design N2/PR2):

- marketplace.json gains two research templates (Shell Company Screening,
  Due Diligence) on a new 'research' shelf; the catalog projects their
  service pointer and delivery facts instead of runtime fields.
- New /v1/research routes: add/remove (the research clone — a user→template
  link, no runtime copy, no cash allocation), manifest proxy with a short
  cache, run submission proxying to the agent's external service per the
  N2/PR2 contract, status polling that completes runs server-side (storing
  report + artifacts + evidence in sqlite), per-user report view, and
  artifact downloads with Content-Disposition.
- Completion side effects fire on the poll that discovers completion: the
  notification email (Brevo, link-only) when the submitter opted in.
- Frontend: Community 'Research Agents' shelf with research cards (no
  equity curve — card shows facts), My Agents 'Research Agents' shelf
  (hidden for guests), and the research workbench — dynamic form rendered
  from the manifest schema, submit, 10s status polling, a safe minimal
  Markdown renderer (escape-first, bounded subset), and downloads.
- The full-route-contract test registers the nine new routes; the trading
  catalog guards (model slugs, vendor prefixes, market chips, taxonomy)
  are scoped to exclude research rows, which run no ATL-owned model.

Verified end-to-end in the browser against the contract stub: add from
Community → shelf entry → workbench form (manifest-driven) → submit →
completed report with Markdown/Word/PDF/Evidence downloads.
Local verification used to need a manual sign-in on every fresh browser.
Two pieces, both scoped to the local machine:

- api/auth.py: get_current_user resolves ATL_LOCAL_AUTOLOGIN_EMAIL (env,
  set only in the local launchd plist) when the request comes from
  loopback and the account is an admin — /me and every dependency-gated
  route answer pre-authenticated, with no cookie ever issued.
- app.js boot: on loopback hostnames the boot probes /me unconditionally;
  the cached-auth-user shortcut would keep a fresh browser a guest
  forever, because nothing cached exists to trigger the first probe.
  Prod boot keeps the cold-start /me skip.

Cache versions bumped (app.js 134→135, styles.css 142→143) with the
version pins in five test files.
Browsers heuristic-cache FileResponses that carry no Cache-Control
header, which is how Chrome kept serving a pre-autologin app.js and the
stale HTML that loads it — the local console then looked signed out no
matter what the server answered. The ?v= pins stay as the hard
cache-buster; this makes every load revalidate instead.
The fallback only fired when no token was present. A browser carrying a
cookie whose session no longer exists (the local-dev DB was swapped under
it) took the token path, 401'd, and the console looked signed out no
matter what — that was Chrome's case. The fallback now covers both
shapes: no cookie, and a cookie that fails to resolve.
The research card markup lacked the agent-card/agent-card-cta wrapper
classes the blue CTA and card chrome hang off, so the Add button rendered
as a bare unstyled control next to the styled trading cards.
The two research templates point at their public repos
(Lin-Feihan/shell-company-screening-agent, Lin-Feihan/due-diligence-agent),
and the cards render the same repo pill the Open Agents shelf uses. The
⏱/📄 emoji in the runtime/output facts rows are replaced with the app's
SVG icon set (icon-clock, new icon-file-text mirrored into the app.html
sprite).
The research add succeeded silently — no toast, no button change, and a
second click repeated the request invisibly. The research branch of the
Add action now flips the button to a disabled 'Added ✓', surfaces the
success (and the already-added case) via the app toast, and the added
state is fetched with the catalog so the buttons render correctly on the
next Community visit.
# Conflicts:
#	dashboard/backend/tests/test_admin_analytics_frontend.py
#	dashboard/backend/tests/test_backtest_comparison_frontend.py
#	dashboard/backend/tests/test_frontend_fast_boot.py
#	dashboard/frontend/app.html
@vercel

vercel Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agentic-trading-lab Ready Ready Preview Sep 23, 2026 5:21pm UTC

if user.get("id") is not None:
try:
enriched["entitlements"] = users_module.user_store.get_entitlements(user["id"])
except Exception:

import base64
import os
from typing import Any, Dict, Optional

@router.get("/runs/{run_id}/artifacts/{kind}")
def download_artifact(run_id: str, kind: str, current_user: dict = Depends(get_current_user)):
run, _template = _run_and_template_or_404(run_id, current_user)

@router.get("/runs/{run_id}/artifacts/{kind}")
def download_artifact(run_id: str, kind: str, current_user: dict = Depends(get_current_user)):
run, _template = _run_and_template_or_404(run_id, current_user)
def store_artifacts(run_id: str, artifacts: Dict[str, Dict[str, str]],
evidence: Dict[str, Any], report_markdown: str) -> None:
"""Persist everything a completed run delivered (replace-on-complete)."""
rows = [
@MrParamecium
MrParamecium merged commit 58ae812 into main Sep 23, 2026
8 checks passed

This branch was successfully deployed

1 active deployment
Preview — f497e051 Deployed Sep 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants