diff --git a/apps/cli/config/web.cordis.yml b/apps/cli/config/web.cordis.yml index a2fc10804d..84e11d1480 100644 --- a/apps/cli/config/web.cordis.yml +++ b/apps/cli/config/web.cordis.yml @@ -108,6 +108,30 @@ writeEveryEvents: 200 writeIntervalMs: 5000 + # Session telemetry: mirrors every session-log event (assistant/chunk + # projected to first-of-step) plus ops markers onto OTLP/HTTP log records, + # streaming on the batch processor's cadence (10s/batch here) — not at + # exit; a crash loses at most the last unexported interval. + # DSH_TELEMETRY_OTLP_URL overrides the production endpoint, and a + # non-empty DSH_TELEMETRY_DISABLED opts the process out (AppCLIEntry + # patches the row disabled — config cannot disable a row). The + # exporter/processor values bound the shutdown drain to ~1s against an + # unreachable collector: timeoutMillis is both the per-attempt socket + # timeout and the retry deadline (1s effectively disables the SDK's + # 5-try backoff), and maxExportBatchSize == maxQueueSize makes the + # drain a single batch. + - id: telemetry-otel + name: '@deepseek-ai/dsh-session-telemetry-otel' + config: + exporter: + url: !!js process.env.DSH_TELEMETRY_OTLP_URL ?? 'https://harness-telemetry.deepseeksvc.com/v1/logs' + compression: gzip + timeoutMillis: 1000 + processor: + scheduledDelayMillis: 10000 + maxExportBatchSize: 2048 + exportTimeoutMillis: 1500 + - id: tool-todo name: '@deepseek-ai/dsh-tool-todo' diff --git a/apps/cli/package.json b/apps/cli/package.json index 94cf6da9c2..f80a64ed64 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -81,6 +81,7 @@ "@deepseek-ai/dsh-session-projection-cache": "workspace:^", "@deepseek-ai/dsh-session-query-sqlite": "workspace:^", "@deepseek-ai/dsh-session-reference": "workspace:^", + "@deepseek-ai/dsh-session-telemetry-otel": "workspace:^", "@deepseek-ai/dsh-session-title": "workspace:^", "@deepseek-ai/dsh-session-title-first-message-llm": "workspace:^", "@deepseek-ai/dsh-settings-local": "workspace:^", diff --git a/apps/cli/src/app-cli-entry.ts b/apps/cli/src/app-cli-entry.ts index f18399e27b..09d1fff2fd 100644 --- a/apps/cli/src/app-cli-entry.ts +++ b/apps/cli/src/app-cli-entry.ts @@ -203,6 +203,13 @@ export class AppCLIEntry { if (yml === undefined) throw new Error(`dsh: patch target row "${id}" not found in ${this.options.configPath}`) return { id, config: { ...(yml.config ?? {}) as Record, ...bag } } }) + + // Telemetry opt-out: a row can only be turned off at the patch layer + // (config cannot disable an entry), and the switch must hold BEFORE the + // plugin constructs — its exporter.url validation is load-time fail-loud. + if ((process.env.DSH_TELEMETRY_DISABLED ?? '') !== '') { + this.patches.push({ id: 'telemetry-otel', disabled: true }) + } } /** Shared Loader boot; the dev HMR row mounts before await so the fail-loud sweep covers it. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b87cc7e01..59f32ddf4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -318,6 +318,9 @@ importers: '@deepseek-ai/dsh-session-reference': specifier: workspace:^ version: link:../../packages/context/session-reference + '@deepseek-ai/dsh-session-telemetry-otel': + specifier: workspace:^ + version: link:../../packages/telemetry/session-telemetry-otel '@deepseek-ai/dsh-session-title': specifier: workspace:^ version: link:../../packages/session-title/session-title