Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 57528d7473 | |||
| f790435023 | |||
| b29105adf3 | |||
| 70243eeb8b | |||
| c7ce780edd | |||
| 95681c4b97 | |||
| 5d9b6fca23 | |||
| ae2584c7f7 | |||
| de6c4e096c | |||
| b9108ae873 | |||
| 01e2d2702c | |||
| ab1cf5f3f8 | |||
| 9ace9d8a02 | |||
| c1e8e53e5b |
@@ -0,0 +1,157 @@
|
||||
# .gitea/workflows/ci.yml - ResearchX phase-4 CI gate (researchx#24).
|
||||
#
|
||||
# This file IS the gate. The pre-code clause (coreci/company#105, c14057):
|
||||
# a code phase opens only when the product repo's gating workflow file has
|
||||
# dispatched at least one run on `main` and every job in that file is green
|
||||
# in that run. Until this file exists, coreci/researchx has no workflow and
|
||||
# no run at all - that is the case the clause was amended for (researchx#24,
|
||||
# c14093). A half-green pipeline does not open the phase either.
|
||||
#
|
||||
# Two jobs:
|
||||
# backend - uv + Python 3.12: ruff, mypy, pytest
|
||||
# frontend - Node 22 + pnpm 12.6.0: typecheck, lint, test, build
|
||||
#
|
||||
# Runner label: `ubuntu-latest` - the org CI fleet's published label whose
|
||||
# image is docker.gitea.com/runner-images:ubuntu-latest (label map read at
|
||||
# source: coreci/nextcraft deploy/ci/docker-compose.yaml + deploy/ci/README.md,
|
||||
# R-3). The previous string `employee-runner` was a fleet NAME, not a label:
|
||||
# the employee fleet's labels are `employee-py` and `employee-coder` (read
|
||||
# from a live job log of this seat's own home), and the CI fleet's are node /
|
||||
# ubuntu-latest / python / release - no runner carried the old label, so a
|
||||
# merged file asking for it could still buy no run.
|
||||
#
|
||||
# Toolchain: measured, not assumed. From the runner's own logs (job 56393,
|
||||
# coreci/nova-platform, 2026-10-26T23:17Z, and job 57005, coreci/inboxos-v1,
|
||||
# 2026-10-27T03:01Z): the image carries python 3.12.3, pip, git, node (the
|
||||
# actions run in it), pypi REACHABLE and github REACHABLE; actions/checkout@v4,
|
||||
# actions/setup-python@v5 and actions/setup-go@v5 all run inside it. It does
|
||||
# NOT carry uv or pnpm, so this file installs them: uv from pypi (pip), pnpm
|
||||
# 12.6.0 through corepack - the repo's own documented way (README command map).
|
||||
# The gates are the repo's documented commands: backend `uv run ruff check src
|
||||
# tests`, `uv run mypy src`, `uv run pytest`; frontend `pnpm typecheck`,
|
||||
# `pnpm lint`, `pnpm test`, `pnpm build`. The frontend lane mirrors the
|
||||
# release image's own recipe (frontend/Dockerfile: node:22-alpine, corepack,
|
||||
# pnpm install --frozen-lockfile, pnpm build), so the gate tests what the
|
||||
# product ships.
|
||||
#
|
||||
# Owner of a red leg (the clause asks for the owner of the fix next to the
|
||||
# owner of the product line): toolchain / image / dispatch problems ->
|
||||
# coreci-sre (employee-runner-fleet + gitea-instance); product-line problems
|
||||
# -> coreci-researchx-po. Approval for this file rides the merge request
|
||||
# (merge = approval, constitution v1.3).
|
||||
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
backend:
|
||||
name: "backend (uv, Python 3.12: ruff/mypy/pytest)"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
# uv is not in the CI image; pypi is reachable from it (measured). The
|
||||
# install is a toolchain leg, not a product gate: the gates still run
|
||||
# from the repo's own committed lockfile (backend/uv.lock).
|
||||
- name: Install uv (from pypi)
|
||||
run: |
|
||||
set -eu
|
||||
python -m pip install --upgrade uv
|
||||
uv --version
|
||||
|
||||
- name: Install dependencies (uv, from the committed lockfile)
|
||||
working-directory: backend
|
||||
run: uv sync --frozen
|
||||
|
||||
- name: Lint (ruff)
|
||||
working-directory: backend
|
||||
run: uv run ruff check src tests
|
||||
|
||||
- name: Typecheck (mypy)
|
||||
working-directory: backend
|
||||
run: uv run mypy src
|
||||
|
||||
- name: Test (pytest)
|
||||
working-directory: backend
|
||||
run: uv run pytest
|
||||
|
||||
frontend:
|
||||
name: "frontend (Next.js on pnpm: typecheck/lint/test/build)"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Node 22 to mirror the release image (frontend/Dockerfile: node:22).
|
||||
- name: Setup Node 22
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Setup Python 3.12 (for the real-stack e2e bridge)
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install uv (from pypi)
|
||||
run: |
|
||||
set -eu
|
||||
python -m pip install --upgrade uv
|
||||
|
||||
# pnpm 12.6.0 is pinned by frontend/package.json `packageManager`;
|
||||
# corepack reads it from there. If the image carries no corepack, npm
|
||||
# installs the same pinned version.
|
||||
- name: pnpm 12.6.0 (corepack, pinned by frontend/package.json)
|
||||
working-directory: frontend
|
||||
run: |
|
||||
set -eu
|
||||
node --version
|
||||
corepack enable pnpm 2>/dev/null || true
|
||||
if ! pnpm --version >/dev/null 2>&1; then
|
||||
npm i -g pnpm@12.6.0
|
||||
fi
|
||||
test "$(pnpm --version)" = "12.6.0"
|
||||
|
||||
- name: Install dependencies (from the committed lockfile)
|
||||
working-directory: frontend
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# frontend/src/lib/api/e2e-real-stack.test.ts drives the real FastAPI
|
||||
# stack: it spawns `uv run python -m researchx.api.dev_bridge` from
|
||||
# ../backend (loopback :8000, fakes only, zero API keys). Without a
|
||||
# synced backend venv that test cannot come up, so the lane provisions
|
||||
# it. Provisioning only - the backend gates stay in the backend job.
|
||||
- name: Backend venv for the real-stack e2e bridge
|
||||
working-directory: backend
|
||||
run: uv sync --frozen
|
||||
|
||||
- name: Typecheck
|
||||
working-directory: frontend
|
||||
run: pnpm typecheck
|
||||
|
||||
- name: Lint
|
||||
working-directory: frontend
|
||||
run: pnpm lint
|
||||
|
||||
- name: Test
|
||||
working-directory: frontend
|
||||
run: pnpm test
|
||||
|
||||
- name: Build
|
||||
working-directory: frontend
|
||||
env:
|
||||
NEXT_TELEMETRY_DISABLED: "1"
|
||||
run: pnpm build
|
||||
@@ -1,5 +1,12 @@
|
||||
# ResearchX
|
||||
|
||||
**TL;DR** — ResearchX turns one question into a cited research report: pick a method, approve the plan, and the engine visits real web sources, with every claim anchored to a quoted passage from a page it actually read. The engine milestone (v0.2.5) is shipped and owner-approved; hosting goes live next (v0.3, in progress).
|
||||
|
||||
- **What** — FastAPI backend (planning, search, extraction, verification, export gates) plus a Next.js frontend; the full test suite runs with zero API keys.
|
||||
- **Why** — Readers can check every citation back to its source passage; runs are resumable from durable state.
|
||||
- **Action** — no action — FYI. Developers: see the Quickstart below.
|
||||
- **Details** — `frontend/README.md` (web app); `.ciagent/` (pipeline state and roadmap).
|
||||
|
||||
A deep-research studio where you bring your own model, storage, and memory; choose a research methodology before a single query fires; and every claim in the final report is anchored to a visited, verified, quotable source.
|
||||
|
||||
**Status: MVP shipped (v0.2.5, owner-approved 2026-09-27)** — the full research engine (FastAPI + asyncio state machine + adapter layer + attack-proven trust loop) behind the v0.1 frontend. Live mode covers the core research loop (G-002/G-009): the engine runs locally per the quickstart; library/settings/suggestions/refine stay mock-backed until v0.3+.
|
||||
|
||||
@@ -226,6 +226,7 @@ def create_app(
|
||||
storage=storage,
|
||||
registry=registry,
|
||||
event_bus=bus,
|
||||
on_complete=runs.note_completed,
|
||||
)
|
||||
probe_data: dict[str, Any] | None = None
|
||||
if supports_probe(model):
|
||||
@@ -240,9 +241,7 @@ def create_app(
|
||||
runs.add(run_id, actor, task, bus)
|
||||
|
||||
async def _watch() -> None:
|
||||
state = await task
|
||||
if state.state == RunStateName.DONE:
|
||||
runs.note_completed()
|
||||
await task
|
||||
|
||||
asyncio.create_task(_watch())
|
||||
return _summary(run_id)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
@@ -34,6 +35,7 @@ class RunActor:
|
||||
storage: LocalStorageAdapter,
|
||||
registry: MethodologyRegistry,
|
||||
event_bus: EventBus,
|
||||
on_complete: Callable[[], None] | None = None,
|
||||
) -> None:
|
||||
self._config = run_config
|
||||
self._model = model
|
||||
@@ -41,6 +43,7 @@ class RunActor:
|
||||
self._storage = storage
|
||||
self._registry = registry
|
||||
self._bus = event_bus
|
||||
self._on_complete = on_complete
|
||||
self._store = EvidenceStore()
|
||||
self.state = RunState(
|
||||
run_id=run_config.run_id,
|
||||
@@ -83,6 +86,8 @@ class RunActor:
|
||||
async def _checkpoint(self, target: RunStateName) -> None:
|
||||
if self.state.state != target:
|
||||
self.state.transition(target)
|
||||
if target is RunStateName.DONE and self._on_complete is not None:
|
||||
self._on_complete()
|
||||
await self._persist()
|
||||
|
||||
async def _wait_if_paused(self) -> None:
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# ResearchX Frontend
|
||||
|
||||
**TL;DR** — This is the ResearchX web interface: ask a question, choose a research method, approve the plan, watch the live trace, read the cited report. The prototype runs entirely on scripted sample data — no API keys, no backend, no network — so the full product journey is tryable today.
|
||||
|
||||
- **What** — A Next.js app (ask, choose, run, report, library, settings) rendering mock data through one typed client interface.
|
||||
- **Why** — The journey is checkable end-to-end before live inference exists.
|
||||
- **Action** — no action — FYI. Developers: Quickstart below (Node 20+, pnpm).
|
||||
- **Details** — Root `README.md`: backend engine, live mode, architecture.
|
||||
|
||||
The prototype frontend for ResearchX — methodology-driven deep research
|
||||
with a trust loop. This milestone (v0.1) runs **entirely on mock data**:
|
||||
no API keys, no env vars, no network calls beyond static assets.
|
||||
|
||||
Reference in New Issue
Block a user