@denpex/sdk 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -4,7 +4,7 @@ export interface DenpexClientOptions {
4
4
  baseUrl?: string;
5
5
  /** Override fetch (tests, custom agents). Defaults to globalThis.fetch. */
6
6
  fetchImpl?: typeof fetch;
7
- /** Per-request timeout in ms (AbortController). Default 320s — server deep-path ceiling is 290s. */
7
+ /** Per-request timeout in ms (AbortController). Default 320s. The server deep-path ceiling is 290s. */
8
8
  timeoutMs?: number;
9
9
  }
10
10
  export interface DiagnoseOptions {
@@ -33,12 +33,12 @@ export interface DiagnoseMeta {
33
33
  confidence?: number;
34
34
  source?: string;
35
35
  tier?: number;
36
- /** Engine build stamp — compare across surfaces to detect a stale deploy. */
36
+ /** Engine build stamp. Compare across surfaces to detect a stale deploy. */
37
37
  engineVersion?: string;
38
38
  }
39
39
  /**
40
40
  * The known response fields. The engine attaches additional sections as it
41
- * grows (forensics, advisories, execution plans) — they pass through untyped
41
+ * grows (forensics, advisories, execution plans). They pass through untyped
42
42
  * rather than being silently dropped, so SDK users always receive everything
43
43
  * the API returned.
44
44
  */
@@ -51,7 +51,7 @@ export interface DiagnoseMeta {
51
51
  * few lines, so treat the node as the stronger signal of the two.
52
52
  *
53
53
  * `analyzedLines` < `totalLines` means the paste exceeded the window the engine
54
- * reads — the verdict covers only what was analysed.
54
+ * reads. The verdict covers only what was analysed.
55
55
  */
56
56
  export interface DiagnoseInitiator {
57
57
  rank?: number | null;
@@ -86,6 +86,16 @@ export interface ClarifyingQuestion {
86
86
  command?: string;
87
87
  }
88
88
  export interface DiagnoseResponse {
89
+ /** Automated review signals, never independent proof of correctness. */
90
+ qualityReview?: {
91
+ schemaVersion: number;
92
+ status: 'needs_review' | 'no_flagged_issue';
93
+ family: string;
94
+ flags: string[];
95
+ verification: 'unverified';
96
+ engineVersion?: string;
97
+ note?: string;
98
+ };
89
99
  fix?: {
90
100
  summary?: string;
91
101
  action?: string;
@@ -139,11 +149,11 @@ export declare class DenpexClient {
139
149
  private readonly fetchImpl;
140
150
  private readonly timeoutMs;
141
151
  constructor(options: DenpexClientOptions);
142
- /** Diagnose a training failure from raw logs (20 chars – 256 KB). */
152
+ /** Diagnose a training failure from raw logs. Oversized input is evidence-selected. */
143
153
  diagnose(logs: string, opts?: DiagnoseOptions): Promise<DiagnoseResponse>;
144
154
  /** Re-run the canonical diagnosis with observed facts or a selected evidence check. */
145
155
  refine(logs: string, operatorAnswers: OperatorAnswerInput[], opts?: Omit<DiagnoseOptions, 'operatorAnswers'>): Promise<DiagnoseResponse>;
146
- /** Report whether a diagnosis worked — this feedback directly improves future priors. */
156
+ /** Report whether a diagnosis worked. This feedback directly improves future priors. */
147
157
  feedback(diagnosisId: string, outcome: FeedbackOutcome, note?: string): Promise<Record<string, unknown>>;
148
158
  /** Remaining diagnosis headroom for this key's plan. */
149
159
  quota(): Promise<QuotaResponse>;
package/dist/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // @denpex/sdk — TypeScript client for the Denpex public API.
2
+ // @denpex/sdk: TypeScript client for the Denpex public API.
3
3
  //
4
4
  // Rewritten 2026-07-20: the previous file was a stub for /v1/{tenant}/incidents
5
5
  // routes that do not exist in the api-worker. This client targets the REAL
@@ -15,6 +15,7 @@
15
15
  // Zero dependencies. Requires global fetch (Node >= 18 or any browser/worker).
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.default = exports.DenpexClient = exports.DenpexError = void 0;
18
+ const evidence_1 = require("./evidence");
18
19
  class DenpexError extends Error {
19
20
  constructor(message, status,
20
21
  /** Machine-readable code when the API provides one (e.g. AUTH_REQUIRED, GPU_LIMIT_EXCEEDED). */
@@ -26,7 +27,7 @@ class DenpexError extends Error {
26
27
  }
27
28
  }
28
29
  exports.DenpexError = DenpexError;
29
- const MIN_LOG_CHARS = 20;
30
+ const MIN_LOG_CHARS = 6;
30
31
  const MAX_LOG_CHARS = 256000;
31
32
  class DenpexClient {
32
33
  constructor(options) {
@@ -37,23 +38,21 @@ class DenpexClient {
37
38
  this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
38
39
  this.timeoutMs = options.timeoutMs ?? 320000;
39
40
  if (!this.fetchImpl)
40
- throw new Error('DenpexClient: global fetch not found — Node >= 18 required, or pass fetchImpl');
41
+ throw new Error('DenpexClient: global fetch not found. Node >= 18 required, or pass fetchImpl');
41
42
  }
42
- /** Diagnose a training failure from raw logs (20 chars – 256 KB). */
43
+ /** Diagnose a training failure from raw logs. Oversized input is evidence-selected. */
43
44
  async diagnose(logs, opts = {}) {
44
45
  if (typeof logs !== 'string' || logs.length < MIN_LOG_CHARS) {
45
46
  throw new DenpexError(`logs must be at least ${MIN_LOG_CHARS} characters`, 400);
46
47
  }
47
- if (logs.length > MAX_LOG_CHARS) {
48
- throw new DenpexError(`logs too large (max ${MAX_LOG_CHARS} chars) — send the failing excerpt`, 400);
49
- }
50
- return this.request('POST', '/api/diagnose', { logs, ...opts });
48
+ const selected = (0, evidence_1.selectEvidence)(logs, MAX_LOG_CHARS);
49
+ return this.request('POST', '/api/diagnose', { logs: selected.text, ...opts });
51
50
  }
52
51
  /** Re-run the canonical diagnosis with observed facts or a selected evidence check. */
53
52
  async refine(logs, operatorAnswers, opts = {}) {
54
53
  return this.diagnose(logs, { ...opts, operatorAnswers });
55
54
  }
56
- /** Report whether a diagnosis worked — this feedback directly improves future priors. */
55
+ /** Report whether a diagnosis worked. This feedback directly improves future priors. */
57
56
  async feedback(diagnosisId, outcome, note) {
58
57
  if (!diagnosisId)
59
58
  throw new DenpexError('diagnosisId required', 400);
@@ -83,7 +82,11 @@ class DenpexClient {
83
82
  }
84
83
  catch { /* non-JSON error body */ }
85
84
  if (!res.ok) {
86
- const message = typeof json.error === 'string' ? json.error : `Denpex API error (status ${res.status})`;
85
+ const message = typeof json.guidance === 'string'
86
+ ? json.guidance
87
+ : typeof json.error === 'string'
88
+ ? json.error
89
+ : `Denpex API error (status ${res.status})`;
87
90
  throw new DenpexError(message, res.status, typeof json.code === 'string' ? json.code : undefined);
88
91
  }
89
92
  return json;
@@ -0,0 +1,4 @@
1
+ export declare function selectEvidence(logs: string, max: number): {
2
+ text: string;
3
+ truncated: boolean;
4
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectEvidence = selectEvidence;
4
+ const EVIDENCE_RE = /error|fail|fatal|traceback|exception|assert|panic|segfault|xid|nvrm|ecc|fallen off the bus|nccl|cuda|oom|out of memory|timeout|nan\b|\binf\b|node_fail|killed|terminated|version|driver|kernel|container|slurm|kubernetes|rank|node|host|gpu|pci|topology|nvlink|nvswitch|infiniband|rdma|roce/i;
5
+ const CAUSAL_RE = /fatal|critical|traceback|exception|assert|panic|segfault|xid|uncorrectable|fallen off the bus|out of memory|watchdog timeout|crc mismatch|loss\s*=\s*(?:nan|inf)|insufficient|unhealthy|ibv_modify_qp|no space left|compil(?:e|ation) (?:error|failed)|no available memory|checksum mismatch|childfailederror|backendcompilerfailed|failedscheduling|input\/output error|nonfinite|divergence|first failure|initiator|caused by/i;
6
+ const MAX_LINE_CHARS = 2000;
7
+ function clipLine(line) {
8
+ if (line.length <= MAX_LINE_CHARS)
9
+ return line;
10
+ const marker = ' [line clipped by Denpex] ';
11
+ const side = Math.max(1, Math.floor((MAX_LINE_CHARS - marker.length) / 2));
12
+ return `${line.slice(0, side)}${marker}${line.slice(-side)}`.slice(0, MAX_LINE_CHARS);
13
+ }
14
+ function selectEvidence(logs, max) {
15
+ if (logs.length <= max)
16
+ return { text: logs, truncated: false };
17
+ const lines = logs.split(/\r?\n/);
18
+ const candidates = new Map();
19
+ const add = (index, radius, priority) => {
20
+ for (let i = Math.max(0, index - radius); i <= Math.min(lines.length - 1, index + radius); i++) {
21
+ candidates.set(i, Math.max(priority, candidates.get(i) ?? 0));
22
+ }
23
+ };
24
+ for (let i = 0; i < Math.min(48, lines.length); i++)
25
+ candidates.set(i, 300);
26
+ for (let i = Math.max(0, lines.length - 96); i < lines.length; i++)
27
+ candidates.set(i, 800);
28
+ let foundFirst = false;
29
+ for (let i = 0; i < lines.length; i++) {
30
+ const line = lines[i] ?? '';
31
+ if (!EVIDENCE_RE.test(line))
32
+ continue;
33
+ const causal = CAUSAL_RE.test(line);
34
+ add(i, causal ? 3 : 1, causal ? 1000 : 700);
35
+ if (!foundFirst) {
36
+ add(i, 6, 1100);
37
+ foundFirst = true;
38
+ }
39
+ }
40
+ const warning = `[Denpex condensed input: input exceeded ${max.toLocaleString()} characters. Environment, causal, rank, topology, middle, and final-tail evidence were selected.]`;
41
+ let used = warning.length;
42
+ const selected = new Set();
43
+ for (const [index] of [...candidates].sort((a, b) => b[1] - a[1] || a[0] - b[0])) {
44
+ const line = clipLine(lines[index] ?? '');
45
+ if (used + line.length + 1 > max)
46
+ continue;
47
+ selected.add(index);
48
+ used += line.length + 1;
49
+ }
50
+ return {
51
+ text: [warning, ...[...selected].sort((a, b) => a - b).map((index) => clipLine(lines[index] ?? ''))].join('\n'),
52
+ truncated: true,
53
+ };
54
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@denpex/sdk",
3
- "version": "0.8.1",
4
- "description": "TypeScript client for the Denpex API — diagnose GPU training failures from logs (POST /api/diagnose), report fix outcomes, check quota. Zero dependencies, Node >= 18.",
3
+ "version": "0.8.3",
4
+ "description": "TypeScript client for the Denpex API : diagnose GPU training failures from logs (POST /api/diagnose), report fix outcomes, check quota. Zero dependencies, Node >= 18.",
5
5
  "keywords": [
6
6
  "denpex",
7
7
  "gpu",