diff --git a/packages/client/ui-settings-account/README.i18n.yaml b/packages/client/ui-settings-account/README.i18n.yaml index 1b597f4d27..dffb10cbad 100644 --- a/packages/client/ui-settings-account/README.i18n.yaml +++ b/packages/client/ui-settings-account/README.i18n.yaml @@ -9,8 +9,8 @@ en: 9ff7ac2d70f70b59 zh: ded522c4cfd6e040 /deepseek-ai-dsh-client-ui-settings-account/summary: - en: 9ff357621753be69 - zh: 3f7ede82acc9fa31 + en: 9578b8d11eb138a1 + zh: d031db76109178ad /deepseek-ai-dsh-client-ui-settings-account/table-of-contents: en: c26f81e8adf0128b zh: e11ab371f51f66bc diff --git a/packages/client/ui-settings-account/README.md b/packages/client/ui-settings-account/README.md index 18604436f7..7d847b0ab6 100644 --- a/packages/client/ui-settings-account/README.md +++ b/packages/client/ui-settings-account/README.md @@ -13,6 +13,8 @@ Server-expired account credentials clear the displayed account details and emit ## Summary +The sign-in dialog offers network troubleshooting only for `no-response` failures. HTTP, business, response-validation, storage, and account-stream failures retain the generic retry message. + The Account settings section displays DeepSeek login state and offers browser sign-in and cancellation; the sidebar account menu provides Platform sign-out. Desktop users also receive a resumable introduction to account credit and presentation preferences. ## Table of Contents diff --git a/packages/client/ui-settings-account/README.zh.md b/packages/client/ui-settings-account/README.zh.md index ccc6daaeae..653c05d0d5 100644 --- a/packages/client/ui-settings-account/README.zh.md +++ b/packages/client/ui-settings-account/README.zh.md @@ -13,6 +13,8 @@ kind: "package-reference" ## 概述 +登录弹窗仅对 `no-response` 失败提示检查网络。HTTP、业务、响应校验、存储和账号状态流失败仍显示通用重试提示。 + 设置中的账号页面显示 DeepSeek 登录状态,并提供浏览器登录和取消;侧边栏账号菜单提供 Platform 退出登录。Desktop 用户还会进入可恢复的引导,了解账号额度并选择展示偏好。 ## 目录 diff --git a/packages/client/ui-settings-account/src/client/SignInDialog.tsx b/packages/client/ui-settings-account/src/client/SignInDialog.tsx index f07b505d8a..cef9e1d701 100644 --- a/packages/client/ui-settings-account/src/client/SignInDialog.tsx +++ b/packages/client/ui-settings-account/src/client/SignInDialog.tsx @@ -33,6 +33,8 @@ export function SignInDialog({ account, colorScheme, start, cancel, close, useAp const active = busy || phase === 'initializing' || phase === 'waiting-browser' || phase === 'exchanging' || phase === 'committing' const expired = phase === 'expired' const error = failed || account.loginFailed || account.failed || phase === 'failed' + const failureKey = !failed && !account.loginFailed && !account.failed + && phase === 'failed' && attempt?.errorCode === 'no-response' ? 'noResponse' : 'failed' const waiting = active && !error const committing = phase === 'committing' useEffect(() => { if (account.view?.status === 'credential-stored') close() }, [account.view?.status, close]) @@ -71,7 +73,7 @@ export function SignInDialog({ account, colorScheme, start, cancel, close, useAp {t(copyResult?.messageKey ?? 'copyLink')} {t('browserDescription')}

:

- {error ? t('failed') : expired ? t('timeoutDescription') : t('loginDescription')} + {error ? t(failureKey) : expired ? t('timeoutDescription') : t('loginDescription')}

}
diff --git a/packages/client/ui-settings-account/src/client/locales.ts b/packages/client/ui-settings-account/src/client/locales.ts index e6f743a4a5..b38e869eb9 100644 --- a/packages/client/ui-settings-account/src/client/locales.ts +++ b/packages/client/ui-settings-account/src/client/locales.ts @@ -23,6 +23,7 @@ export const en = { initializing: 'Starting sign in…', waiting: 'Continue in your browser', completing: 'Completing sign in…', expired: 'Sign in expired. Try again.', failed: 'Could not complete the operation. Try again.', + noResponse: 'Something went wrong. Please check your network connection and try again.', settingsSignedOutTitle: 'You are not signed in to DeepSeek Harness', settingsSignedOutDescription: 'Sign in to DeepSeek Harness to get your dedicated API Key', signInDescription: 'Use your DeepSeek account to get started.', @@ -58,6 +59,7 @@ export const zh: Record = { initializing: '正在发起登录…', waiting: '请在浏览器中继续', completing: '正在完成登录…', expired: '登录已过期,请重试。', failed: '操作未完成,请重试。', + noResponse: '操作未完成,可能是网络异常,请检查你的网络状况后重试', settingsSignedOutTitle: '当前未登录 DeepSeek Harness 账号', settingsSignedOutDescription: '登录 DeepSeek Harness 账号获取专属 API Key', signInDescription: '登录 DeepSeek 账号以开始使用', diff --git a/packages/client/ui-settings-account/tests/expected/login-no-response-en.txt b/packages/client/ui-settings-account/tests/expected/login-no-response-en.txt new file mode 100644 index 0000000000..fc7fd18766 --- /dev/null +++ b/packages/client/ui-settings-account/tests/expected/login-no-response-en.txt @@ -0,0 +1 @@ +Could not sign inSomething went wrong. Please check your network connection and try again.Add API KeySign in again diff --git a/packages/client/ui-settings-account/tests/expected/login-no-response-zh.txt b/packages/client/ui-settings-account/tests/expected/login-no-response-zh.txt new file mode 100644 index 0000000000..19784e281b --- /dev/null +++ b/packages/client/ui-settings-account/tests/expected/login-no-response-zh.txt @@ -0,0 +1 @@ +登录失败操作未完成,可能是网络异常,请检查你的网络状况后重试添加 API Key重新登录 diff --git a/packages/client/ui-settings-account/tests/sign-in-dialog.client.spec.tsx b/packages/client/ui-settings-account/tests/sign-in-dialog.client.spec.tsx index c03b3613d8..9cd8ef5a37 100644 --- a/packages/client/ui-settings-account/tests/sign-in-dialog.client.spec.tsx +++ b/packages/client/ui-settings-account/tests/sign-in-dialog.client.spec.tsx @@ -191,3 +191,24 @@ it('does not report workspace login views or login choices', async () => { expect(props.useApiKey).toHaveBeenCalledOnce() expect(track).not.toHaveBeenCalled() }) + +it.each([en, zh])('shows network advice only when the login request received no response', async (copy) => { + const props = mount({ id, phase: 'failed', errorCode: 'no-response' }, copy) + await expect(`${screen.getByRole('dialog').textContent}\n`).toMatchFileSnapshot(`./expected/login-no-response-${copy === en ? 'en' : 'zh'}.txt`) + await act(async () => { fireEvent.click(screen.getByRole('button', { name: copy.retry })) }) + expect(props.start).toHaveBeenCalledOnce() +}) + +it.each(['network', 'protocol', 'storage'] as const)('keeps generic copy for %s failures', (errorCode) => { + mount({ id, phase: 'failed', errorCode }) + expect(screen.getByText(en.failed)).toBeTruthy() + expect(screen.queryByText(en.noResponse)).toBeNull() +}) + +it('does not reuse network advice for a subsequent start failure', async () => { + const props = mount({ id, phase: 'failed', errorCode: 'no-response' }) + props.start.mockRejectedValueOnce(new Error('RPC failed')) + await act(async () => { fireEvent.click(screen.getByRole('button', { name: en.retry })) }) + expect(screen.getByText(en.failed)).toBeTruthy() + expect(screen.queryByText(en.noResponse)).toBeNull() +}) diff --git a/packages/credentials/deepseek-account-platform/README.i18n.yaml b/packages/credentials/deepseek-account-platform/README.i18n.yaml index 95c17ea670..21d6772de9 100644 --- a/packages/credentials/deepseek-account-platform/README.i18n.yaml +++ b/packages/credentials/deepseek-account-platform/README.i18n.yaml @@ -9,8 +9,8 @@ en: 7be860d52e1202db zh: a2612757253d67a6 /deepseek-ai-dsh-deepseek-account-platform/summary: - en: ce3da383e4b065d8 - zh: 56d68ad8ee1c27a8 + en: 64ed24b5cac74d92 + zh: ca9deb0d61b500db /deepseek-ai-dsh-deepseek-account-platform/table-of-contents: en: af856ba79fe31b8e zh: 15b7d1a5d1856de2 diff --git a/packages/credentials/deepseek-account-platform/README.md b/packages/credentials/deepseek-account-platform/README.md index abaa130b40..ba569060e1 100644 --- a/packages/credentials/deepseek-account-platform/README.md +++ b/packages/credentials/deepseek-account-platform/README.md @@ -17,6 +17,8 @@ Profile and balance HTTP 401 responses or top-level response code `40003` (inval ## Summary +Platform requests report `no-response` when fetch rejects before returning a Response, including request timeouts. HTTP errors and response-body failures do not use this code; authorization-attempt expiry retains `expired`. + Sign in through the system browser and keep the account credential in the existing local credential store. Local cancellation prevents late callbacks and exchange responses from signing the user in. Device identity reads validate the existing login device record and expose only its ID, the current account ID, and the shared login OS version string. diff --git a/packages/credentials/deepseek-account-platform/README.zh.md b/packages/credentials/deepseek-account-platform/README.zh.md index f976a1890b..e1192d1109 100644 --- a/packages/credentials/deepseek-account-platform/README.zh.md +++ b/packages/credentials/deepseek-account-platform/README.zh.md @@ -17,6 +17,8 @@ getPlatformSession 仅在已存授权的 issuer 与 platformOrigin 一致时导 ## 概述 +当 fetch 在返回 Response 前拒绝(包括单次请求超时)时,Platform 请求报告 `no-response`。HTTP 错误和响应体失败不使用此代码;授权尝试到期仍使用 `expired`。 + 通过系统浏览器登录,并将账号凭证保存在现有本地凭证存储中。本地取消会阻止迟到的回调和兑换响应使用户登录。 设备身份读取会校验已有登录设备记录,仅提供设备 ID、当前账户 ID 和与登录共用的操作系统版本字符串。 diff --git a/packages/credentials/deepseek-account-platform/src/protocol.ts b/packages/credentials/deepseek-account-platform/src/protocol.ts index 10f2993546..a8ab9b3d3c 100644 --- a/packages/credentials/deepseek-account-platform/src/protocol.ts +++ b/packages/credentials/deepseek-account-platform/src/protocol.ts @@ -1,11 +1,11 @@ /** Validated platform HTTP messages and restricted browser destinations. */ import { z } from 'zod' -import type { AccountBonusOrderId } from '@deepseek-ai/dsh-deepseek-account/types' +import type { AccountBonusOrderId, SignInErrorCode } from '@deepseek-ai/dsh-deepseek-account/types' /** Protocol errors expose a stable code, never a response body or authorization URL. */ export class PlatformAuthError extends Error { /** @param code - safe error classification. */ - constructor(readonly code: 'network' | 'protocol' | 'expired' | 'storage') { super(`account: ${code}`) } + constructor(readonly code: SignInErrorCode) { super(`account: ${code}`) } } /** An authenticated Platform request was rejected with HTTP 401 or code 40003. */ @@ -170,8 +170,8 @@ async function platformRequest(url: string, init: RequestInit, signal: AbortSign try { response = await fetch(url, { ...init, redirect: 'error', signal }) } catch { - console.info('[deepseek-account] request failed', { path, errorCode: 'network', aborted: signal.aborted }) - throw new PlatformAuthError('network') + console.info('[deepseek-account] request failed', { path, errorCode: 'no-response', aborted: signal.aborted }) + throw new PlatformAuthError('no-response') } console.info('[deepseek-account] response', { path, status: response.status }) if (response.status === 401 && new Headers(init.headers).has('x-dsh-auth-token')) { diff --git a/packages/credentials/deepseek-account-platform/tests/diagnostics.spec.ts b/packages/credentials/deepseek-account-platform/tests/diagnostics.spec.ts index be3203bc08..55e41ac62b 100644 --- a/packages/credentials/deepseek-account-platform/tests/diagnostics.spec.ts +++ b/packages/credentials/deepseek-account-platform/tests/diagnostics.spec.ts @@ -44,9 +44,9 @@ it('reports transport failure without exposing the thrown error', async () => { const fetcher = vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('private-network-detail')) try { await expect(requestPlatform('https://platform.deepseek.com', 'auth_init', {}, - new AbortController().signal, {})).rejects.toThrow('account: network') + new AbortController().signal, {})).rejects.toThrow('account: no-response') const logged = JSON.stringify(output.mock.calls) - expect(logged).toContain('network') + expect(logged).toContain('no-response') expect(logged).not.toContain('private-network-detail') } finally { fetcher.mockRestore() diff --git a/packages/credentials/deepseek-account/README.i18n.yaml b/packages/credentials/deepseek-account/README.i18n.yaml index 4771c5591d..1d96b9d325 100644 --- a/packages/credentials/deepseek-account/README.i18n.yaml +++ b/packages/credentials/deepseek-account/README.i18n.yaml @@ -9,8 +9,8 @@ en: fcacd6de573d7636 zh: 6dbbc05a66dbb126 /deepseek-ai-dsh-deepseek-account/summary: - en: c41643b81a07a489 - zh: 2c16999de40a67b9 + en: 8e8365fea2a07a9f + zh: c8eef466dd505ca2 /deepseek-ai-dsh-deepseek-account/table-of-contents: en: af856ba79fe31b8e zh: 15b7d1a5d1856de2 diff --git a/packages/credentials/deepseek-account/README.md b/packages/credentials/deepseek-account/README.md index 0c134ca325..f092fd69f7 100644 --- a/packages/credentials/deepseek-account/README.md +++ b/packages/credentials/deepseek-account/README.md @@ -19,6 +19,8 @@ getUnnotifiedBonuses returns the granted bonuses Platform has not yet recorded a ## Summary +`SignInErrorCode` distinguishes `no-response` (fetch returned no Response) from HTTP and response-validation failures so clients can offer network troubleshooting. + Account consumers read stored login state, start or cancel a browser login, and sign out without editing API keys. Host model consumers resolve account credentials only for the provider-configured inference origin. `getDeviceIdentity()` returns existing device and account IDs plus the login OS version string, without credentials or device creation. diff --git a/packages/credentials/deepseek-account/README.zh.md b/packages/credentials/deepseek-account/README.zh.md index 24844185dc..73a364f21d 100644 --- a/packages/credentials/deepseek-account/README.zh.md +++ b/packages/credentials/deepseek-account/README.zh.md @@ -19,6 +19,8 @@ getUnnotifiedBonuses 返回平台尚未记录为已展示的赠金及其所属 ## 概述 +`SignInErrorCode` 将 `no-response`(fetch 未返回 Response)与 HTTP 和响应校验失败区分开,使客户端可以提示检查网络。 + 账号使用方可读取本地登录状态、发起或取消浏览器登录,并在保留 API Key 的情况下退出。Host 模型使用方仅能为提供者配置的推理来源解析账号凭证。 `getDeviceIdentity()` 返回已有设备和账户 ID 以及登录使用的操作系统版本字符串,不返回凭据,也不创建设备标识。 diff --git a/packages/credentials/deepseek-account/src/types.ts b/packages/credentials/deepseek-account/src/types.ts index 414388ef46..2ef34f2502 100644 --- a/packages/credentials/deepseek-account/src/types.ts +++ b/packages/credentials/deepseek-account/src/types.ts @@ -13,8 +13,8 @@ export interface AccountClientMetadata { /** Identity of one local login attempt, unrelated to the platform request ID. */ export type SignInAttemptId = Branded<'SignInAttemptId'> -/** Safe failure codes rendered through the caller's locale dictionary. */ -export type SignInErrorCode = 'network' | 'protocol' | 'expired' | 'storage' +/** Safe failure codes rendered through the caller's locale dictionary; no-response means fetch returned no Response. */ +export type SignInErrorCode = 'no-response' | 'network' | 'protocol' | 'expired' | 'storage' /** Latest login attempt, including terminal outcomes until the next attempt. */ export interface SignInAttemptView { readonly id: SignInAttemptId diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts index 597b046378..ce3853df6c 100644 --- a/packages/extensions/tool-cordis/src/api-catalog.ts +++ b/packages/extensions/tool-cordis/src/api-catalog.ts @@ -7039,7 +7039,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SignInErrorCode', - declaration: 'export type SignInErrorCode = \'network\' | \'protocol\' | \'expired\' | \'storage\';', + declaration: 'export type SignInErrorCode = \'no-response\' | \'network\' | \'protocol\' | \'expired\' | \'storage\';', }, { name: 'SkillCandidate',