Disable static asset caching

This commit is contained in:
caoqianming 2026-06-08 09:16:31 +08:00
parent 4ee09976ee
commit c898ff863d
4 changed files with 44 additions and 3 deletions

View File

@ -2,7 +2,7 @@
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`
最后更新:2026-06-08(前端模块化 Step 2 完成:抽出 chat.js;main 75 行,路径 1 收官)
最后更新:2026-06-08(task_progress 进度工具 + 前端固定进度区 + 静态资源 no-cache)
---
@ -21,6 +21,10 @@
## 已完成关键能力
### 2026-06-08
- **新增 Codex 式 `task_progress` 进度工具 + Web 固定进度区**:`TaskProgressTool` 默认注册到 agent,支持 `set_plan/update_step/clear`,返回极短 UI-only 结果;上下文压缩对旧 `task_progress` tool_call/result 做专门折叠,避免进度历史长期占 prompt。前端新增 `progress.js` 做 task 级进度状态合并,修复 `update_step` 只带 `{id,status}` 时因缺标题不显示的问题;当前进度显示从助手消息内提升到 `#task-progress-dock`(对话流下方、输入框上方),历史消息内仍保留进度块作记录。system prompt + coding/ppt/proposal/analyze skill 加轻量使用约定,要求只在多步骤关键阶段少量更新。**部署侧补静态资源 no-cache**:`NoCacheStaticFiles` 替换默认 `StaticFiles`,让浏览器重新校验 `/static/*.js` 等资源,避免前端修复已部署但旧 `chat.js` 仍被缓存导致看不到进度区。校验:`pytest tests/test_context_compaction.py tests/test_task_progress_tool.py tests/test_executor_docker.py tests/test_static_vendor.py -v` 相关集通过;`node --test tests/frontend_task_progress.test.mjs` 2 过;`node --check web/static/js/chat.js web/static/js/progress.js` 过。
### 2026-06-06
- **前端模块化 Step 2 收官:抽出 `chat.js`(对话视图)+ main.js 缩成 75 行入口**:最后也是最缠的一块——任务列表(浏览/筛选/滚动)+ selectTask 切换 + renderChatMeta/模型下拉 + renderMessages + live-run 助手 + sendMessage/cancel + fetchSse/handleSseEvent + 润色/粘贴文件 + 完成/废弃/删除/导出/清空(原 main.js 连续区 641132)→ `chat.js`(1086 行)。**决策:合一个 chat.js 而非强拆 tasks.js+stream.js**——读完依赖图确认二者共享 `state.liveRuns` + `chat-stream` DOM + run 生命周期,且 live-run 助手(renderLiveRunIfVisible/ensureRunningTaskSubscribed 等)被 selectTask 和 SSE 机器两边调用、骑墙;强拆会制造双向各 ~4-5 个 import 且边界不自然(用户已确认选合一)。导出 `loadTaskList`/`loadModels`/`selectTask`,embed/files/newtask 对这三个的 import 从 `./main.js` 改指 `./chat.js`;`formatUploadProgress` 加 export(粘贴上传进度用)。**chat 不调 enterApp → 与 main 无环**。`main.js` 仅留 `enterApp`(编排)+ `loadStorage` + Esc 关栈 + boot = **75 行入口**,import 精简到 11 行(layout/markdown/media 不再被 main 直接引用,但经 chat 仍在依赖图、副作用照常)。**校验升级**:除 node 全检 + import/export 一致性,新增**从 main BFS 的模块可达性检查**(14/14 可达,确保副作用模块不掉出图)。dev.html 4087 行单文件 → 14 个零构建 ES module + 纯 HTML;main 2719→75。**路径 1(拆文件)完成**,后续可按需进路径 2(给 chat/files 等局部引 Alpine/petite-vue 响应式)。

View File

@ -1,6 +1,12 @@
from pathlib import Path
import tempfile
import unittest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from web.static_files import NoCacheStaticFiles
ROOT = Path(__file__).resolve().parents[1]
STATIC_DIR = ROOT / "web" / "static"
@ -43,6 +49,19 @@ class StaticVendorTests(unittest.TestCase):
self.assertIn("context_original_chars", src)
self.assertIn("cache_hit_tokens", src)
def test_static_js_is_served_with_revalidation_header(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
static_dir = Path(tmp)
(static_dir / "app.js").write_text("export const ok = true;\n", encoding="utf-8")
app = FastAPI()
app.mount("/static", NoCacheStaticFiles(directory=str(static_dir)), name="static")
client = TestClient(app)
resp = client.get("/static/app.js")
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.headers.get("cache-control"), "no-cache")
if __name__ == "__main__":
unittest.main()

View File

@ -25,7 +25,6 @@ from uuid import UUID, uuid4
from fastapi import Depends, FastAPI, File, Form, HTTPException, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, RedirectResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from sqlalchemy import BigInteger, cast, func, select, update
from starlette.background import BackgroundTask
@ -51,6 +50,7 @@ from .auth import (
)
from .broker import broker
from .sinks import WebEventSink
from .static_files import NoCacheStaticFiles
STATUS_FILTERS = ("active", "completed", "abandoned")
@ -690,7 +690,7 @@ def create_app() -> FastAPI:
# Windows 上 mimetypes 偶尔把 .js 判成 text/plain,会令 <script type="module"> 被浏览器拒执行;
# 显式兜底,保证静态 ES module 以正确 MIME 下发。
mimetypes.add_type("text/javascript", ".js")
app.mount("/static", StaticFiles(directory=str(_STATIC_DIR)), name="static")
app.mount("/static", NoCacheStaticFiles(directory=str(_STATIC_DIR)), name="static")
# ───────────── Misc ─────────────

18
web/static_files.py Normal file
View File

@ -0,0 +1,18 @@
"""Static file helpers for the Web SPA."""
from __future__ import annotations
from starlette.responses import Response
from fastapi.staticfiles import StaticFiles
class NoCacheStaticFiles(StaticFiles):
"""StaticFiles variant that asks browsers to revalidate SPA assets.
The Web UI is a module graph of small JS files. Without revalidation, users
can keep an old chat.js after a deploy and miss frontend-only fixes.
"""
def file_response(self, *args, **kwargs) -> Response:
response = super().file_response(*args, **kwargs)
response.headers["Cache-Control"] = "no-cache"
return response