Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Deep Code 使用 `settings.json` 设置文件进行持久化配置,支持两
| `thinkingEnabled` | boolean | 是否启用思考模式(DeepSeek V4 系列默认启用) |
| `reasoningEffort` | string | 推理强度,可选 `"high"` 或 `"max"`(默认 `"max"`) |
| `debugLogEnabled` | boolean | 是否启用调试日志输出(默认 `false`) |
| `telemetryEnabled` | boolean | 是否启用匿名使用数据上报(默认 `true`) |
| `notify` | string | 任务完成通知脚本的完整路径(如 Slack 通知脚本) |
| `webSearchTool` | string | 自定义联网搜索脚本的完整路径 |
| `mcpServers` | object | MCP 服务器配置(键为服务名,值为 McpServerConfig 对象) |
Expand All @@ -45,6 +46,7 @@ Deep Code 使用 `settings.json` 设置文件进行持久化配置,支持两
| `THINKING_ENABLED` | string | 是否启用思考模式 |
| `REASONING_EFFORT` | string | 推理强度 |
| `DEBUG_LOG_ENABLED` | string | 是否启用调试日志输出 |
| `TELEMETRY_ENABLED` | string | 是否启用匿名使用数据上报 |
| `<其他任意KEY>` | string | 自定义环境变量 |

#### `thinkingEnabled` — 思考模式
Expand Down Expand Up @@ -130,6 +132,16 @@ MCP(Model Context Protocol)服务器配置。值是键值对,键为服务

设为 `true` 可让程序输出详细的调试日志(默认 `false`),用于排查 API 调用和工具执行的问题。

#### `telemetryEnabled` — 匿名使用数据上报

设为 `false` 可关闭匿名使用数据上报(默认 `true`)。上报仅包含匿名的机器标识,不包含对话内容、代码或 API 密钥。

也可以通过环境变量关闭:

```bash
DEEPCODE_TELEMETRY_ENABLED=0 deepcode
```

## 环境变量优先级

环境变量是配置应用程序的常用方式,尤其适用于敏感信息(如 api-key)或可能在不同环境之间更改的设置。
Expand Down
12 changes: 12 additions & 0 deletions docs/configuration_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The following are all the top-level fields supported in `settings.json`, along w
| `thinkingEnabled` | boolean | Whether to enable thinking mode (enabled by default for DeepSeek V4 series)|
| `reasoningEffort` | string | Reasoning intensity, either `"high"` or `"max"` (default `"max"`) |
| `debugLogEnabled` | boolean | Enable debug log output (default `false`) |
| `telemetryEnabled` | boolean | Enable anonymous usage reporting (default `true`) |
| `notify` | string | Full path to a task-completion notification script (e.g., Slack notification script) |
| `webSearchTool` | string | Full path to a custom web search script |
| `mcpServers` | object | MCP server configurations (keys are service names, values are McpServerConfig objects) |
Expand All @@ -45,6 +46,7 @@ The following are all the top-level fields supported in `settings.json`, along w
| `THINKING_ENABLED`| string | Enable thinking mode |
| `REASONING_EFFORT`| string | Reasoning intensity |
| `DEBUG_LOG_ENABLED`| string| Enable debug log output |
| `TELEMETRY_ENABLED`| string| Enable anonymous usage reporting |
| `<any other KEY>` | string | Custom environment variable |

#### `thinkingEnabled` — Thinking Mode
Expand Down Expand Up @@ -129,6 +131,16 @@ For detailed MCP usage instructions, refer to [mcp.md](mcp.md).

Set to `true` to enable detailed debug logging (default `false`), useful for troubleshooting API calls and tool execution.

#### `telemetryEnabled` — Anonymous Usage Reporting

Set to `false` to disable anonymous usage reporting (default `true`). The report only includes an anonymous machine identifier and does not contain conversation content, code, or API keys.

You can also disable it via environment variable:

```bash
DEEPCODE_TELEMETRY_ENABLED=0 deepcode
```

## Environment Variable Priority

Environment variables are a common way to configure applications, especially for sensitive information (such as api-key) or settings that may change between environments.
Expand Down
4 changes: 4 additions & 0 deletions src/common/openai-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function createOpenAIClient(projectRoot: string = process.cwd()): {
thinkingEnabled: boolean;
reasoningEffort: "high" | "max";
debugLogEnabled: boolean;
telemetryEnabled: boolean;
notify?: string;
webSearchTool?: string;
env: Record<string, string>;
Expand All @@ -40,6 +41,7 @@ export function createOpenAIClient(projectRoot: string = process.cwd()): {
thinkingEnabled: settings.thinkingEnabled,
reasoningEffort: settings.reasoningEffort,
debugLogEnabled: settings.debugLogEnabled,
telemetryEnabled: settings.telemetryEnabled,
notify: settings.notify,
webSearchTool: settings.webSearchTool,
env: settings.env,
Expand All @@ -56,6 +58,7 @@ export function createOpenAIClient(projectRoot: string = process.cwd()): {
thinkingEnabled: settings.thinkingEnabled,
reasoningEffort: settings.reasoningEffort,
debugLogEnabled: settings.debugLogEnabled,
telemetryEnabled: settings.telemetryEnabled,
notify: settings.notify,
webSearchTool: settings.webSearchTool,
env: settings.env,
Expand Down Expand Up @@ -91,6 +94,7 @@ export function createOpenAIClient(projectRoot: string = process.cwd()): {
thinkingEnabled: settings.thinkingEnabled,
reasoningEffort: settings.reasoningEffort,
debugLogEnabled: settings.debugLogEnabled,
telemetryEnabled: settings.telemetryEnabled,
notify: settings.notify,
webSearchTool: settings.webSearchTool,
env: settings.env,
Expand Down
34 changes: 34 additions & 0 deletions src/common/telemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const DEFAULT_NEW_PROMPT_API_URL = "https://deepcode.vegamo.cn/api/plugin/new";
const DEFAULT_REPORT_TIMEOUT_MS = 3000;

export type NewPromptReportOptions = {
enabled: boolean;
machineId?: string;
timeoutMs?: number;
};

/**
* Fire-and-forget report of a new prompt session.
* Respects the `enabled` toggle: when disabled, the call is a no-op.
*/
export function reportNewPrompt(options: NewPromptReportOptions): void {
if (!options.enabled || !options.machineId) {
return;
}

const timeoutMs = options.timeoutMs ?? DEFAULT_REPORT_TIMEOUT_MS;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);

void fetch(DEFAULT_NEW_PROMPT_API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Token: options.machineId,
},
body: JSON.stringify({}),
signal: controller.signal,
})
.catch(() => {})
.finally(() => clearTimeout(timeout));
}
24 changes: 3 additions & 21 deletions src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
type UserToolPermission,
} from "./common/permissions";
import { clearSessionWorkingDir } from "./tools/bash-handler";
import { reportNewPrompt } from "./common/telemetry";

export type { PermissionScope } from "./settings";
export type {
Expand All @@ -59,8 +60,6 @@ export type {
const MAX_SESSION_ENTRIES = 50;
const MAX_PROJECT_CODE_LENGTH = 64;
const PROJECT_CODE_HASH_LENGTH = 16;
const DEFAULT_NEW_PROMPT_API_URL = "https://deepcode.vegamo.cn/api/plugin/new";
const NEW_PROMPT_REPORT_TIMEOUT_MS = 3000;
const DEFAULT_COMPACT_PROMPT_TOKEN_THRESHOLD = 128 * 1024;
const DEEPSEEK_V4_COMPACT_PROMPT_TOKEN_THRESHOLD = 512 * 1024;

Expand Down Expand Up @@ -1504,25 +1503,8 @@ ${skillMd}
}

private reportNewPrompt(): void {
const { machineId } = this.createOpenAIClient();
if (!machineId) {
return;
}

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), NEW_PROMPT_REPORT_TIMEOUT_MS);

void fetch(DEFAULT_NEW_PROMPT_API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Token: machineId,
},
body: JSON.stringify({}),
signal: controller.signal,
})
.catch(() => {})
.finally(() => clearTimeout(timeout));
const { machineId, telemetryEnabled } = this.createOpenAIClient();
reportNewPrompt({ enabled: telemetryEnabled ?? true, machineId });
}

interruptActiveSession(): void {
Expand Down
12 changes: 12 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type DeepcodingEnv = Record<string, string | undefined> & {
THINKING_ENABLED?: string;
REASONING_EFFORT?: string;
DEBUG_LOG_ENABLED?: string;
TELEMETRY_ENABLED?: string;
};

export type ReasoningEffort = "high" | "max";
Expand Down Expand Up @@ -47,6 +48,7 @@ export type DeepcodingSettings = {
thinkingEnabled?: boolean;
reasoningEffort?: ReasoningEffort;
debugLogEnabled?: boolean;
telemetryEnabled?: boolean;
notify?: string;
webSearchTool?: string;
mcpServers?: Record<string, McpServerConfig>;
Expand All @@ -61,6 +63,7 @@ export type ResolvedDeepcodingSettings = {
thinkingEnabled: boolean;
reasoningEffort: ReasoningEffort;
debugLogEnabled: boolean;
telemetryEnabled: boolean;
notify?: string;
webSearchTool?: string;
mcpServers?: Record<string, McpServerConfig>;
Expand Down Expand Up @@ -313,6 +316,14 @@ export function resolveSettingsSources(
parseBoolean(userEnv.DEBUG_LOG_ENABLED) ??
false;

const telemetryEnabled =
parseBoolean(systemEnv.TELEMETRY_ENABLED) ??
parseBoolean(projectSettings?.telemetryEnabled) ??
parseBoolean(projectEnv.TELEMETRY_ENABLED) ??
parseBoolean(userSettings?.telemetryEnabled) ??
parseBoolean(userEnv.TELEMETRY_ENABLED) ??
true;

const notify =
trimString(systemEnv.NOTIFY) || trimString(projectSettings?.notify) || trimString(userSettings?.notify) || "";
const webSearchTool =
Expand All @@ -329,6 +340,7 @@ export function resolveSettingsSources(
thinkingEnabled,
reasoningEffort,
debugLogEnabled,
telemetryEnabled,
notify: notify || undefined,
webSearchTool: webSearchTool || undefined,
mcpServers: mergeMcpServers(userSettings, projectSettings, userEnv, projectEnv, systemEnv),
Expand Down
34 changes: 34 additions & 0 deletions src/tests/settings-and-notify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,36 @@ test("resolveSettings reads THINKING_ENABLED, REASONING_EFFORT, and DEBUG_LOG_EN
assert.equal(resolved.baseURL, "https://default.example.com");
});

test("resolveSettings defaults telemetryEnabled to true", () => {
const resolved = resolveSettings(
{},
{ model: "default-model", baseURL: "https://default.example.com" },
TEST_PROCESS_ENV
);
assert.equal(resolved.telemetryEnabled, true);
});

test("resolveSettings reads TELEMETRY_ENABLED from env", () => {
const resolved = resolveSettings(
{ env: { TELEMETRY_ENABLED: "0" } },
{ model: "default-model", baseURL: "https://default.example.com" },
TEST_PROCESS_ENV
);
assert.equal(resolved.telemetryEnabled, false);
});

test("resolveSettings gives top-level telemetryEnabled priority over env TELEMETRY_ENABLED", () => {
const resolved = resolveSettings(
{
telemetryEnabled: false,
env: { TELEMETRY_ENABLED: "true" },
},
{ model: "default-model", baseURL: "https://default.example.com" },
TEST_PROCESS_ENV
);
assert.equal(resolved.telemetryEnabled, false);
});

test("resolveSettings ignores removed legacy env.THINKING", () => {
const resolved = resolveSettings(
{
Expand Down Expand Up @@ -115,6 +145,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
thinkingEnabled: true,
reasoningEffort: "max",
debugLogEnabled: true,
telemetryEnabled: false,
},
{
env: {
Expand All @@ -125,6 +156,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
},
model: "project-top-model",
thinkingEnabled: true,
telemetryEnabled: true,
},
{
model: "default-model",
Expand All @@ -135,6 +167,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
DEEPCODE_THINKING_ENABLED: "false",
DEEPCODE_REASONING_EFFORT: "high",
DEEPCODE_DEBUG_LOG_ENABLED: "true",
DEEPCODE_TELEMETRY_ENABLED: "false",
DEEPCODE_WEBHOOK: "system-webhook",
}
);
Expand All @@ -144,6 +177,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
assert.equal(resolved.thinkingEnabled, false);
assert.equal(resolved.reasoningEffort, "high");
assert.equal(resolved.debugLogEnabled, true);
assert.equal(resolved.telemetryEnabled, false);
assert.equal(resolved.env.WEBHOOK, "system-webhook");
});

Expand Down
Loading
Loading