docs(plan): update planning artifacts for adapter and account-pool work
Desktop Client Build / Resolve Build Metadata (push) Successful in 24s
Frontend CI / Frontend (push) Successful in 2m56s
Backend CI / Backend (push) Failing after 8m6s
Desktop Client Build / Build Desktop Client (push) Successful in 24m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 50s
Desktop Client Build / Resolve Build Metadata (push) Successful in 24s
Frontend CI / Frontend (push) Successful in 2m56s
Backend CI / Backend (push) Failing after 8m6s
Desktop Client Build / Build Desktop Client (push) Successful in 24m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 50s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+66
@@ -292,3 +292,69 @@
|
||||
- The Electron main bundle owns Playwright adapters. Playwright serializes `page.evaluate` callbacks with `Function.prototype.toString()` and runs them in the target web page. When `javascript-obfuscator` rewrites main-process evaluate callbacks, string-array helper identifiers remain in the function body but are not defined in the browser page context.
|
||||
- `electron.vite.config.ts` already disables Vite minification for main for the same reason; the remaining failure path was `scripts/obfuscate.cjs` obfuscating `out/main/*.cjs` after build.
|
||||
- Fix: keep the main process bundle unobfuscated and only obfuscate renderer assets. `pnpm --filter @geo/desktop-client build:obf` now rebuilds main cleanly and obfuscates renderer only.
|
||||
|
||||
## Hunyuan SSE/Search And Markdown - 2026-07-12
|
||||
|
||||
- `yuanbao.ts` already captures JSON/event-stream responses and parses current `hunyuan_t1` frames, so the SSE-first change should strengthen the existing path rather than introduce a second protocol implementation.
|
||||
- The page query currently ensures the deep-think toggle is enabled before submit, but initial inspection found no corresponding pre-submit `ensureToggleEnabledByPattern(webSearchPattern, ...)` call.
|
||||
- Final answer selection currently compares parsed SSE text and DOM text by a quality score; this violates the requested strict ordering because a longer DOM snapshot may replace a valid API answer.
|
||||
- The Markdown display issue can originate either in Yuanbao answer normalization or in `TrackingQuestionDetailView` preprocessing; the exact boundary remains to be reproduced before editing.
|
||||
- A web-search enablement function already exists and is called, including a Tools-menu fallback, but its success is inferred from text/color state and has not been verified against the outgoing chat request.
|
||||
- The response capture currently accepts every Yuanbao-host `/api/` response and merges all parsed candidates, rather than binding the result to the current POST chat SSE response.
|
||||
- `selectBestAnswerText` can replace a valid parsed API answer with a higher-scoring DOM answer, so the current implementation is not API-first.
|
||||
- Both `sanitizeAnswerCandidate` in the desktop adapter and `sanitizeAnswerBody` in admin-web split on repeated newlines and rejoin with single newlines. That destroys Markdown paragraph boundaries before `markdown-it` renders the answer.
|
||||
- Ranked diagnosis hypotheses: (1) DOM quality scoring overrides valid SSE; (2) broad capture mixes unrelated API responses; (3) search toggle detection reports a false positive; (4) admin sanitization removes Markdown block spacing; (5) stream-fragment merging itself damages Markdown.
|
||||
- `yuanbaoQueryInPage` already calls `ensureWebSearchEnabled`, so the implementation gap is verification and fail-closed search enablement rather than adding the call from scratch.
|
||||
- `selectBestAnswerText` is exported through `__yuanbaoTestUtils`, providing a direct deterministic seam for an API-priority regression test.
|
||||
- The API-priority regression test fails exactly as predicted: current selection returns the longer DOM/tooling text instead of valid SSE Markdown.
|
||||
- Recent real run `question_monitor_runs.id=1034` contains three concatenated layers: model reasoning, a corrupted partial answer, then the complete Markdown answer. Its raw metadata reports `candidate_count=782`, confirming broad capture/recursive merge contamination rather than a renderer-only defect.
|
||||
- The same real run reports `web_search_enabled=null` even though search sources were collected, so search execution occurred but UI state verification did not establish a reliable enabled state.
|
||||
- The stored answer already contains malformed/duplicated Markdown before admin-web renders it; admin newline normalization can worsen layout, but the primary corruption starts in desktop SSE aggregation.
|
||||
## 2026-07-12 Desktop Hunyuan/Yuanbao CDP findings
|
||||
|
||||
- Electron CDP at `127.0.0.1:9339` exposes two authenticated Yuanbao chat pages.
|
||||
- The current Yuanbao composer is a Quill `.ql-editor`; web search is not a persistent switch. It is an item inside the `工具` dropdown.
|
||||
- A CDP screenshot showed only the `深度思考` chip active at the composer. `联网搜索` was present only in the open tools menu, so web search was not enabled for that page.
|
||||
- `yuanbaoQueryInPage.ensureWebSearchEnabled()` currently falls back to `menuState ?? true` after clicking the menu item. The live menu item has no `aria-checked`, `aria-selected`, `aria-pressed`, or equivalent state attributes, so this path can report `true` without verifying that the active `联网搜索` chip actually appeared.
|
||||
- Next CDP probe: click the live `联网搜索` item, verify the active composer chip, then submit a short query while recording only the request method/URL, safe request-body shape, response content type, and SSE event shape.
|
||||
- CDP verified successful activation by the appearance of a visible `<span class="application-blot-ai-atom">联网搜索</span>` in the composer.
|
||||
- The authoritative response is `POST https://yuanbao.tencent.com/api/chat/{conversationId}` with `content-type: text/event-stream`.
|
||||
- The live search-enabled chat request contains `supportFunctions: ["openAutoSearchSwitch", "autoInternetSearch"]`; its model extension also contains `internetSearch` state.
|
||||
- One submission also emitted unrelated POSTs such as `updateModel`, `promptSug`, `hintV2`, and red-dot APIs. This confirms the current broad `/api/` capture admits unrelated payloads.
|
||||
- The captured official SSE contained 124 frames: 13 top-level `text` answer deltas, 105 `deepSearch` process frames, three `step` frames, one `searchGuid`, one `hint_v2_tip`, and a final `meta` frame with `endConv`. Recursively treating nested `deepSearch.contents` text as answer is the direct answer-contamination mechanism.
|
||||
- Implementation boundary selected: bind capture to the current question's POST chat SSE, compose answer only from top-level `text` frames, keep search/process frames source-only, prefer any usable SSE answer over DOM, and expose `response_source` diagnostics.
|
||||
- A live invocation of the updated `yuanbaoAdapter.query()` against the Electron CDP page passed in about 10 seconds. It asserted `status=succeeded`, `response_source=api_sse`, `web_search_enabled=true`, `capture_count=1`, and a non-empty API answer.
|
||||
- The current request-body equality filter was therefore validated against the real Yuanbao payload, not only a fixture: live `prompt` matches the submitted monitoring question and the official stream is retained.
|
||||
## 2026-07-12 AI platform multi-account request
|
||||
|
||||
- Desired behavior: one AI platform can bind multiple model accounts on the same desktop client.
|
||||
- Monitoring should try another healthy account from the same platform when the selected account triggers risk control/challenge or returns no usable result.
|
||||
- The current AI-platform screen presents one platform card with a single `当前账号`, so multi-account visibility and add-account controls are missing even if storage supports multiple rows.
|
||||
- Existing account rows and session partitions must remain intact; failover should happen within the same platform only and must not duplicate final task completion.
|
||||
- Server storage already supports multiple accounts: the active uniqueness key is `(workspace_id, client_id, platform_id, platform_uid)`, and desktop account list/upsert APIs are client-scoped.
|
||||
- `buildRuntimeAccountDedupeKey()` currently collapses every AI account to `ai-platform:{platform}`. The next sync then calls `cleanupDuplicateDesktopAccounts()`, tombstoning valid extra accounts and deleting their local sessions.
|
||||
- `noteRuntimeAccountBound()` also matches any existing AI account with the same platform, replaces it in memory, clears its health/session, and deletes its server row.
|
||||
- `monitorPlatformBlockedReason()` examines only the first current-client account. A challenged Doubao account therefore blocks the whole Doubao platform even when another account is active.
|
||||
- Server monitor tasks are completed once after local execution. The desktop can attempt several same-platform sessions inside one leased task and submit only the final result; no server schema change is required for failover.
|
||||
- Adapter results already feed `reportAccountFailure()`. Doubao challenge/risk-control responses become `challenge_required/risk_control`, enqueue a server health report, create a runtime activity warning, and surface through the existing Home/tray issue indicators.
|
||||
- Failover policy selected: skip blocked/expired/revoked/cooling accounts; try the server-preferred healthy account first, then least-recently-used same-platform accounts; cool risk/challenge/auth failures for 30 minutes, empty/unknown results briefly, and generic account-specific failures for a shorter interval.
|
||||
- The redesigned AI page follows the existing media-account management structure: account-level statistics, platform selector cards with counts/add actions, filters, and a per-account table.
|
||||
- Electron CDP visual verification at 1420x960 found no horizontal overflow or clipped controls. The live page showed three authorized AI accounts as separate rows and six model-platform selector cards.
|
||||
- Per-account challenge/risk text is rendered inside the affected account identity cell, while the status tag remains account-specific; healthy accounts from the same platform remain visible and usable.
|
||||
- Server monitor generation remains platform-scoped when multiple accounts are bound: `uniqueMonitorDesktopTaskPlatformIDs()` collapses duplicate platform specs, while `selectMonitorDesktopTaskTargetsWithOptions()` groups every account candidate by platform and returns at most one target for each platform. Extra same-platform accounts therefore form a desktop execution pool without multiplying questions or final task submissions.
|
||||
|
||||
## 2026-07-12 AI/media account UI alignment
|
||||
|
||||
- The media account page uses one consistent visual hierarchy: hero statistics, large platform authorization cards, and a bordered account-list panel with integrated filters.
|
||||
- The first AI multi-account implementation diverged by introducing compact selector cards and a separately styled table. Functionality matched, but card size, radius, spacing, status treatment, and table shell did not match Media Account Management.
|
||||
- Alignment boundary: reuse the media page's card and table composition while retaining AI-specific multi-account counts, add-account behavior, session/probe fields, and account-level risk-control warnings.
|
||||
- Electron CDP comparison at 1420x960 measured identical first-card geometry on both pages: 327x157, 20px radius, and 24px padding. Both account-list shells measured 1021px wide with 20px radius and hidden overflow.
|
||||
- At 1024x800, AI platform cards form a stable two-column grid, the account-list toolbar wraps to 116px high, and `body.scrollWidth === body.clientWidth === 1024`; no horizontal page overflow occurs.
|
||||
- The removed global “添加 AI 账号” action is absent from the live DOM. New accounts remain available through each platform card's “新增账号” or “绑定账号” action, matching Media Account Management.
|
||||
|
||||
## 2026-07-12 Admin AI account management extraction
|
||||
|
||||
- The embedded “AI 平台状态” section lives in `TrackingView.vue` and queries all tenant desktop accounts, but groups them by platform and exposes only `matchedAccounts[0]`; this hides additional same-platform accounts.
|
||||
- `/api/tenant/accounts` already returns account-level client, health, runtime authorization, verification, heartbeat, deletion, and session data. No new storage schema or list endpoint is required.
|
||||
- `tenantAccountsApi.remove(id)` and `requestDelete(id)` already support the same node-scoped unbind lifecycle used by Media Account Management.
|
||||
- The new management page should list only real bound AI accounts, one card per account. Platform coverage and health totals can preserve the former overview without rendering fake account cards for unbound platforms.
|
||||
|
||||
Reference in New Issue
Block a user