Files
openclaw/extensions/deepseek/index.ts
litang9 d446c26acb feat(deepseek): show provider balance in usage status
Show DeepSeek API-key account balance in status/auth-status usage surfaces by adding a summary-only provider usage snapshot path, a DeepSeek balance fetcher, SDK/docs coverage, and focused regression tests.

Maintainer verification accepted the additive provider-usage/status contract and the DeepSeek balance visibility boundary for authenticated status surfaces.

Proof:
- Live DeepSeek balance proof via 1Password-backed DEEPSEEK_API_KEY against https://api.deepseek.com/user/balance; key and balance amount redacted.
- GitHub CI run 26717953383 passed on the current head.
- Real behavior proof run 26718215605 passed after the PR body was refreshed.
- Local clean PR clone: git diff --check; node --max-old-space-size=8192 --import tsx scripts/generate-plugin-sdk-api-baseline.ts --check; node scripts/run-vitest.mjs run src/agents/bash-tools.exec.path.test.ts.

Co-authored-by: Alex Tang <tangli1987118@hotmail.com>
Co-authored-by: litang9 <141409885+litang9@users.noreply.github.com>
2026-05-31 17:35:41 +01:00

68 lines
2.6 KiB
TypeScript

import { readConfiguredProviderCatalogEntries } from "openclaw/plugin-sdk/provider-catalog-shared";
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
import { buildProviderToolCompatFamilyHooks } from "openclaw/plugin-sdk/provider-tools";
import { fetchDeepSeekUsage } from "openclaw/plugin-sdk/provider-usage";
import { applyDeepSeekConfig, DEEPSEEK_DEFAULT_MODEL_REF } from "./onboard.js";
import { buildDeepSeekProvider } from "./provider-catalog.js";
import { createDeepSeekV4ThinkingWrapper } from "./stream.js";
import { resolveDeepSeekV4ThinkingProfile } from "./thinking.js";
const PROVIDER_ID = "deepseek";
export default defineSingleProviderPluginEntry({
id: PROVIDER_ID,
name: "DeepSeek Provider",
description: "Bundled DeepSeek provider plugin",
provider: {
label: "DeepSeek",
docsPath: "/providers/deepseek",
auth: [
{
methodId: "api-key",
label: "DeepSeek API key",
hint: "API key",
optionKey: "deepseekApiKey",
flagName: "--deepseek-api-key",
envVar: "DEEPSEEK_API_KEY",
promptMessage: "Enter DeepSeek API key",
defaultModel: DEEPSEEK_DEFAULT_MODEL_REF,
applyConfig: (cfg) => applyDeepSeekConfig(cfg),
wizard: {
choiceId: "deepseek-api-key",
choiceLabel: "DeepSeek API key",
groupId: "deepseek",
groupLabel: "DeepSeek",
groupHint: "API key",
},
},
],
catalog: {
buildProvider: buildDeepSeekProvider,
},
augmentModelCatalog: ({ config }) =>
readConfiguredProviderCatalogEntries({
config,
providerId: PROVIDER_ID,
}),
matchesContextOverflowError: ({ errorMessage }) =>
/\bdeepseek\b.*(?:input.*too long|context.*exceed)/i.test(errorMessage),
...buildProviderReplayFamilyHooks({
family: "openai-compatible",
dropReasoningFromHistory: false,
}),
...buildProviderToolCompatFamilyHooks("deepseek"),
wrapStreamFn: (ctx) => createDeepSeekV4ThinkingWrapper(ctx.streamFn, ctx.thinkingLevel),
resolveThinkingProfile: ({ modelId }) => resolveDeepSeekV4ThinkingProfile(modelId),
isModernModelRef: ({ modelId }) => Boolean(resolveDeepSeekV4ThinkingProfile(modelId)),
resolveUsageAuth: async (ctx) => {
const apiKey = ctx.resolveApiKeyFromConfigAndStore({
envDirect: [ctx.env.DEEPSEEK_API_KEY],
});
return apiKey ? { token: apiKey } : null;
},
fetchUsageSnapshot: async (ctx) =>
await fetchDeepSeekUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn),
},
});