EdCity Chat v2 — Honest Connection + Real Wiring

Status after PRD → 4-sub fork → /verify → /scout → critical-fix patches. Ready for runtime verification on your machine, then PR to Leslie.

TL;DR

What v2 ships

A. Pill honesty — three explicit states

StateWhat it meansUI
● Live + cachedEdCity logged in, token fresh (<8h), live tools available alongside cached.Green pill, account email + last-login time in tooltip.
● Session expiredCached tools still available, but live tools unreachable until reconnect.Amber pill + "Reconnect" button.
● Not connectedCache only (or no tools for this page).Grey pill + "+ Connect" button.

Replaces the previous always-on green that lied when EdCity was actually down.

B. Real EdCity wiring — two new live tools

Files changed

FileChange
api/src/services/edcityLiveClient.tsNEW — pure HTTPS client, token status, fresh URLs, list papers.
api/src/services/agentTools.ts+ createGetFreshUrlsTool, + createListMyPapersTool; getToolsForPage conditionally appends live tools.
api/src/services/agentHarness.tsFIXToolCallLog now carries images[] and questions[] through both runAgentLoop and runAgentLoopStream.
api/src/routes/help/edcity-connect.post.tsNEW — connect endpoint; honors EDCITY_TOKEN_CACHE_PATH env to stay in sync with live client.
api/src/routes/help/chat-tools.get.ts+ edcity_session, + tools_breakdown, + tools_available, + live_session_connected; connected marked deprecated.
api/src/routes/index.tsRegistered POST /help/edcity/connect.
web/src/components/help/ToolStatusPill.tsxREWRITTEN — three pill states + connect/reconnect actions.
web/src/components/help/ChatMessage.tsxInline image rendering w/ kind: cached|fresh badge + onError refresh affordance.
web/src/services/web_api/help-chat.ts+ connectEdCity(), extended ChatToolsHealth, ChatImage.kind, ToolCallLogEntryPayload.images/questions.

What scout caught (and what I fixed)

Critical 1 — SSE done stripped images

During streaming, tool_call_done events carried images[]/questions[] — they rendered inline correctly. But the final done event sent the harness's tool_calls_log which only contained {tool, args, result_summary}. The frontend overwrote the rich client-side state, so images visibly disappeared the moment the stream finished.

Fix: Extended ToolCallLog in agentHarness.ts with optional images + questions; populated from envelope.structured in both push sites. Server-side tool_calls_log now carries the same envelope payload as the live tool_call_done events. Frontend overwrite is now safe.

Critical 2 — JSON path never had images at all

Same root cause in the non-streaming runAgentLoop. Same fix.

Moderate 3 — Token-path desync

edcity-connect.post.ts hardcoded the cache path while edcityLiveClient.ts honored EDCITY_TOKEN_CACHE_PATH. Could silently desync if env var was set. Fix: connect endpoint now also honors the env var.

Moderate 4 — Misleading data.connected field

connected = edcity_session.connected || tools_count > 0 meant "connected" returned true for cache-only pages. Pill itself reads edcity_session.connected correctly, but other consumers could be misled. Fix: Added tools_available and live_session_connected as explicit aliases; marked connected @deprecated. Backward-compat preserved.

Moderate 5 — Refresh-image button unwired

onRequestImageRefresh prop exists in ChatMessage but isn't passed from AiChatDrawer. Status: Sub-4 actually handled this defensively — when no handler is provided, the button-shaped element shows "Image expired — ask the AI to refresh." instead of a clickable button. Not a ship blocker; can be wired in a follow-up if you want one-click refresh.

Pending — runtime verification on your machine

# 1. Restart API (current one is 47min stale, doesn't hot-reload)
cd app/essai/api && yarn start:func

# 2. Refresh EdCity token (current cache is 39.8h old — expired)
node tools/edcity-client.js login

# 3. Walkthrough on http://localhost:5176/math/question-bank
#    - Pill should be GREEN (live + cached) right after step 2
#    - Ask: "Find 3 fresh image URLs for question 12345" → tool fires, fresh badge shows
#    - Ask: "List my EdCity papers" → tool fires, returns paper list
#    - Stop the func host → reload page → pill goes AMBER (session expired)
#    - Wipe .token-cache.json → pill goes GREY (+Connect button)

# 4. Re-run eval
node workdir/math/edcity-ai-chat/benchmark/eval-agentic-monorepo.js

What's left for the PR to Leslie

Generated locally · essai workspace · all changes committed pending your review.