Files
geo/docs/superpowers/plans/2026-04-23-deepseek-monitoring.md
root f6e553dcc3 feat(monitoring): add DeepSeek monitoring end-to-end
- desktop: new DeepSeek page adapter and monitor registry
- desktop: extract generic AI auth helpers into shared module and
  skip binding when challenge signals are present
- admin-web: render DeepSeek HTML answers with inline citation anchors
  and surface reference-number badges on source cards
- server: fall back to inline_links/source_panel_links and read
  text/siteName fields when extracting DeepSeek citations

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:54:56 +08:00

8.4 KiB
Raw Permalink Blame History

DeepSeek Monitoring Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add production-usable deepseek desktop monitoring support with answer capture, citation extraction, runtime routing, and regression coverage.

Architecture: Reuse the existing generic AI auth flow, add a new Playwright-based desktop monitor adapter for DeepSeek, register it in the desktop runtime, and keep server-side result ingestion unchanged. The adapter should favor structured page observation plus network-response capture so answer capture and citation extraction can degrade independently.

Tech Stack: TypeScript + Vitest in apps/desktop-client, Go + testing in server/internal/tenant/app, Playwright hidden-page execution, pnpm workspace, existing shared monitoring payload contracts.


Task 1: Lock In Failing Tests First

Files:

  • Create: apps/desktop-client/src/main/adapters/deepseek.test.ts

  • Modify: server/internal/tenant/app/monitoring_callback_service_test.go

  • Step 1: Write the failing desktop adapter helper tests

import { describe, expect, it } from "vitest";

import { __deepseekTestUtils } from "./deepseek";

const {
  extractQuestionText,
  dedupeSourceItems,
  classifyDeepseekSources,
  isObservationComplete,
} = __deepseekTestUtils;

describe("deepseek adapter helpers", () => {
  it("extracts question text from monitoring payload", () => {
    expect(extractQuestionText({ question_text: "DeepSeek 怎么看 GEO" })).toBe("DeepSeek 怎么看 GEO");
  });

  it("dedupes sources by normalized url", () => {
    const items = dedupeSourceItems([
      { url: "https://example.com/a#top", normalized_url: "https://example.com/a#top" },
      { url: "https://example.com/a#bottom", normalized_url: "https://example.com/a#bottom" },
    ]);

    expect(items).toHaveLength(1);
    expect(items[0]?.normalized_url).toBe("https://example.com/a");
  });

  it("separates citations from search-style sources", () => {
    const classified = classifyDeepseekSources({
      inlineLinks: [{ url: "https://example.com/citation", normalized_url: "https://example.com/citation" }],
      sourcePanelLinks: [],
      searchPanelLinks: [{ url: "https://example.com/search", normalized_url: "https://example.com/search" }],
    });

    expect(classified.citations).toHaveLength(1);
    expect(classified.searchResults).toHaveLength(1);
  });

  it("treats a stable answer as complete even without citations", () => {
    expect(isObservationComplete({
      answer: "这是最终答案",
      busy: false,
      loginRequired: false,
      challengeRequired: false,
      signature: "sig-1",
    })).toBe(true);
  });
});
  • Step 2: Run the new desktop test to verify it fails

Run:

pnpm --filter @geo/desktop-client test apps/desktop-client/src/main/adapters/deepseek.test.ts

Expected:

  • FAIL because ./deepseek does not exist yet

  • Step 3: Write the failing server regression test

func TestBuildMonitoringRawPayloadDeepSeekIncludesSearchResultsInCitationInputs(t *testing.T) {
	searchTitle := "搜索网页结果"

	req := MonitoringTaskResultRequest{
		Status: "succeeded",
		SearchResults: []MonitoringSourceItem{
			{
				URL:   "https://example.com/search",
				Title: &searchTitle,
			},
		},
	}

	_, sourceInputs := buildMonitoringRawPayload("deepseek", req)
	if len(sourceInputs) != 1 {
		t.Fatalf("buildMonitoringRawPayload() sourceInputs len = %d, want 1", len(sourceInputs))
	}
	if sourceInputs[0].URL != "https://example.com/search" {
		t.Fatalf("buildMonitoringRawPayload() source url = %q, want search url", sourceInputs[0].URL)
	}
}
  • Step 4: Run the targeted Go test to verify the new assertion state

Run:

cd server && go test ./internal/tenant/app -run TestBuildMonitoringRawPayloadDeepSeekIncludesSearchResultsInCitationInputs -count=1

Expected:

  • PASS or FAIL is acceptable here, but the test must compile and pin the intended DeepSeek ingestion behavior before adapter code lands

Task 2: Implement the DeepSeek Desktop Adapter

Files:

  • Create: apps/desktop-client/src/main/adapters/deepseek.ts

  • Modify: apps/desktop-client/src/main/adapters/index.ts

  • Modify: apps/desktop-client/src/main/runtime-controller.ts

  • Step 1: Add the adapter skeleton and helper exports

export const deepseekAdapter: MonitorAdapter = {
  provider: "deepseek",
  executionMode: "playwright",
  async query(context, payload) {
    // implement after tests are in place
  },
};

export const __deepseekTestUtils = {
  extractQuestionText,
  dedupeSourceItems,
  classifyDeepseekSources,
  isObservationComplete,
};
  • Step 2: Implement page bootstrap and observation helpers
async function ensurePageOnDeepSeekChat(page: PlaywrightPage, signal: AbortSignal): Promise<void> {
  if (signal.aborted) {
    throw new Error("adapter_aborted");
  }

  if (!page.url() || !page.url().startsWith("https://chat.deepseek.com/")) {
    await page.goto("https://chat.deepseek.com/", {
      waitUntil: "domcontentloaded",
      timeout: 20_000,
    });
  }

  await page.waitForLoadState("domcontentloaded", { timeout: 20_000 }).catch(() => undefined);
  await page.waitForLoadState("networkidle", { timeout: 3_000 }).catch(() => undefined);
}
  • Step 3: Implement answer submission, wait loop, and citation extraction
const result = await waitForDeepSeekAnswer(page, questionText, context.signal);
const classified = classifyDeepseekSources({
  inlineLinks: result.inlineLinks,
  sourcePanelLinks: result.sourcePanelLinks,
  searchPanelLinks: result.searchPanelLinks,
});

return {
  status: "succeeded",
  summary: "DeepSeek 监控任务执行成功。",
  payload: {
    platform: "deepseek",
    provider_model: result.providerModel ?? "deepseek-chat",
    provider_request_id: result.providerRequestID,
    request_id: result.requestID,
    answer: result.answer,
    citations: toJsonSources(classified.citations),
    search_results: toJsonSources(classified.searchResults),
    raw_response_json: {
      platform: "deepseek",
      page_url: result.url,
      answer: result.answer,
      citations: toJsonSources(classified.citations),
      search_results: toJsonSources(classified.searchResults),
    },
  },
};
  • Step 4: Register the adapter in exports and runtime routing
export * from "./deepseek";
import { deepseekAdapter } from "./adapters";

if (platform === deepseekAdapter.provider) {
  return deepseekAdapter;
}
  • Step 5: Run the desktop DeepSeek tests to verify they now pass

Run:

pnpm --filter @geo/desktop-client test apps/desktop-client/src/main/adapters/deepseek.test.ts

Expected:

  • PASS

Task 3: Verify Integration Boundaries

Files:

  • Modify: apps/desktop-client/src/main/platform-auth-adapters.ts only if DeepSeek-specific auth/risk strings are discovered during implementation

  • Modify: server/internal/tenant/app/monitoring_callback_service_test.go

  • Step 1: Keep server ingestion behavior explicit for DeepSeek

func TestBuildMonitoringRawPayloadDeepSeekIncludesSearchResultsInCitationInputs(t *testing.T) {
	// keep DeepSeek aligned with the default non-Kimi ingestion path
}
  • Step 2: Run the combined targeted verification suite

Run:

pnpm --filter @geo/desktop-client test apps/desktop-client/src/main/adapters/deepseek.test.ts apps/desktop-client/src/main/platform-auth-adapters.test.ts
cd server && go test ./internal/tenant/app -run 'TestBuildMonitoringRawPayload(DeepSeek|Qwen|Kimi)|TestExtractMonitoringInlineCitationsFromRawResponseKimi' -count=1

Expected:

  • all targeted tests pass

  • Step 3: Run desktop typecheck

Run:

pnpm typecheck:desktop

Expected:

  • PASS with no new type errors from the DeepSeek adapter wiring

  • Step 4: Commit the implementation

git add apps/desktop-client/src/main/adapters/deepseek.ts \
        apps/desktop-client/src/main/adapters/deepseek.test.ts \
        apps/desktop-client/src/main/adapters/index.ts \
        apps/desktop-client/src/main/runtime-controller.ts \
        server/internal/tenant/app/monitoring_callback_service_test.go \
        docs/superpowers/plans/2026-04-23-deepseek-monitoring.md
git commit -m "feat(desktop): add DeepSeek monitoring adapter"