feat(api): add Lovart-style project and agent thread endpoints

Add canva/canda-compatible routes for lightweight project open/save and
agent thread history:
- POST /canva/project/queryProject, saveProject
- POST /canva/agent/queryAgentLastThread, agentThreadList
- GET /canda/chat-history, /canda/thread/status

Canvas save now accepts a compressed SHAKKERDATA:// snapshot payload,
preserves connections, and returns a SaveProject response; blank
successful image nodes are backfilled from generated artifacts. Frontend
designGateway adopts the new save/query flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-08 19:10:08 +08:00
parent ada29cee12
commit 263748af4a
27 changed files with 2045 additions and 114 deletions
+53 -4
View File
@@ -177,6 +177,17 @@ Returns all project summaries, sorted by `updatedAt` descending.
Returns the full project, including viewport, nodes, connections, and agent messages.
`POST /api/canva/project/queryProject`
```json
{
"projectId": "project-id",
"cid": "1781596271730ngdozsck"
}
```
Returns a Lovart-style project document with `assetMeta`, compressed `canvas`, `validProjectId`, `projectType`, `version`, and permission metadata. The frontend uses this for lightweight project opening, then decodes the `SHAKKERDATA://` canvas locally.
`PATCH /api/projects/:id/title`
```json
@@ -240,19 +251,57 @@ Returns replayable assistant/user chat history for the project.
}
```
Lovart-style agent thread endpoints are also available:
`POST /api/canva/agent/queryAgentLastThread`
Returns `{ "code": 0, "msg": null, "data": "<thread-id>" }`.
`POST /api/canva/agent/agentThreadList`
Accepts `{ "projectId": "project-id", "page": 1, "pageSize": 100, "cid": "..." }` and returns paginated thread summaries.
`GET /api/canda/chat-history?thread_id=<thread-id>&project_id=<project-id>`
Returns Lovart-style thread history items grouped by `thread_meta`.
`GET /api/canda/thread/status?thread_id=<thread-id>&project_id=<project-id>`
Returns `{ "code": 0, "msg": "success", "data": { "status": "done" } }` or the current project thread status when `project_id` is present.
## Save Canvas
`POST /api/canva/project/saveProject`
`PATCH /api/projects/:id/canvas`
```json
{
"viewport": { "x": 420, "y": 260, "k": 0.72 },
"nodes": [],
"connections": []
"canvas": "SHAKKERDATA://<gzip-base64-canvas-snapshot>",
"projectCoverList": ["https://cdn.example.com/canvas/image.png"],
"picCount": 1,
"projectName": "Untitled",
"projectId": "project-id",
"version": "1783472149000",
"sessionId": "browser-session-id",
"canvasV2Gray": true
}
```
Saves canvas layout changes. The frontend uses this after dragging or zooming.
```json
{
"code": 0,
"msg": null,
"data": {
"projectId": "project-id",
"newCreated": false,
"validProjectId": true,
"version": "1783498482000"
}
}
```
Saves canvas layout changes with a Lovart-style lightweight payload. The frontend posts to `/api/canva/project/saveProject`; `/api/projects/:id/canvas` remains as a compatibility route. The `canvas` value is a `SHAKKERDATA://` gzip+base64 encoded snapshot containing viewport, nodes, and connections. Legacy uncompressed `{ "viewport": ..., "nodes": ..., "connections": ... }` payloads are still accepted.
When a canvas image node disappears from the saved node list, its backing OSS asset is queued for asynchronous deletion after the canvas save succeeds.