File size: 2,106 Bytes
0ed8124
 
 
3fd9ca4
0ed8124
 
fa59dd6
0ed8124
 
 
 
 
 
 
fa59dd6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ed8124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
export interface WebGpuDeviceLostDetails {
  recoverable: true;
  nextAction: 'reload-model';
  stage: 'load' | 'generate' | 'score-sequence' | 'backend-report';
  modelId: string;
  cpuFallbackAvailable: boolean;
  cause: 'memory-pressure' | 'device-loss';
  signal: {
    line: string;
    reason: number | null;
    message: string | null;
  };
}

export type ResourceFailureKind = 'context-capacity' | 'memory-pressure';

export function classifyResourceFailure(
  error: unknown,
  nativeLog: readonly string[] = [],
): ResourceFailureKind | null {
  const errorRecord = typeof error === 'object' && error !== null
    ? error as { message?: unknown; name?: unknown; type?: unknown }
    : null;
  const diagnostic = [
    typeof error === 'string' ? error : '',
    typeof errorRecord?.name === 'string' ? errorRecord.name : '',
    typeof errorRecord?.message === 'string' ? errorRecord.message : '',
    typeof errorRecord?.type === 'string' ? errorRecord.type : '',
    ...nativeLog,
  ].join('\n');
  if (
    /\bkv[_\s-]?cache(?:[_\s-]+is)?[_\s-]+full\b|running out of context capacity|context (?:window|capacity).*(?:full|exhausted)|(?:prompt|tokens?).*(?:exceed|too (?:long|large)).*(?:context|n_ctx)/iu.test(diagnostic)
  ) {
    return 'context-capacity';
  }
  if (
    /\bout[ -]of[ -](?:device[ -])?memory\b|\boom\b|GPUOutOfMemoryError|memory access out of bounds|cannot (?:enlarge|allocate).*memory|failed to (?:allocate|create).*(?:buffer|memory)|(?:buffer|memory) allocation failed/iu.test(diagnostic)
  ) {
    return 'memory-pressure';
  }
  return null;
}

export class EngineRuntimeError extends Error {
  readonly code: string;
  readonly details?: unknown;

  constructor(code: string, message: string, details?: unknown) {
    super(message);
    this.name = 'EngineRuntimeError';
    this.code = code;
    this.details = details;
  }
}

export function abortError(): DOMException {
  return new DOMException('The engine operation was aborted.', 'AbortError');
}

export function throwIfAborted(signal: AbortSignal): void {
  if (signal.aborted) {
    throw abortError();
  }
}