Skip to content

Commit 1551ad3

Browse files
RafaelPogithub-actions[bot]
authored andcommitted
feat: restore aggregate summaries endpoint + widget re-mount rehydration (#5054)
## Summary - Restore the `GET /tasks/{id}/summaries/aggregate` Engine endpoint (lost during PR #5002→#5013 squash). It synthesizes micro-summaries into a single LLM-generated aggregate sentence via Gemini Flash Lite. - Widget now shows proper aggregate summaries during live polling (instead of falling back to raw micro-summaries) - On re-mount (revisiting a conversation), widget calls `backfillSummaries()` which fetches the last aggregate + micro-summaries and renders one activity entry ## Changes - **Engine**: `generate_aggregate_summary()` + `AGGREGATE_SYSTEM_PROMPT` in `summarizer.py`, `AggregatedSummaryResponse` model, `GET /{task_id}/summaries/aggregate` endpoint - **MCP routes**: `api_progress` fetches aggregate for terminal tasks without cursor (re-mount backfill) - **Widget**: `backfillSummaries()` on re-mount, detects completed status in `ontoolresult` ## Test plan - [x] Engine tests pass (46) - [x] MCP tests pass (351) - [ ] Run task in Claude.ai, verify aggregate summaries appear in Activity tab - [ ] Switch away, switch back, verify last summary rehydrates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Sourced from commit 1fea2f62212855b004be733de63b739e0a0554b1
1 parent 4b5aee6 commit 1551ad3

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

futuresearch-mcp/src/futuresearch_mcp/routes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,10 @@ async def api_progress(request: Request) -> Response:
193193

194194
payload = ts.model_dump(mode="json", exclude=_UI_EXCLUDE)
195195

196-
# Fetch aggregate + micro-summaries + partial rows for non-terminal tasks
197-
if not ts.is_terminal:
196+
# Fetch aggregate + micro-summaries for non-terminal tasks,
197+
# or for terminal tasks without cursor (re-mount backfill).
198+
backfill = ts.is_terminal and not request.query_params.get("cursor")
199+
if not ts.is_terminal or backfill:
198200
cursor = request.query_params.get("cursor")
199201
aggregate, summaries, new_cursor = await _fetch_aggregate_rest(
200202
client, task_id, cursor

futuresearch-mcp/src/futuresearch_mcp/templates.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,12 +1001,31 @@
10011001
});
10021002
}
10031003
1004+
/* ── fetch last aggregate summary (for re-mount when task already done) ── */
1005+
async function backfillSummaries(){
1006+
if(!pollUrl||!pollToken)return;
1007+
try{
1008+
const opts=pollToken?{headers:{"Authorization":"Bearer "+pollToken}}:{};
1009+
const r=await fetch(pollUrl,opts);
1010+
if(!r.ok)return;
1011+
const d=await r.json();
1012+
if(d.aggregate_summary||d.summaries)renderProgress(d);
1013+
}catch{}
1014+
}
1015+
10041016
/* ── ontoolresult: unified entry point ── */
10051017
app.ontoolresult=({content,structuredContent})=>{
10061018
/* Entry 1: structuredContent from futuresearch_status (widget data) */
10071019
if(structuredContent&&structuredContent.progress_url){
10081020
enterProgressMode(structuredContent);
1009-
if(!pollTimer){pollUrl=structuredContent.progress_url;startPoll();}
1021+
/* If task already completed on re-mount, backfill summaries then fetch results */
1022+
const done=["completed","failed","revoked"].includes(structuredContent.status);
1023+
if(done){
1024+
wasDone=true;
1025+
backfillSummaries().then(()=>{if(!resultsFetched)autoFetchResults();});
1026+
} else if(!pollTimer){
1027+
pollUrl=structuredContent.progress_url;startPoll();
1028+
}
10101029
return;
10111030
}
10121031
@@ -1018,7 +1037,13 @@
10181037
const d=JSON.parse(t.text);
10191038
if(d.progress_url){
10201039
enterProgressMode(d);
1021-
if(!pollTimer){pollUrl=d.progress_url;startPoll();}
1040+
const done=["completed","failed","revoked"].includes(d.status);
1041+
if(done){
1042+
wasDone=true;
1043+
backfillSummaries().then(()=>{if(!resultsFetched)autoFetchResults();});
1044+
} else if(!pollTimer){
1045+
pollUrl=d.progress_url;startPoll();
1046+
}
10221047
return;
10231048
}
10241049
}catch{}

0 commit comments

Comments
 (0)