Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .cursor/plans/junction_engine_mcp_server_46c4953c.plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ Each tool handler receives `app.db.db` (Drizzle instance) to query the database

- **Course lookup by code**: Several tools accept a human-readable `code` like "COS 226" in addition to the internal `courseId`. These do a `LIKE` query on `courses.code`.
- **Eval lookup by code**: Evaluation tools resolve course codes to `listing_id` by joining with the `courses` table, so students can ask "reviews for COS 226" naturally.
- `**discover_courses**`: Queries for courses matching filters — `new` checks for high listing IDs (first-time offerings), `small_seminar` filters by low capacity sections, `no_final` uses the `has_final` flag, `open` checks section status.
- `**discover_courses`**: Queries for courses matching filters — `new` checks for high listing IDs (first-time offerings), `small_seminar` filters by low capacity sections, `no_final` uses the `has_final` flag, `open` checks section status.
- `**find_courses_that_fit**`: Loads the user's existing schedule sections, computes occupied time slots, then finds courses whose sections don't overlap. Optionally filters by department or distribution area.
- `**summarize_course_reviews**`: Returns the raw comments array and ratings so the AI client can generate a natural language summary. The tool doesn't summarize itself — it provides the data for the LLM to work with.
- **Caching**: Course-heavy tools use the existing Redis `getOrSetJson` pattern where appropriate.
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ vite.config.ts.timestamp-*
Engine API
.vscode/settings.json
apps/engine/src/cache/rediscache.ts.timestamp-*
apps/engine/.env
apps/engine/.env
apps/ask-gateway/.venv/
apps/ask-gateway/**/__pycache__/
16 changes: 13 additions & 3 deletions UPDATE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,21 @@ In [`src/lib/constants.ts`](src/lib/constants.ts) check the array titled DEPARTM

## Step 4: Populate the Database

Run `npm run dev` in the terminal to start the development server. Once the server is running, go to `localhost:5173/admin` in your browser. This may require you to login, in which case you will have to replace `junction.tigerapps.org` with `localhost:5173` in the URL when the login page redirects you (you will receive an error if not already logged in on localhost). If you do not have admin access, grant yourself admin access by going to the `private_profiles` table in Supabase and setting the `is_admin` column to `true` for your user. _PLEASE BE CAREFUL TO NOT ACCIDENTLY GRANT ADMIN ACCESS TO SOMEONE ELSE_.
Database population is done via CLI scripts in `apps/database`. Make sure your `apps/database/.env` file is configured with the required environment variables (see `apps/database/.env.example`): `PUBLIC_SUPABASE_URL`, `SERVICE_ROLE_KEY`, `API_ACCESS_TOKEN`, `REDIS_PASSWORD`, and `REG_COOKIE`.

Once you are on the admin page, input the term you are adding into the term field, and click `Push Listings`. This should take less than a minute to complete. Once it is done, input the term again and check the `Refresh Grading` checkbox. Then, click `Push Courses` and wait for it to complete. This will take a while (around 30 minutes). Finally, input the term again and click `Push Ratings`. This shoudl take less than a minute to complete. Once all of these are done, you can close the server.
Before running the scripts, add the new term code to the `TERMS` array in `apps/database/src/scripts/supabase/shared.ts`, or the scripts will reject it as invalid.

_Make sure to do this on localhost and not on the production site, it will timeout_.
From the `apps/database` directory, run the following commands in order:

1. **Push Listings + Courses + Redis:** `bun run update-supabase <term> --grading`
- This populates listings, courses (with grading info), and syncs to Redis in one step.
- The `--grading` (or `-g`) flag refreshes grading fields. Omit it if you don't need to update grading.
- This will take a while (~30 minutes).

2. **Push Ratings:** `bun run ratings-supabase <term>`
- This scrapes course evaluation ratings and updates them in Supabase, then syncs to Redis.
- Requires `REG_COOKIE` to be set (a valid `PHPSESSID` cookie from the registrar evaluations site).
- You can optionally pass a `startIndex` as a second argument to resume from a specific course if the script is interrupted.

## Step 5: Test and Deploy

Expand Down
15 changes: 15 additions & 0 deletions apps/ask-gateway/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ASK_GATEWAY_API_TOKEN=
JUNCTION_MCP_URL=http://localhost:3000/princetoncourses/mcp
JUNCTION_MCP_TOKEN=
MCP_PROTOCOL_VERSION=2025-03-26
ASK_TOOL_TIMEOUT_SECONDS=10
ASK_CONNECT_TIMEOUT_SECONDS=5
OPENROUTER_API_KEY=
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_SITE_URL=
OPENROUTER_APP_NAME=tiger-junction-ask-gateway
ASK_LLM_MODEL=moonshotai/kimi-k2:thinking
ASK_LLM_TEST_MODEL=google/gemini-3.1-flash-lite
ASK_LLM_TIMEOUT_SECONDS=12
ASK_LLM_PLANNER_ENABLED=false
ASK_LLM_SYNTHESIS_ENABLED=false
38 changes: 38 additions & 0 deletions apps/ask-gateway/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Ask Gateway

FastAPI service that provides SSE chat streaming for PrincetonCourses and calls Junction MCP tools.

## Endpoints

- `GET /health` - health check
- `POST /ask/stream` - SSE chat stream

## Run locally

1. Create and activate a Python virtual environment.
2. Install dependencies:

```bash
pip install -r requirements.txt
```

3. Copy `.env.example` to `.env` and set secrets.
4. Start:

```bash
uvicorn app.main:app --reload --port 8010
```

## Human-in-the-loop test (Commit 5)

1. Start Engine (`apps/engine`) and Ask Gateway.
2. Send `POST /ask/stream` with a user message and observe SSE events in order:
- `status(starting)` -> `tool_call` -> `tool_result` -> `token` -> `done`
3. Trigger timeout by setting very low `ASK_TOOL_TIMEOUT_SECONDS` and verify `event:error` with `code=timeout`.
4. Disconnect the client mid-stream and verify a cancellation error event is emitted.

## Smoke test

```bash
ASK_GATEWAY_URL=http://localhost:8010 ./scripts/smoke_ask_ai.sh
```
1 change: 1 addition & 0 deletions apps/ask-gateway/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Ask gateway package
Loading
Loading