deepline 0.3.234 → 0.3.236
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/bundling-sources/sdk/src/http.ts +46 -10
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +22 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +7 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +26 -7
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +113 -23
- package/dist/cli/index.js +37 -4
- package/dist/cli/index.mjs +37 -4
- package/dist/index.js +37 -4
- package/dist/index.mjs +37 -4
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/dist/viewer/viewer.css +2 -1
- package/dist/viewer/viewer.js +64 -9
- package/package.json +1 -1
|
@@ -204,6 +204,18 @@ function describeRequestTarget(path: string): string {
|
|
|
204
204
|
return 'Deepline';
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
function networkDiagnosticUrl(value: string): string | undefined {
|
|
208
|
+
try {
|
|
209
|
+
const url = new URL(value);
|
|
210
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:') return undefined;
|
|
211
|
+
// Diagnostics never retain URL credentials, query values, or fragments.
|
|
212
|
+
return `${url.origin}${url.pathname}`;
|
|
213
|
+
} catch {
|
|
214
|
+
// Preserve the original transport failure for malformed request URLs.
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
207
219
|
function providerLabelFromToolId(toolId: string): string {
|
|
208
220
|
const normalized = toolId.trim().toLowerCase();
|
|
209
221
|
const provider = normalized.split(/[_:./-]+/)[0];
|
|
@@ -379,6 +391,10 @@ export class HttpClient {
|
|
|
379
391
|
const baseUrl = this.config.baseUrl;
|
|
380
392
|
const url = `${baseUrl}${path}`;
|
|
381
393
|
const method = options?.method ?? 'GET';
|
|
394
|
+
const requestStartedAt = Date.now();
|
|
395
|
+
let fetchAttempts = 0;
|
|
396
|
+
let lastRequestUrl = url;
|
|
397
|
+
let networkFailedAt: number | undefined;
|
|
382
398
|
|
|
383
399
|
const headers = this.authHeaders(options?.headers);
|
|
384
400
|
|
|
@@ -397,6 +413,7 @@ export class HttpClient {
|
|
|
397
413
|
requestAttempts: for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
398
414
|
if (options?.signal?.aborted) {
|
|
399
415
|
lastError = requestCancelledError(options.signal);
|
|
416
|
+
networkFailedAt = Date.now();
|
|
400
417
|
break;
|
|
401
418
|
}
|
|
402
419
|
if (attempt > 0) {
|
|
@@ -410,6 +427,7 @@ export class HttpClient {
|
|
|
410
427
|
await sleep(delayMs, options?.signal);
|
|
411
428
|
} catch (error) {
|
|
412
429
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
430
|
+
networkFailedAt = Date.now();
|
|
413
431
|
break;
|
|
414
432
|
}
|
|
415
433
|
}
|
|
@@ -417,6 +435,7 @@ export class HttpClient {
|
|
|
417
435
|
for (const candidateUrl of candidateUrls) {
|
|
418
436
|
if (options?.signal?.aborted) {
|
|
419
437
|
lastError = requestCancelledError(options.signal);
|
|
438
|
+
networkFailedAt = Date.now();
|
|
420
439
|
break requestAttempts;
|
|
421
440
|
}
|
|
422
441
|
const controller = new AbortController();
|
|
@@ -432,17 +451,20 @@ export class HttpClient {
|
|
|
432
451
|
});
|
|
433
452
|
|
|
434
453
|
try {
|
|
454
|
+
const requestBody =
|
|
455
|
+
options?.formData !== undefined
|
|
456
|
+
? typeof options.formData === 'function'
|
|
457
|
+
? options.formData()
|
|
458
|
+
: options.formData
|
|
459
|
+
: options?.body !== undefined
|
|
460
|
+
? JSON.stringify(options.body)
|
|
461
|
+
: undefined;
|
|
462
|
+
fetchAttempts += 1;
|
|
463
|
+
lastRequestUrl = candidateUrl;
|
|
435
464
|
const response = await fetch(candidateUrl, {
|
|
436
465
|
method,
|
|
437
466
|
headers,
|
|
438
|
-
body:
|
|
439
|
-
options?.formData !== undefined
|
|
440
|
-
? typeof options.formData === 'function'
|
|
441
|
-
? options.formData()
|
|
442
|
-
: options.formData
|
|
443
|
-
: options?.body !== undefined
|
|
444
|
-
? JSON.stringify(options.body)
|
|
445
|
-
: undefined,
|
|
467
|
+
body: requestBody,
|
|
446
468
|
signal: controller.signal,
|
|
447
469
|
});
|
|
448
470
|
|
|
@@ -605,6 +627,7 @@ export class HttpClient {
|
|
|
605
627
|
return parsed as T;
|
|
606
628
|
} catch (error) {
|
|
607
629
|
clearTimeout(timeoutId);
|
|
630
|
+
networkFailedAt = Date.now();
|
|
608
631
|
if (options?.signal?.aborted) {
|
|
609
632
|
lastError = requestCancelledError(options.signal);
|
|
610
633
|
break requestAttempts;
|
|
@@ -637,6 +660,19 @@ export class HttpClient {
|
|
|
637
660
|
lastError,
|
|
638
661
|
describeRequestTarget(path),
|
|
639
662
|
);
|
|
663
|
+
const failedAt = networkFailedAt ?? Date.now();
|
|
664
|
+
const diagnosticUrl = networkDiagnosticUrl(lastRequestUrl);
|
|
665
|
+
const networkDetails = {
|
|
666
|
+
...mappedNetworkError.details,
|
|
667
|
+
request: {
|
|
668
|
+
method,
|
|
669
|
+
...(diagnosticUrl === undefined ? {} : { url: diagnosticUrl }),
|
|
670
|
+
failedAtUtc: new Date(failedAt).toISOString(),
|
|
671
|
+
// Elapsed time covers the entire logical request, including retries.
|
|
672
|
+
elapsedMs: Math.max(0, failedAt - requestStartedAt),
|
|
673
|
+
attempts: fetchAttempts,
|
|
674
|
+
},
|
|
675
|
+
};
|
|
640
676
|
if (options?.toolId) {
|
|
641
677
|
const code = mappedNetworkError.code;
|
|
642
678
|
throw withErrorCause(
|
|
@@ -662,7 +698,7 @@ export class HttpClient {
|
|
|
662
698
|
? 'unknown'
|
|
663
699
|
: 'unavailable',
|
|
664
700
|
networkScope: 'client_to_deepline',
|
|
665
|
-
details:
|
|
701
|
+
details: networkDetails,
|
|
666
702
|
publicDetails: options.idempotencyKey
|
|
667
703
|
? { idempotencyKey: options.idempotencyKey }
|
|
668
704
|
: null,
|
|
@@ -676,7 +712,7 @@ export class HttpClient {
|
|
|
676
712
|
withCoworkNetworkHint(mappedNetworkError.message),
|
|
677
713
|
undefined,
|
|
678
714
|
mappedNetworkError.code,
|
|
679
|
-
|
|
715
|
+
networkDetails,
|
|
680
716
|
),
|
|
681
717
|
lastError,
|
|
682
718
|
);
|
|
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
|
|
|
200
200
|
// getters keep their established compatibility behavior.
|
|
201
201
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
202
202
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
203
|
-
version: '0.3.
|
|
203
|
+
version: '0.3.236',
|
|
204
204
|
updateSummary:
|
|
205
205
|
'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
|
|
206
206
|
packageCapabilities: {
|
|
@@ -43,6 +43,7 @@ export type PlayRunRecoveryReason =
|
|
|
43
43
|
| 'modal_runner_start_failed_before_execution'
|
|
44
44
|
| 'daytona_sandbox_transition_pending_before_execution'
|
|
45
45
|
| 'daytona_sandbox_acquisition_unavailable_before_execution'
|
|
46
|
+
| 'runtime_scheduler_unavailable_before_execution'
|
|
46
47
|
| 'runtime_initialization_transport_before_execution'
|
|
47
48
|
| 'runtime_traffic_hold_before_execution'
|
|
48
49
|
| 'runtime_traffic_throttled_before_execution';
|
|
@@ -211,6 +212,27 @@ export function recoveryForRuntimeTrafficPolicy(input: {
|
|
|
211
212
|
});
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Scheduler admission must be durable before a provider create. If that
|
|
217
|
+
* control-plane read/write is temporarily unavailable, defer through the
|
|
218
|
+
* recovery ledger instead of turning an unstarted Play into a runner failure.
|
|
219
|
+
*/
|
|
220
|
+
export function recoveryForRuntimeSchedulerAdmissionFailure(
|
|
221
|
+
error: unknown,
|
|
222
|
+
): PlayRunRecoveryError {
|
|
223
|
+
return new PlayRunRecoveryError({
|
|
224
|
+
decision: {
|
|
225
|
+
stage: 'pre_code',
|
|
226
|
+
action: 'defer',
|
|
227
|
+
reason: 'runtime_scheduler_unavailable_before_execution',
|
|
228
|
+
dependency: 'runtime',
|
|
229
|
+
},
|
|
230
|
+
message:
|
|
231
|
+
'Runtime scheduler admission is temporarily unavailable before customer execution began.',
|
|
232
|
+
cause: error,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
214
236
|
/**
|
|
215
237
|
* Daytona acknowledged a named sandbox but has not finished creating it.
|
|
216
238
|
* Resume that durable provider operation after a bounded defer; another
|
|
@@ -38,7 +38,10 @@ import {
|
|
|
38
38
|
type OneShotDaytonaSandboxLifecycle,
|
|
39
39
|
validateDaytonaExecutionContext,
|
|
40
40
|
} from './daytona-lifecycle';
|
|
41
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
isPlayRunRecoveryError,
|
|
43
|
+
recoveryForDaytonaSandboxTransitionPending,
|
|
44
|
+
} from '../../play-run-recovery-policy';
|
|
42
45
|
import { stageDaytonaRunnerPayload } from './daytona-payload-transport';
|
|
43
46
|
import {
|
|
44
47
|
DaytonaRunnerInitializationError,
|
|
@@ -1819,6 +1822,9 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1819
1822
|
if (error instanceof DaytonaSandboxAcquisitionUnavailableError) {
|
|
1820
1823
|
throw error;
|
|
1821
1824
|
}
|
|
1825
|
+
if (isPlayRunRecoveryError(error)) {
|
|
1826
|
+
throw error;
|
|
1827
|
+
}
|
|
1822
1828
|
emitDaytonaStage(callbacks, config.context, 'execute:error', {
|
|
1823
1829
|
sandboxId: sandboxCleanup.currentSandbox()?.id ?? null,
|
|
1824
1830
|
runnerAttempt: Math.max(0, Math.floor(config.context.runAttempt ?? 0)),
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* cross-call session state.
|
|
12
12
|
*/
|
|
13
13
|
import { createRequire } from 'node:module';
|
|
14
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
14
15
|
import { readFileSync } from 'node:fs';
|
|
15
16
|
import path from 'node:path';
|
|
16
17
|
import {
|
|
@@ -30,6 +31,18 @@ import {
|
|
|
30
31
|
|
|
31
32
|
export { ABSURD_SCHEMA_VERSION };
|
|
32
33
|
|
|
34
|
+
const absurdSchedulerQuerySignal = new AsyncLocalStorage<AbortSignal>();
|
|
35
|
+
|
|
36
|
+
/** Applies cancellation to this async operation's Absurd SQL calls only.
|
|
37
|
+
* The SDK has no signal argument; keep cancellation in its Deepline adapter,
|
|
38
|
+
* without affecting other tasks sharing the same queryable or pool. */
|
|
39
|
+
export function runWithAbsurdSchedulerQuerySignal<T>(
|
|
40
|
+
signal: AbortSignal,
|
|
41
|
+
operation: () => Promise<T>,
|
|
42
|
+
): Promise<T> {
|
|
43
|
+
return absurdSchedulerQuerySignal.run(signal, operation);
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
/**
|
|
34
47
|
* Builds an SDK `Queryable` backed by the hardened runtime scheduler pool.
|
|
35
48
|
* Every query runs on a freshly checked-out pooled client and releases it,
|
|
@@ -43,13 +56,19 @@ export function absurdQueryableForRuntimeScheduler(
|
|
|
43
56
|
sql: string,
|
|
44
57
|
params?: unknown[],
|
|
45
58
|
): Promise<QueryResult<Row>> => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
const signal = absurdSchedulerQuerySignal.getStore();
|
|
60
|
+
return withRuntimeSchedulerClient(
|
|
61
|
+
poolOptions,
|
|
62
|
+
async (client) => {
|
|
63
|
+
const result = await client.query<Row & Record<string, unknown>>(
|
|
64
|
+
sql,
|
|
65
|
+
params,
|
|
66
|
+
);
|
|
67
|
+
return { rows: result.rows as Row[] };
|
|
68
|
+
},
|
|
69
|
+
undefined,
|
|
70
|
+
{ signal },
|
|
71
|
+
);
|
|
53
72
|
},
|
|
54
73
|
};
|
|
55
74
|
}
|
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts
CHANGED
|
@@ -50,6 +50,7 @@ import { runtimeLimitExceededCause } from '../run-failure';
|
|
|
50
50
|
import {
|
|
51
51
|
recoveryForDaytonaSandboxAcquisitionUnavailable,
|
|
52
52
|
recoveryForRuntimeInitializationTransportFailure,
|
|
53
|
+
recoveryForRuntimeSchedulerAdmissionFailure,
|
|
53
54
|
recoveryForRuntimeTrafficPolicy,
|
|
54
55
|
} from '../play-run-recovery-policy';
|
|
55
56
|
import type { PlayCheckpoint } from '../ctx-types';
|
|
@@ -208,9 +209,10 @@ import {
|
|
|
208
209
|
} from './absurd-worker-required-env';
|
|
209
210
|
import {
|
|
210
211
|
acquirePgNotifyHub,
|
|
212
|
+
isConnectionCategoryError,
|
|
211
213
|
isRuntimeSchedulerCapacityError,
|
|
214
|
+
isRuntimeSchedulerQueryCancellationError,
|
|
212
215
|
isRuntimeSchedulerRetryableTransactionError,
|
|
213
|
-
isConnectionCategoryError,
|
|
214
216
|
parseRuntimeSchedulerCapacityError,
|
|
215
217
|
RuntimeSchedulerCapacityError,
|
|
216
218
|
runtimeSchedulerCapacityRetryAfterMs,
|
|
@@ -219,6 +221,7 @@ import {
|
|
|
219
221
|
type RuntimeSchedulerPoolOptions,
|
|
220
222
|
withRuntimeSchedulerClient,
|
|
221
223
|
} from './postgres-pool';
|
|
224
|
+
import { runWithAbsurdSchedulerQuerySignal } from './absurd-pool';
|
|
222
225
|
import {
|
|
223
226
|
createPostgresSchedulerProgressReporter,
|
|
224
227
|
type PostgresSchedulerProgressReporter,
|
|
@@ -548,7 +551,10 @@ export async function runWithAbsurdExecutionLeaseHeartbeat<T>(input: {
|
|
|
548
551
|
lastHeartbeatAt = now;
|
|
549
552
|
heartbeatState.inFlight = (async () => {
|
|
550
553
|
try {
|
|
551
|
-
await
|
|
554
|
+
await runWithAbsurdSchedulerQuerySignal(
|
|
555
|
+
cancellationController.signal,
|
|
556
|
+
() => input.ctx.heartbeat(),
|
|
557
|
+
);
|
|
552
558
|
} catch (error) {
|
|
553
559
|
if (!isTransientHeartbeatTimeout(error) || stopped) throw error;
|
|
554
560
|
console.warn('[absurd-runtime.worker] lease_heartbeat_timeout_retry', {
|
|
@@ -557,10 +563,22 @@ export async function runWithAbsurdExecutionLeaseHeartbeat<T>(input: {
|
|
|
557
563
|
});
|
|
558
564
|
await sleep(heartbeatTimeoutRetryDelayMs);
|
|
559
565
|
if (stopped) return;
|
|
560
|
-
await
|
|
566
|
+
await runWithAbsurdSchedulerQuerySignal(
|
|
567
|
+
cancellationController.signal,
|
|
568
|
+
() => input.ctx.heartbeat(),
|
|
569
|
+
);
|
|
561
570
|
}
|
|
562
571
|
})()
|
|
563
572
|
.catch((error) => {
|
|
573
|
+
// The handoff deadline owns this cancellation. A cancelled local SQL
|
|
574
|
+
// call does not prove that the engine cancelled the durable task.
|
|
575
|
+
if (
|
|
576
|
+
cancellationController.signal.aborted &&
|
|
577
|
+
error === cancellationController.signal.reason &&
|
|
578
|
+
error instanceof AbsurdExecutionOperationTimeoutError
|
|
579
|
+
) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
564
582
|
const engineTerminal =
|
|
565
583
|
error instanceof CancelledTask || error instanceof FailedTask;
|
|
566
584
|
if (engineTerminal) {
|
|
@@ -593,9 +611,22 @@ export async function runWithAbsurdExecutionLeaseHeartbeat<T>(input: {
|
|
|
593
611
|
timer.unref?.();
|
|
594
612
|
let operationTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
595
613
|
try {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
)
|
|
614
|
+
// A completed backend still cannot park until its in-flight lease update
|
|
615
|
+
// settles. Keep that drain inside the same supervised handoff deadline.
|
|
616
|
+
const operation = (async () => {
|
|
617
|
+
try {
|
|
618
|
+
operationResult = await Promise.resolve().then(() =>
|
|
619
|
+
input.operation(cancellationController.signal),
|
|
620
|
+
);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
operationError = error;
|
|
623
|
+
} finally {
|
|
624
|
+
stopped = true;
|
|
625
|
+
stopHeartbeatTimer();
|
|
626
|
+
await heartbeatState.inFlight;
|
|
627
|
+
}
|
|
628
|
+
return operationResult;
|
|
629
|
+
})();
|
|
599
630
|
if (operationTimeoutMs !== null) {
|
|
600
631
|
operationResult = await Promise.race([
|
|
601
632
|
operation,
|
|
@@ -617,15 +648,11 @@ export async function runWithAbsurdExecutionLeaseHeartbeat<T>(input: {
|
|
|
617
648
|
operationResult = await operation;
|
|
618
649
|
}
|
|
619
650
|
} catch (error) {
|
|
620
|
-
operationError
|
|
651
|
+
operationError ??= error;
|
|
621
652
|
} finally {
|
|
622
653
|
if (operationTimeout) clearTimeout(operationTimeout);
|
|
623
654
|
stopped = true;
|
|
624
655
|
stopHeartbeatTimer();
|
|
625
|
-
const pendingHeartbeat = heartbeatState.inFlight;
|
|
626
|
-
if (pendingHeartbeat) {
|
|
627
|
-
await pendingHeartbeat.catch(() => undefined);
|
|
628
|
-
}
|
|
629
656
|
}
|
|
630
657
|
if (heartbeatFailure) {
|
|
631
658
|
if (
|
|
@@ -3490,22 +3517,85 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3490
3517
|
);
|
|
3491
3518
|
}
|
|
3492
3519
|
const mode = runtimeSandboxCapacityAdmissionMode();
|
|
3493
|
-
const
|
|
3494
|
-
|
|
3495
|
-
|
|
3520
|
+
const reservationInput = {
|
|
3521
|
+
orgId: launch.orgId,
|
|
3522
|
+
runId,
|
|
3523
|
+
provider,
|
|
3524
|
+
mode,
|
|
3525
|
+
attempt: generation,
|
|
3526
|
+
environment: 'production' as const,
|
|
3527
|
+
resumePendingDaytonaOperation: provider === 'daytona',
|
|
3528
|
+
operationKey: `sandbox-operation:${runId}:${generation}:${provider}:${providerAttempt ?? 1}`,
|
|
3529
|
+
};
|
|
3530
|
+
const reserve = () =>
|
|
3531
|
+
deps.runWithClient((client) =>
|
|
3532
|
+
reserveRuntimeSandboxOperation(
|
|
3533
|
+
client,
|
|
3534
|
+
reservationInput,
|
|
3535
|
+
options,
|
|
3536
|
+
),
|
|
3537
|
+
);
|
|
3538
|
+
const deferForSchedulerFailure = (error: unknown): never => {
|
|
3539
|
+
console.warn(
|
|
3540
|
+
'[absurd-runtime.worker] sandbox_capacity_admission_deferred',
|
|
3496
3541
|
{
|
|
3497
|
-
orgId: launch.orgId,
|
|
3498
3542
|
runId,
|
|
3499
3543
|
provider,
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3544
|
+
providerAttempt: providerAttempt ?? 1,
|
|
3545
|
+
error:
|
|
3546
|
+
error instanceof Error
|
|
3547
|
+
? error.message
|
|
3548
|
+
: String(error),
|
|
3505
3549
|
},
|
|
3506
|
-
|
|
3507
|
-
)
|
|
3508
|
-
|
|
3550
|
+
);
|
|
3551
|
+
throw recoveryForRuntimeSchedulerAdmissionFailure(error);
|
|
3552
|
+
};
|
|
3553
|
+
const isRetryableSchedulerFailure = (error: unknown) =>
|
|
3554
|
+
isRuntimeSchedulerCapacityError(error) ||
|
|
3555
|
+
isConnectionCategoryError(error) ||
|
|
3556
|
+
isRuntimeSchedulerRetryableTransactionError(error) ||
|
|
3557
|
+
isRuntimeSchedulerQueryCancellationError(error);
|
|
3558
|
+
let reserved: Awaited<ReturnType<typeof reserve>> | null =
|
|
3559
|
+
null;
|
|
3560
|
+
try {
|
|
3561
|
+
reserved = await reserve();
|
|
3562
|
+
} catch (error) {
|
|
3563
|
+
if (isRuntimeSchedulerQueryCancellationError(error)) {
|
|
3564
|
+
// A query timeout has an ambiguous outcome. The stable
|
|
3565
|
+
// operation key makes this reservation safe to repeat:
|
|
3566
|
+
// a committed first attempt is read back, and a missing
|
|
3567
|
+
// one is inserted once.
|
|
3568
|
+
console.warn(
|
|
3569
|
+
'[absurd-runtime.worker] sandbox_capacity_admission_retry',
|
|
3570
|
+
{
|
|
3571
|
+
runId,
|
|
3572
|
+
provider,
|
|
3573
|
+
providerAttempt: providerAttempt ?? 1,
|
|
3574
|
+
error:
|
|
3575
|
+
error instanceof Error
|
|
3576
|
+
? error.message
|
|
3577
|
+
: String(error),
|
|
3578
|
+
},
|
|
3579
|
+
);
|
|
3580
|
+
try {
|
|
3581
|
+
reserved = await reserve();
|
|
3582
|
+
} catch (retryError) {
|
|
3583
|
+
if (!isRetryableSchedulerFailure(retryError)) {
|
|
3584
|
+
throw retryError;
|
|
3585
|
+
}
|
|
3586
|
+
deferForSchedulerFailure(retryError);
|
|
3587
|
+
}
|
|
3588
|
+
} else if (isRetryableSchedulerFailure(error)) {
|
|
3589
|
+
deferForSchedulerFailure(error);
|
|
3590
|
+
} else {
|
|
3591
|
+
throw error;
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
if (reserved === null) {
|
|
3595
|
+
throw new Error(
|
|
3596
|
+
'Runtime scheduler sandbox capacity reservation returned no result.',
|
|
3597
|
+
);
|
|
3598
|
+
}
|
|
3509
3599
|
if (!reserved.granted) {
|
|
3510
3600
|
throw new RuntimeSandboxCapacityLimitError({
|
|
3511
3601
|
orgId: launch.orgId,
|
package/dist/cli/index.js
CHANGED
|
@@ -3454,7 +3454,7 @@ var SDK_RELEASE = {
|
|
|
3454
3454
|
// getters keep their established compatibility behavior.
|
|
3455
3455
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3456
3456
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3457
|
-
version: "0.3.
|
|
3457
|
+
version: "0.3.236",
|
|
3458
3458
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3459
3459
|
packageCapabilities: {
|
|
3460
3460
|
updatePreferences: 1
|
|
@@ -4133,6 +4133,15 @@ function describeRequestTarget(path) {
|
|
|
4133
4133
|
}
|
|
4134
4134
|
return "Deepline";
|
|
4135
4135
|
}
|
|
4136
|
+
function networkDiagnosticUrl(value) {
|
|
4137
|
+
try {
|
|
4138
|
+
const url = new URL(value);
|
|
4139
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
|
|
4140
|
+
return `${url.origin}${url.pathname}`;
|
|
4141
|
+
} catch {
|
|
4142
|
+
return void 0;
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4136
4145
|
function providerLabelFromToolId(toolId) {
|
|
4137
4146
|
const normalized = toolId.trim().toLowerCase();
|
|
4138
4147
|
const provider = normalized.split(/[_:./-]+/)[0];
|
|
@@ -4233,6 +4242,10 @@ var HttpClient = class {
|
|
|
4233
4242
|
const baseUrl = this.config.baseUrl;
|
|
4234
4243
|
const url = `${baseUrl}${path}`;
|
|
4235
4244
|
const method = options?.method ?? "GET";
|
|
4245
|
+
const requestStartedAt = Date.now();
|
|
4246
|
+
let fetchAttempts = 0;
|
|
4247
|
+
let lastRequestUrl = url;
|
|
4248
|
+
let networkFailedAt;
|
|
4236
4249
|
const headers = this.authHeaders(options?.headers);
|
|
4237
4250
|
if (options?.body !== void 0) {
|
|
4238
4251
|
headers["Content-Type"] = "application/json";
|
|
@@ -4244,6 +4257,7 @@ var HttpClient = class {
|
|
|
4244
4257
|
requestAttempts: for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
4245
4258
|
if (options?.signal?.aborted) {
|
|
4246
4259
|
lastError = requestCancelledError(options.signal);
|
|
4260
|
+
networkFailedAt = Date.now();
|
|
4247
4261
|
break;
|
|
4248
4262
|
}
|
|
4249
4263
|
if (attempt > 0) {
|
|
@@ -4254,12 +4268,14 @@ var HttpClient = class {
|
|
|
4254
4268
|
await sleep(delayMs, options?.signal);
|
|
4255
4269
|
} catch (error) {
|
|
4256
4270
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
4271
|
+
networkFailedAt = Date.now();
|
|
4257
4272
|
break;
|
|
4258
4273
|
}
|
|
4259
4274
|
}
|
|
4260
4275
|
for (const candidateUrl of candidateUrls) {
|
|
4261
4276
|
if (options?.signal?.aborted) {
|
|
4262
4277
|
lastError = requestCancelledError(options.signal);
|
|
4278
|
+
networkFailedAt = Date.now();
|
|
4263
4279
|
break requestAttempts;
|
|
4264
4280
|
}
|
|
4265
4281
|
const controller = new AbortController();
|
|
@@ -4274,10 +4290,13 @@ var HttpClient = class {
|
|
|
4274
4290
|
once: true
|
|
4275
4291
|
});
|
|
4276
4292
|
try {
|
|
4293
|
+
const requestBody = options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0;
|
|
4294
|
+
fetchAttempts += 1;
|
|
4295
|
+
lastRequestUrl = candidateUrl;
|
|
4277
4296
|
const response = await fetch(candidateUrl, {
|
|
4278
4297
|
method,
|
|
4279
4298
|
headers,
|
|
4280
|
-
body:
|
|
4299
|
+
body: requestBody,
|
|
4281
4300
|
signal: controller.signal
|
|
4282
4301
|
});
|
|
4283
4302
|
options?.onResponse?.(response);
|
|
@@ -4381,6 +4400,7 @@ var HttpClient = class {
|
|
|
4381
4400
|
return parsed;
|
|
4382
4401
|
} catch (error) {
|
|
4383
4402
|
clearTimeout(timeoutId);
|
|
4403
|
+
networkFailedAt = Date.now();
|
|
4384
4404
|
if (options?.signal?.aborted) {
|
|
4385
4405
|
lastError = requestCancelledError(options.signal);
|
|
4386
4406
|
break requestAttempts;
|
|
@@ -4411,6 +4431,19 @@ var HttpClient = class {
|
|
|
4411
4431
|
lastError,
|
|
4412
4432
|
describeRequestTarget(path)
|
|
4413
4433
|
);
|
|
4434
|
+
const failedAt = networkFailedAt ?? Date.now();
|
|
4435
|
+
const diagnosticUrl = networkDiagnosticUrl(lastRequestUrl);
|
|
4436
|
+
const networkDetails = {
|
|
4437
|
+
...mappedNetworkError.details,
|
|
4438
|
+
request: {
|
|
4439
|
+
method,
|
|
4440
|
+
...diagnosticUrl === void 0 ? {} : { url: diagnosticUrl },
|
|
4441
|
+
failedAtUtc: new Date(failedAt).toISOString(),
|
|
4442
|
+
// Elapsed time covers the entire logical request, including retries.
|
|
4443
|
+
elapsedMs: Math.max(0, failedAt - requestStartedAt),
|
|
4444
|
+
attempts: fetchAttempts
|
|
4445
|
+
}
|
|
4446
|
+
};
|
|
4414
4447
|
if (options?.toolId) {
|
|
4415
4448
|
const code = mappedNetworkError.code;
|
|
4416
4449
|
throw withErrorCause(
|
|
@@ -4431,7 +4464,7 @@ var HttpClient = class {
|
|
|
4431
4464
|
retryAfterMs: null,
|
|
4432
4465
|
networkKind: code === "NETWORK_TIMEOUT" ? "timeout" : code === "NETWORK_ABORTED" ? "unknown" : "unavailable",
|
|
4433
4466
|
networkScope: "client_to_deepline",
|
|
4434
|
-
details:
|
|
4467
|
+
details: networkDetails,
|
|
4435
4468
|
publicDetails: options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : null
|
|
4436
4469
|
}
|
|
4437
4470
|
),
|
|
@@ -4443,7 +4476,7 @@ var HttpClient = class {
|
|
|
4443
4476
|
withCoworkNetworkHint(mappedNetworkError.message),
|
|
4444
4477
|
void 0,
|
|
4445
4478
|
mappedNetworkError.code,
|
|
4446
|
-
|
|
4479
|
+
networkDetails
|
|
4447
4480
|
),
|
|
4448
4481
|
lastError
|
|
4449
4482
|
);
|
package/dist/cli/index.mjs
CHANGED
|
@@ -3449,7 +3449,7 @@ var SDK_RELEASE = {
|
|
|
3449
3449
|
// getters keep their established compatibility behavior.
|
|
3450
3450
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3451
3451
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3452
|
-
version: "0.3.
|
|
3452
|
+
version: "0.3.236",
|
|
3453
3453
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3454
3454
|
packageCapabilities: {
|
|
3455
3455
|
updatePreferences: 1
|
|
@@ -4128,6 +4128,15 @@ function describeRequestTarget(path) {
|
|
|
4128
4128
|
}
|
|
4129
4129
|
return "Deepline";
|
|
4130
4130
|
}
|
|
4131
|
+
function networkDiagnosticUrl(value) {
|
|
4132
|
+
try {
|
|
4133
|
+
const url = new URL(value);
|
|
4134
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
|
|
4135
|
+
return `${url.origin}${url.pathname}`;
|
|
4136
|
+
} catch {
|
|
4137
|
+
return void 0;
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4131
4140
|
function providerLabelFromToolId(toolId) {
|
|
4132
4141
|
const normalized = toolId.trim().toLowerCase();
|
|
4133
4142
|
const provider = normalized.split(/[_:./-]+/)[0];
|
|
@@ -4228,6 +4237,10 @@ var HttpClient = class {
|
|
|
4228
4237
|
const baseUrl = this.config.baseUrl;
|
|
4229
4238
|
const url = `${baseUrl}${path}`;
|
|
4230
4239
|
const method = options?.method ?? "GET";
|
|
4240
|
+
const requestStartedAt = Date.now();
|
|
4241
|
+
let fetchAttempts = 0;
|
|
4242
|
+
let lastRequestUrl = url;
|
|
4243
|
+
let networkFailedAt;
|
|
4231
4244
|
const headers = this.authHeaders(options?.headers);
|
|
4232
4245
|
if (options?.body !== void 0) {
|
|
4233
4246
|
headers["Content-Type"] = "application/json";
|
|
@@ -4239,6 +4252,7 @@ var HttpClient = class {
|
|
|
4239
4252
|
requestAttempts: for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
4240
4253
|
if (options?.signal?.aborted) {
|
|
4241
4254
|
lastError = requestCancelledError(options.signal);
|
|
4255
|
+
networkFailedAt = Date.now();
|
|
4242
4256
|
break;
|
|
4243
4257
|
}
|
|
4244
4258
|
if (attempt > 0) {
|
|
@@ -4249,12 +4263,14 @@ var HttpClient = class {
|
|
|
4249
4263
|
await sleep(delayMs, options?.signal);
|
|
4250
4264
|
} catch (error) {
|
|
4251
4265
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
4266
|
+
networkFailedAt = Date.now();
|
|
4252
4267
|
break;
|
|
4253
4268
|
}
|
|
4254
4269
|
}
|
|
4255
4270
|
for (const candidateUrl of candidateUrls) {
|
|
4256
4271
|
if (options?.signal?.aborted) {
|
|
4257
4272
|
lastError = requestCancelledError(options.signal);
|
|
4273
|
+
networkFailedAt = Date.now();
|
|
4258
4274
|
break requestAttempts;
|
|
4259
4275
|
}
|
|
4260
4276
|
const controller = new AbortController();
|
|
@@ -4269,10 +4285,13 @@ var HttpClient = class {
|
|
|
4269
4285
|
once: true
|
|
4270
4286
|
});
|
|
4271
4287
|
try {
|
|
4288
|
+
const requestBody = options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0;
|
|
4289
|
+
fetchAttempts += 1;
|
|
4290
|
+
lastRequestUrl = candidateUrl;
|
|
4272
4291
|
const response = await fetch(candidateUrl, {
|
|
4273
4292
|
method,
|
|
4274
4293
|
headers,
|
|
4275
|
-
body:
|
|
4294
|
+
body: requestBody,
|
|
4276
4295
|
signal: controller.signal
|
|
4277
4296
|
});
|
|
4278
4297
|
options?.onResponse?.(response);
|
|
@@ -4376,6 +4395,7 @@ var HttpClient = class {
|
|
|
4376
4395
|
return parsed;
|
|
4377
4396
|
} catch (error) {
|
|
4378
4397
|
clearTimeout(timeoutId);
|
|
4398
|
+
networkFailedAt = Date.now();
|
|
4379
4399
|
if (options?.signal?.aborted) {
|
|
4380
4400
|
lastError = requestCancelledError(options.signal);
|
|
4381
4401
|
break requestAttempts;
|
|
@@ -4406,6 +4426,19 @@ var HttpClient = class {
|
|
|
4406
4426
|
lastError,
|
|
4407
4427
|
describeRequestTarget(path)
|
|
4408
4428
|
);
|
|
4429
|
+
const failedAt = networkFailedAt ?? Date.now();
|
|
4430
|
+
const diagnosticUrl = networkDiagnosticUrl(lastRequestUrl);
|
|
4431
|
+
const networkDetails = {
|
|
4432
|
+
...mappedNetworkError.details,
|
|
4433
|
+
request: {
|
|
4434
|
+
method,
|
|
4435
|
+
...diagnosticUrl === void 0 ? {} : { url: diagnosticUrl },
|
|
4436
|
+
failedAtUtc: new Date(failedAt).toISOString(),
|
|
4437
|
+
// Elapsed time covers the entire logical request, including retries.
|
|
4438
|
+
elapsedMs: Math.max(0, failedAt - requestStartedAt),
|
|
4439
|
+
attempts: fetchAttempts
|
|
4440
|
+
}
|
|
4441
|
+
};
|
|
4409
4442
|
if (options?.toolId) {
|
|
4410
4443
|
const code = mappedNetworkError.code;
|
|
4411
4444
|
throw withErrorCause(
|
|
@@ -4426,7 +4459,7 @@ var HttpClient = class {
|
|
|
4426
4459
|
retryAfterMs: null,
|
|
4427
4460
|
networkKind: code === "NETWORK_TIMEOUT" ? "timeout" : code === "NETWORK_ABORTED" ? "unknown" : "unavailable",
|
|
4428
4461
|
networkScope: "client_to_deepline",
|
|
4429
|
-
details:
|
|
4462
|
+
details: networkDetails,
|
|
4430
4463
|
publicDetails: options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : null
|
|
4431
4464
|
}
|
|
4432
4465
|
),
|
|
@@ -4438,7 +4471,7 @@ var HttpClient = class {
|
|
|
4438
4471
|
withCoworkNetworkHint(mappedNetworkError.message),
|
|
4439
4472
|
void 0,
|
|
4440
4473
|
mappedNetworkError.code,
|
|
4441
|
-
|
|
4474
|
+
networkDetails
|
|
4442
4475
|
),
|
|
4443
4476
|
lastError
|
|
4444
4477
|
);
|
package/dist/index.js
CHANGED
|
@@ -1267,7 +1267,7 @@ var SDK_RELEASE = {
|
|
|
1267
1267
|
// getters keep their established compatibility behavior.
|
|
1268
1268
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
1269
1269
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
1270
|
-
version: "0.3.
|
|
1270
|
+
version: "0.3.236",
|
|
1271
1271
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
1272
1272
|
packageCapabilities: {
|
|
1273
1273
|
updatePreferences: 1
|
|
@@ -1909,6 +1909,15 @@ function describeRequestTarget(path) {
|
|
|
1909
1909
|
}
|
|
1910
1910
|
return "Deepline";
|
|
1911
1911
|
}
|
|
1912
|
+
function networkDiagnosticUrl(value) {
|
|
1913
|
+
try {
|
|
1914
|
+
const url = new URL(value);
|
|
1915
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
|
|
1916
|
+
return `${url.origin}${url.pathname}`;
|
|
1917
|
+
} catch {
|
|
1918
|
+
return void 0;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1912
1921
|
function providerLabelFromToolId(toolId) {
|
|
1913
1922
|
const normalized = toolId.trim().toLowerCase();
|
|
1914
1923
|
const provider = normalized.split(/[_:./-]+/)[0];
|
|
@@ -2009,6 +2018,10 @@ var HttpClient = class {
|
|
|
2009
2018
|
const baseUrl = this.config.baseUrl;
|
|
2010
2019
|
const url = `${baseUrl}${path}`;
|
|
2011
2020
|
const method = options?.method ?? "GET";
|
|
2021
|
+
const requestStartedAt = Date.now();
|
|
2022
|
+
let fetchAttempts = 0;
|
|
2023
|
+
let lastRequestUrl = url;
|
|
2024
|
+
let networkFailedAt;
|
|
2012
2025
|
const headers = this.authHeaders(options?.headers);
|
|
2013
2026
|
if (options?.body !== void 0) {
|
|
2014
2027
|
headers["Content-Type"] = "application/json";
|
|
@@ -2020,6 +2033,7 @@ var HttpClient = class {
|
|
|
2020
2033
|
requestAttempts: for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
2021
2034
|
if (options?.signal?.aborted) {
|
|
2022
2035
|
lastError = requestCancelledError(options.signal);
|
|
2036
|
+
networkFailedAt = Date.now();
|
|
2023
2037
|
break;
|
|
2024
2038
|
}
|
|
2025
2039
|
if (attempt > 0) {
|
|
@@ -2030,12 +2044,14 @@ var HttpClient = class {
|
|
|
2030
2044
|
await sleep(delayMs, options?.signal);
|
|
2031
2045
|
} catch (error) {
|
|
2032
2046
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
2047
|
+
networkFailedAt = Date.now();
|
|
2033
2048
|
break;
|
|
2034
2049
|
}
|
|
2035
2050
|
}
|
|
2036
2051
|
for (const candidateUrl of candidateUrls) {
|
|
2037
2052
|
if (options?.signal?.aborted) {
|
|
2038
2053
|
lastError = requestCancelledError(options.signal);
|
|
2054
|
+
networkFailedAt = Date.now();
|
|
2039
2055
|
break requestAttempts;
|
|
2040
2056
|
}
|
|
2041
2057
|
const controller = new AbortController();
|
|
@@ -2050,10 +2066,13 @@ var HttpClient = class {
|
|
|
2050
2066
|
once: true
|
|
2051
2067
|
});
|
|
2052
2068
|
try {
|
|
2069
|
+
const requestBody = options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0;
|
|
2070
|
+
fetchAttempts += 1;
|
|
2071
|
+
lastRequestUrl = candidateUrl;
|
|
2053
2072
|
const response = await fetch(candidateUrl, {
|
|
2054
2073
|
method,
|
|
2055
2074
|
headers,
|
|
2056
|
-
body:
|
|
2075
|
+
body: requestBody,
|
|
2057
2076
|
signal: controller.signal
|
|
2058
2077
|
});
|
|
2059
2078
|
options?.onResponse?.(response);
|
|
@@ -2157,6 +2176,7 @@ var HttpClient = class {
|
|
|
2157
2176
|
return parsed;
|
|
2158
2177
|
} catch (error) {
|
|
2159
2178
|
clearTimeout(timeoutId);
|
|
2179
|
+
networkFailedAt = Date.now();
|
|
2160
2180
|
if (options?.signal?.aborted) {
|
|
2161
2181
|
lastError = requestCancelledError(options.signal);
|
|
2162
2182
|
break requestAttempts;
|
|
@@ -2187,6 +2207,19 @@ var HttpClient = class {
|
|
|
2187
2207
|
lastError,
|
|
2188
2208
|
describeRequestTarget(path)
|
|
2189
2209
|
);
|
|
2210
|
+
const failedAt = networkFailedAt ?? Date.now();
|
|
2211
|
+
const diagnosticUrl = networkDiagnosticUrl(lastRequestUrl);
|
|
2212
|
+
const networkDetails = {
|
|
2213
|
+
...mappedNetworkError.details,
|
|
2214
|
+
request: {
|
|
2215
|
+
method,
|
|
2216
|
+
...diagnosticUrl === void 0 ? {} : { url: diagnosticUrl },
|
|
2217
|
+
failedAtUtc: new Date(failedAt).toISOString(),
|
|
2218
|
+
// Elapsed time covers the entire logical request, including retries.
|
|
2219
|
+
elapsedMs: Math.max(0, failedAt - requestStartedAt),
|
|
2220
|
+
attempts: fetchAttempts
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2190
2223
|
if (options?.toolId) {
|
|
2191
2224
|
const code = mappedNetworkError.code;
|
|
2192
2225
|
throw withErrorCause(
|
|
@@ -2207,7 +2240,7 @@ var HttpClient = class {
|
|
|
2207
2240
|
retryAfterMs: null,
|
|
2208
2241
|
networkKind: code === "NETWORK_TIMEOUT" ? "timeout" : code === "NETWORK_ABORTED" ? "unknown" : "unavailable",
|
|
2209
2242
|
networkScope: "client_to_deepline",
|
|
2210
|
-
details:
|
|
2243
|
+
details: networkDetails,
|
|
2211
2244
|
publicDetails: options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : null
|
|
2212
2245
|
}
|
|
2213
2246
|
),
|
|
@@ -2219,7 +2252,7 @@ var HttpClient = class {
|
|
|
2219
2252
|
withCoworkNetworkHint(mappedNetworkError.message),
|
|
2220
2253
|
void 0,
|
|
2221
2254
|
mappedNetworkError.code,
|
|
2222
|
-
|
|
2255
|
+
networkDetails
|
|
2223
2256
|
),
|
|
2224
2257
|
lastError
|
|
2225
2258
|
);
|
package/dist/index.mjs
CHANGED
|
@@ -1171,7 +1171,7 @@ var SDK_RELEASE = {
|
|
|
1171
1171
|
// getters keep their established compatibility behavior.
|
|
1172
1172
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
1173
1173
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
1174
|
-
version: "0.3.
|
|
1174
|
+
version: "0.3.236",
|
|
1175
1175
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
1176
1176
|
packageCapabilities: {
|
|
1177
1177
|
updatePreferences: 1
|
|
@@ -1813,6 +1813,15 @@ function describeRequestTarget(path) {
|
|
|
1813
1813
|
}
|
|
1814
1814
|
return "Deepline";
|
|
1815
1815
|
}
|
|
1816
|
+
function networkDiagnosticUrl(value) {
|
|
1817
|
+
try {
|
|
1818
|
+
const url = new URL(value);
|
|
1819
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
|
|
1820
|
+
return `${url.origin}${url.pathname}`;
|
|
1821
|
+
} catch {
|
|
1822
|
+
return void 0;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1816
1825
|
function providerLabelFromToolId(toolId) {
|
|
1817
1826
|
const normalized = toolId.trim().toLowerCase();
|
|
1818
1827
|
const provider = normalized.split(/[_:./-]+/)[0];
|
|
@@ -1913,6 +1922,10 @@ var HttpClient = class {
|
|
|
1913
1922
|
const baseUrl = this.config.baseUrl;
|
|
1914
1923
|
const url = `${baseUrl}${path}`;
|
|
1915
1924
|
const method = options?.method ?? "GET";
|
|
1925
|
+
const requestStartedAt = Date.now();
|
|
1926
|
+
let fetchAttempts = 0;
|
|
1927
|
+
let lastRequestUrl = url;
|
|
1928
|
+
let networkFailedAt;
|
|
1916
1929
|
const headers = this.authHeaders(options?.headers);
|
|
1917
1930
|
if (options?.body !== void 0) {
|
|
1918
1931
|
headers["Content-Type"] = "application/json";
|
|
@@ -1924,6 +1937,7 @@ var HttpClient = class {
|
|
|
1924
1937
|
requestAttempts: for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1925
1938
|
if (options?.signal?.aborted) {
|
|
1926
1939
|
lastError = requestCancelledError(options.signal);
|
|
1940
|
+
networkFailedAt = Date.now();
|
|
1927
1941
|
break;
|
|
1928
1942
|
}
|
|
1929
1943
|
if (attempt > 0) {
|
|
@@ -1934,12 +1948,14 @@ var HttpClient = class {
|
|
|
1934
1948
|
await sleep(delayMs, options?.signal);
|
|
1935
1949
|
} catch (error) {
|
|
1936
1950
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1951
|
+
networkFailedAt = Date.now();
|
|
1937
1952
|
break;
|
|
1938
1953
|
}
|
|
1939
1954
|
}
|
|
1940
1955
|
for (const candidateUrl of candidateUrls) {
|
|
1941
1956
|
if (options?.signal?.aborted) {
|
|
1942
1957
|
lastError = requestCancelledError(options.signal);
|
|
1958
|
+
networkFailedAt = Date.now();
|
|
1943
1959
|
break requestAttempts;
|
|
1944
1960
|
}
|
|
1945
1961
|
const controller = new AbortController();
|
|
@@ -1954,10 +1970,13 @@ var HttpClient = class {
|
|
|
1954
1970
|
once: true
|
|
1955
1971
|
});
|
|
1956
1972
|
try {
|
|
1973
|
+
const requestBody = options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0;
|
|
1974
|
+
fetchAttempts += 1;
|
|
1975
|
+
lastRequestUrl = candidateUrl;
|
|
1957
1976
|
const response = await fetch(candidateUrl, {
|
|
1958
1977
|
method,
|
|
1959
1978
|
headers,
|
|
1960
|
-
body:
|
|
1979
|
+
body: requestBody,
|
|
1961
1980
|
signal: controller.signal
|
|
1962
1981
|
});
|
|
1963
1982
|
options?.onResponse?.(response);
|
|
@@ -2061,6 +2080,7 @@ var HttpClient = class {
|
|
|
2061
2080
|
return parsed;
|
|
2062
2081
|
} catch (error) {
|
|
2063
2082
|
clearTimeout(timeoutId);
|
|
2083
|
+
networkFailedAt = Date.now();
|
|
2064
2084
|
if (options?.signal?.aborted) {
|
|
2065
2085
|
lastError = requestCancelledError(options.signal);
|
|
2066
2086
|
break requestAttempts;
|
|
@@ -2091,6 +2111,19 @@ var HttpClient = class {
|
|
|
2091
2111
|
lastError,
|
|
2092
2112
|
describeRequestTarget(path)
|
|
2093
2113
|
);
|
|
2114
|
+
const failedAt = networkFailedAt ?? Date.now();
|
|
2115
|
+
const diagnosticUrl = networkDiagnosticUrl(lastRequestUrl);
|
|
2116
|
+
const networkDetails = {
|
|
2117
|
+
...mappedNetworkError.details,
|
|
2118
|
+
request: {
|
|
2119
|
+
method,
|
|
2120
|
+
...diagnosticUrl === void 0 ? {} : { url: diagnosticUrl },
|
|
2121
|
+
failedAtUtc: new Date(failedAt).toISOString(),
|
|
2122
|
+
// Elapsed time covers the entire logical request, including retries.
|
|
2123
|
+
elapsedMs: Math.max(0, failedAt - requestStartedAt),
|
|
2124
|
+
attempts: fetchAttempts
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2094
2127
|
if (options?.toolId) {
|
|
2095
2128
|
const code = mappedNetworkError.code;
|
|
2096
2129
|
throw withErrorCause(
|
|
@@ -2111,7 +2144,7 @@ var HttpClient = class {
|
|
|
2111
2144
|
retryAfterMs: null,
|
|
2112
2145
|
networkKind: code === "NETWORK_TIMEOUT" ? "timeout" : code === "NETWORK_ABORTED" ? "unknown" : "unavailable",
|
|
2113
2146
|
networkScope: "client_to_deepline",
|
|
2114
|
-
details:
|
|
2147
|
+
details: networkDetails,
|
|
2115
2148
|
publicDetails: options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : null
|
|
2116
2149
|
}
|
|
2117
2150
|
),
|
|
@@ -2123,7 +2156,7 @@ var HttpClient = class {
|
|
|
2123
2156
|
withCoworkNetworkHint(mappedNetworkError.message),
|
|
2124
2157
|
void 0,
|
|
2125
2158
|
mappedNetworkError.code,
|
|
2126
|
-
|
|
2159
|
+
networkDetails
|
|
2127
2160
|
),
|
|
2128
2161
|
lastError
|
|
2129
2162
|
);
|
package/dist/release.d.mts
CHANGED
|
@@ -149,7 +149,7 @@ type SdkRelease = {
|
|
|
149
149
|
supportPolicy: SdkSupportPolicy;
|
|
150
150
|
};
|
|
151
151
|
declare const SDK_RELEASE: {
|
|
152
|
-
readonly version: "0.3.
|
|
152
|
+
readonly version: "0.3.236";
|
|
153
153
|
readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
|
|
154
154
|
readonly packageCapabilities: {
|
|
155
155
|
readonly updatePreferences: 1;
|
package/dist/release.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ type SdkRelease = {
|
|
|
149
149
|
supportPolicy: SdkSupportPolicy;
|
|
150
150
|
};
|
|
151
151
|
declare const SDK_RELEASE: {
|
|
152
|
-
readonly version: "0.3.
|
|
152
|
+
readonly version: "0.3.236";
|
|
153
153
|
readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
|
|
154
154
|
readonly packageCapabilities: {
|
|
155
155
|
readonly updatePreferences: 1;
|
package/dist/release.js
CHANGED
|
@@ -74,7 +74,7 @@ var SDK_RELEASE = {
|
|
|
74
74
|
// getters keep their established compatibility behavior.
|
|
75
75
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
76
76
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
77
|
-
version: "0.3.
|
|
77
|
+
version: "0.3.236",
|
|
78
78
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
79
79
|
packageCapabilities: {
|
|
80
80
|
updatePreferences: 1
|
package/dist/release.mjs
CHANGED
|
@@ -48,7 +48,7 @@ var SDK_RELEASE = {
|
|
|
48
48
|
// getters keep their established compatibility behavior.
|
|
49
49
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
50
50
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
51
|
-
version: "0.3.
|
|
51
|
+
version: "0.3.236",
|
|
52
52
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
53
53
|
packageCapabilities: {
|
|
54
54
|
updatePreferences: 1
|
package/dist/viewer/viewer.css
CHANGED
|
@@ -737,7 +737,7 @@ body {
|
|
|
737
737
|
top: -24px;
|
|
738
738
|
z-index: 20;
|
|
739
739
|
display: grid;
|
|
740
|
-
grid-template-columns: minmax(180px, 1.2fr) minmax(170px, 1.2fr) repeat(
|
|
740
|
+
grid-template-columns: minmax(180px, 1.2fr) minmax(170px, 1.2fr) repeat(5, minmax(120px, .75fr)) auto auto;
|
|
741
741
|
gap: 8px;
|
|
742
742
|
align-items: end;
|
|
743
743
|
margin: -24px -32px 18px;
|
|
@@ -902,6 +902,7 @@ body {
|
|
|
902
902
|
.expectation-result.pass { color: var(--green); }
|
|
903
903
|
.expectation-result.fail { color: var(--red); }
|
|
904
904
|
.expectation-result.unknown { color: var(--yellow); }
|
|
905
|
+
.grading-detail { margin-top: 3px; color: var(--text-dim); white-space: pre-wrap; }
|
|
905
906
|
.expectation-failure-reason {
|
|
906
907
|
margin-top: 5px;
|
|
907
908
|
color: color-mix(in srgb, var(--red) 80%, var(--text-dim));
|
package/dist/viewer/viewer.js
CHANGED
|
@@ -1371,11 +1371,12 @@ let isLive = false;
|
|
|
1371
1371
|
let liveIntervalId = null;
|
|
1372
1372
|
let currentEval = '';
|
|
1373
1373
|
let currentSelection = 'all';
|
|
1374
|
-
let sliceBy = '
|
|
1374
|
+
let sliceBy = 'none';
|
|
1375
1375
|
let runFilter = '';
|
|
1376
1376
|
let agentFilter = 'all';
|
|
1377
1377
|
let modelFilter = 'all';
|
|
1378
1378
|
let skillFilter = 'all';
|
|
1379
|
+
let treatmentFilter = 'all';
|
|
1379
1380
|
let visibleEvalKeys = [];
|
|
1380
1381
|
let visibleSelectionKeys = [];
|
|
1381
1382
|
|
|
@@ -1444,6 +1445,7 @@ function attachEvalMetadata() {
|
|
|
1444
1445
|
agent: firstPresent([metric && metric.agent], inferAgent(session.label, session.meta)),
|
|
1445
1446
|
model: firstPresent([metric && metric.model_id, metric && metric.requested_model, metric && metric.model], inferModel(session.label, session.meta)),
|
|
1446
1447
|
skill: firstPresent([metric && metric.invoke_skill], inferSkill(session)),
|
|
1448
|
+
treatment: firstPresent([metric && metric.variant_id], 'Unrecorded treatment'),
|
|
1447
1449
|
};
|
|
1448
1450
|
});
|
|
1449
1451
|
}
|
|
@@ -1457,7 +1459,7 @@ function sessionsForCurrentEval() {
|
|
|
1457
1459
|
}
|
|
1458
1460
|
|
|
1459
1461
|
function selectionDimensions() {
|
|
1460
|
-
const dimensions = ['run', 'agent', 'model', 'skill'];
|
|
1462
|
+
const dimensions = ['run', 'agent', 'model', 'skill', 'treatment'];
|
|
1461
1463
|
return sliceBy === 'none' ? dimensions : dimensions.filter(dimension => dimension !== sliceBy);
|
|
1462
1464
|
}
|
|
1463
1465
|
|
|
@@ -1471,6 +1473,7 @@ function selectionLabel(session) {
|
|
|
1471
1473
|
agent: value => value,
|
|
1472
1474
|
model: value => value,
|
|
1473
1475
|
skill: value => value,
|
|
1476
|
+
treatment: value => value,
|
|
1474
1477
|
};
|
|
1475
1478
|
return selectionDimensions().map(dimension => labels[dimension](session.dimensions[dimension])).join(' · ') || 'All transcripts';
|
|
1476
1479
|
}
|
|
@@ -1481,7 +1484,8 @@ function matchesTopFilters(session) {
|
|
|
1481
1484
|
if (agentFilter !== 'all' && d.agent !== agentFilter) return false;
|
|
1482
1485
|
if (modelFilter !== 'all' && d.model !== modelFilter) return false;
|
|
1483
1486
|
if (skillFilter !== 'all' && d.skill !== skillFilter) return false;
|
|
1484
|
-
|
|
1487
|
+
if (treatmentFilter !== 'all' && d.treatment !== treatmentFilter) return false;
|
|
1488
|
+
return !query || [session.label, d.eval, d.run, d.agent, d.model, d.skill, d.treatment].join(' ').toLowerCase().includes(query);
|
|
1485
1489
|
}
|
|
1486
1490
|
|
|
1487
1491
|
function matchingConfigurations() {
|
|
@@ -1525,6 +1529,7 @@ function saveViewerState() {
|
|
|
1525
1529
|
agentFilter: agentFilter,
|
|
1526
1530
|
modelFilter: modelFilter,
|
|
1527
1531
|
skillFilter: skillFilter,
|
|
1532
|
+
treatmentFilter: treatmentFilter,
|
|
1528
1533
|
}));
|
|
1529
1534
|
}
|
|
1530
1535
|
|
|
@@ -1563,14 +1568,15 @@ function init() {
|
|
|
1563
1568
|
currentEval = saved && visibleEvalKeys.includes(saved.currentEval)
|
|
1564
1569
|
? saved.currentEval
|
|
1565
1570
|
: ((SESSIONS[Math.max(0, initialSession)] || {}).dimensions || {}).eval || visibleEvalKeys[0] || '';
|
|
1566
|
-
sliceBy = saved && ['none', 'run', 'agent', 'model', 'skill'].includes(saved.sliceBy)
|
|
1571
|
+
sliceBy = saved && ['none', 'run', 'agent', 'model', 'skill', 'treatment'].includes(saved.sliceBy)
|
|
1567
1572
|
? saved.sliceBy
|
|
1568
|
-
:
|
|
1573
|
+
: 'none';
|
|
1569
1574
|
currentSelection = (saved && (saved.currentSelection || saved.currentRun)) || 'all';
|
|
1570
1575
|
runFilter = (saved && saved.runFilter) || '';
|
|
1571
1576
|
agentFilter = (saved && saved.agentFilter) || 'all';
|
|
1572
1577
|
modelFilter = (saved && saved.modelFilter) || 'all';
|
|
1573
1578
|
skillFilter = (saved && saved.skillFilter) || 'all';
|
|
1579
|
+
treatmentFilter = (saved && saved.treatmentFilter) || 'all';
|
|
1574
1580
|
|
|
1575
1581
|
if (SESSIONS.length > 1) {
|
|
1576
1582
|
document.getElementById('sidebar').classList.remove('hidden');
|
|
@@ -1720,6 +1726,7 @@ function switchEval(index) {
|
|
|
1720
1726
|
agentFilter = 'all';
|
|
1721
1727
|
modelFilter = 'all';
|
|
1722
1728
|
skillFilter = 'all';
|
|
1729
|
+
treatmentFilter = 'all';
|
|
1723
1730
|
renderSidebar();
|
|
1724
1731
|
renderRunSidebar();
|
|
1725
1732
|
renderWorkspace();
|
|
@@ -1744,7 +1751,7 @@ function switchSession(i) {
|
|
|
1744
1751
|
|
|
1745
1752
|
function switchToCompare() {
|
|
1746
1753
|
currentSelection = 'all';
|
|
1747
|
-
sliceBy = '
|
|
1754
|
+
sliceBy = 'none';
|
|
1748
1755
|
renderRunSidebar();
|
|
1749
1756
|
renderWorkspace();
|
|
1750
1757
|
}
|
|
@@ -1760,14 +1767,17 @@ function renderWorkspaceControls() {
|
|
|
1760
1767
|
const agents = uniqueValues(sessions.map(s => s.dimensions.agent));
|
|
1761
1768
|
const models = uniqueValues(sessions.map(s => s.dimensions.model));
|
|
1762
1769
|
const skills = uniqueValues(sessions.map(s => s.dimensions.skill));
|
|
1770
|
+
const treatments = uniqueValues(sessions.map(s => s.dimensions.treatment));
|
|
1763
1771
|
return `<section class="workspace-controls" aria-label="Transcript filters">
|
|
1764
1772
|
<div class="workspace-context"><span class="eyebrow">Evaluation</span><strong>${esc(currentEval)}</strong></div>
|
|
1765
1773
|
<label class="control-field control-search"><span>Filter runs</span><input id="run-filter" value="${esc(runFilter)}" placeholder="model, skill, label…" oninput="runFilter=this.value" onkeydown="if(event.key==='Enter'){applyWorkspaceFilters()}"></label>
|
|
1766
1774
|
<label class="control-field"><span>Agent</span><select id="agent-filter" onchange="agentFilter=this.value;applyWorkspaceFilters()">${optionList(agents, agentFilter, 'All agents')}</select></label>
|
|
1767
1775
|
<label class="control-field"><span>Model</span><select id="model-filter" onchange="modelFilter=this.value;applyWorkspaceFilters()">${optionList(models, modelFilter, 'All models')}</select></label>
|
|
1768
1776
|
<label class="control-field"><span>Skill</span><select id="skill-filter" onchange="skillFilter=this.value;applyWorkspaceFilters()">${optionList(skills, skillFilter, 'All skills')}</select></label>
|
|
1777
|
+
<label class="control-field"><span>Treatment</span><select id="treatment-filter" onchange="treatmentFilter=this.value;applyWorkspaceFilters()">${optionList(treatments, treatmentFilter, 'All treatments')}</select></label>
|
|
1769
1778
|
<label class="control-field slice-control"><span>Slice by</span><select id="slice-by" onchange="changeSlice(this.value)">
|
|
1770
1779
|
<option value="none" ${sliceBy === 'none' ? 'selected' : ''}>No slicing</option>
|
|
1780
|
+
<option value="treatment" ${sliceBy === 'treatment' ? 'selected' : ''}>Treatment</option>
|
|
1771
1781
|
<option value="run" ${sliceBy === 'run' ? 'selected' : ''}>Run number</option>
|
|
1772
1782
|
<option value="agent" ${sliceBy === 'agent' ? 'selected' : ''}>Agent</option>
|
|
1773
1783
|
<option value="model" ${sliceBy === 'model' ? 'selected' : ''}>Model</option>
|
|
@@ -1790,6 +1800,9 @@ function resetWorkspaceFilters() {
|
|
|
1790
1800
|
agentFilter = 'all';
|
|
1791
1801
|
modelFilter = 'all';
|
|
1792
1802
|
skillFilter = 'all';
|
|
1803
|
+
treatmentFilter = 'all';
|
|
1804
|
+
sliceBy = 'none';
|
|
1805
|
+
currentSelection = 'all';
|
|
1793
1806
|
renderRunSidebar();
|
|
1794
1807
|
renderWorkspace();
|
|
1795
1808
|
}
|
|
@@ -1801,12 +1814,43 @@ function changeSlice(value) {
|
|
|
1801
1814
|
renderWorkspace();
|
|
1802
1815
|
}
|
|
1803
1816
|
|
|
1817
|
+
function renderSavedGrading(grading) {
|
|
1818
|
+
if (!grading || typeof grading !== 'object') return '';
|
|
1819
|
+
const outcome = grading.result || {};
|
|
1820
|
+
const graders = Array.isArray(grading.graders) ? grading.graders : [];
|
|
1821
|
+
if (!grading.result && !graders.length) return '';
|
|
1822
|
+
// Quality is an outcome, not a pass/fail check. In particular, zero is a
|
|
1823
|
+
// real Low score; missing evidence and judge errors must remain ungraded.
|
|
1824
|
+
const quality = outcome.score != null
|
|
1825
|
+
? `${outcome.score}/${outcome.max_score ?? 2} (${outcome.grade || 'scored'})`
|
|
1826
|
+
: `Not scored (${outcome.status || 'unknown'})`;
|
|
1827
|
+
const checks = outcome.checks_status || 'unknown';
|
|
1828
|
+
const rows = graders.map(item => {
|
|
1829
|
+
const status = item.status || 'unknown';
|
|
1830
|
+
const result = item.score != null
|
|
1831
|
+
? `${item.score} (${item.grade || status})`
|
|
1832
|
+
: status;
|
|
1833
|
+
const resultClass = item.type === 'deterministic' && status === 'passed'
|
|
1834
|
+
? 'pass' : (status === 'failed' || status === 'error' ? 'fail' : (item.score != null ? '' : 'unknown'));
|
|
1835
|
+
const errors = Array.isArray(item.evidence_errors) ? item.evidence_errors : [];
|
|
1836
|
+
const details = [item.reason, item.error_kind, ...errors.map(error => [error.code, error.detail].filter(Boolean).join(': '))].filter(Boolean);
|
|
1837
|
+
const reason = details.length ? `<div class="${status === 'failed' || status === 'error' ? 'expectation-failure-reason' : 'grading-detail'}">${esc(details.join(' · '))}</div>` : '';
|
|
1838
|
+
return `<tr><td>${esc(item.id || 'Unnamed grader')}${reason}</td><td>${esc(item.type || 'unknown')}</td><td><span class="expectation-result ${resultClass}">${esc(result)}</span></td></tr>`;
|
|
1839
|
+
}).join('');
|
|
1840
|
+
return `<div class="expectations-mini${checks === 'failed' || checks === 'error' ? ' has-failures' : ''}">
|
|
1841
|
+
<div class="expectations-mini-heading"><span>Outcome quality</span><strong>${esc(quality)}</strong></div>
|
|
1842
|
+
<div class="expectations-mini-heading"><span>Required checks: ${esc(checks)}</span><span>Grading: ${esc(outcome.status || 'unknown')}</span></div>
|
|
1843
|
+
${rows ? `<div class="expectations-table-wrap"><table><thead><tr><th>Grader</th><th>Type</th><th>Result</th></tr></thead><tbody>${rows}</tbody></table></div>` : ''}
|
|
1844
|
+
</div>`;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1804
1847
|
function renderExpectationMiniTable(session) {
|
|
1805
1848
|
const metric = session.evalMetric;
|
|
1849
|
+
const grading = renderSavedGrading(metric && metric.grading);
|
|
1806
1850
|
const expectations = metric && Array.isArray(metric.expectations) ? metric.expectations : [];
|
|
1807
1851
|
const summary = metric && metric.expectation_summary;
|
|
1808
1852
|
if (!expectations.length) {
|
|
1809
|
-
return `<div class="expectations-empty"><span>Eval results</span><strong>Pending or unavailable</strong></div>`;
|
|
1853
|
+
return grading || `<div class="expectations-empty"><span>Eval results</span><strong>Pending or unavailable</strong></div>`;
|
|
1810
1854
|
}
|
|
1811
1855
|
const passed = summary ? summary.passed : expectations.filter(item => String(item.result || '').toUpperCase() === 'PASS').length;
|
|
1812
1856
|
const total = summary ? summary.total : expectations.length;
|
|
@@ -1820,7 +1864,7 @@ function renderExpectationMiniTable(session) {
|
|
|
1820
1864
|
: '';
|
|
1821
1865
|
return `<tr><td>${esc(item.expectation || '—')}${reason}</td><td>${esc(item.category || 'other')}</td><td><span class="expectation-result ${resultClass}">${esc(result)}</span></td></tr>`;
|
|
1822
1866
|
}).join('');
|
|
1823
|
-
return `<div class="expectations-mini ${statusClass}">
|
|
1867
|
+
return grading + `<div class="expectations-mini ${statusClass}">
|
|
1824
1868
|
<div class="expectations-mini-heading"><span>Eval results</span><strong>${passed}/${total} passed</strong></div>
|
|
1825
1869
|
<div class="expectations-table-wrap"><table><thead><tr><th>Expectation</th><th>Category</th><th>Result</th></tr></thead><tbody>${rows}</tbody></table></div>
|
|
1826
1870
|
</div>`;
|
|
@@ -1887,6 +1931,14 @@ function renderFinalArtifacts(session) {
|
|
|
1887
1931
|
</section>`;
|
|
1888
1932
|
}
|
|
1889
1933
|
|
|
1934
|
+
function renderSourceProvenance(metric) {
|
|
1935
|
+
if (!metric.bundle_digest) return '';
|
|
1936
|
+
const fields = { 'Source run': metric.source_run, 'Bundle': metric.bundle_digest, 'Assignment': metric.assignment_id };
|
|
1937
|
+
return '<details class="lane-prompt"><summary>Source provenance</summary><div class="prompt-text">'
|
|
1938
|
+
+ Object.entries(fields).filter(([, value]) => value).map(([key, value]) => esc(key + ': ' + value)).join('<br>')
|
|
1939
|
+
+ '</div></details>';
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1890
1942
|
function renderLaneSession(session) {
|
|
1891
1943
|
const i = session.sourceIndex;
|
|
1892
1944
|
const d = session.dimensions;
|
|
@@ -1900,9 +1952,10 @@ function renderLaneSession(session) {
|
|
|
1900
1952
|
let html = `<article class="lane-session">
|
|
1901
1953
|
<header class="lane-session-header">
|
|
1902
1954
|
<div class="lane-title-row"><div><span class="run-kicker">Run ${esc(d.run)}</span><h3>${esc(d.agent)} / ${esc(d.model)}</h3></div><button class="download-btn" onclick="downloadJsonl(${i})">JSONL</button></div>
|
|
1903
|
-
<div class="dimension-chips"><span>${esc(d.skill)}</span><span>${formatDuration(session.stats.duration_s)}</span><span>${session.stats.tool_calls} calls</span><span class="${session.stats.tool_errors ? 'chip-error' : ''}">${session.stats.tool_errors} errors${errorRate ? ' · ' + errorRate + '%' : ''}</span>${embeddedFailures ? `<span class="chip-error">${embeddedFailures} embedded failures</span>` : ''}${infraAffected ? `<span class="chip-error">infra affected${infraCodes ? ' · ' + esc(infraCodes) : ''}</span>` : ''}</div>
|
|
1955
|
+
<div class="dimension-chips"><span>${esc(d.treatment)}</span><span>${esc(d.skill)}</span><span>${formatDuration(session.stats.duration_s)}</span><span>${session.stats.tool_calls} calls</span><span class="${session.stats.tool_errors ? 'chip-error' : ''}">${session.stats.tool_errors} errors${errorRate ? ' · ' + errorRate + '%' : ''}</span>${embeddedFailures ? `<span class="chip-error">${embeddedFailures} embedded failures</span>` : ''}${infraAffected ? `<span class="chip-error">infra affected${infraCodes ? ' · ' + esc(infraCodes) : ''}</span>` : ''}</div>
|
|
1904
1956
|
${renderExpectationMiniTable(session)}
|
|
1905
1957
|
${renderInfraSignals(metric)}
|
|
1958
|
+
${renderSourceProvenance(metric)}
|
|
1906
1959
|
</header>`;
|
|
1907
1960
|
if (!session.transcript_available) {
|
|
1908
1961
|
html += '<div class="transcript-unavailable">No transcript was retained for this completed eval. Its scored expectations remain included in this comparison.</div>';
|
|
@@ -1985,6 +2038,7 @@ function renderSession(i) {
|
|
|
1985
2038
|
html += item('Agent', s.dimensions.agent);
|
|
1986
2039
|
html += item('Model', s.dimensions.model || s.meta.model || '\u2014');
|
|
1987
2040
|
html += item('Skill', s.dimensions.skill);
|
|
2041
|
+
html += item('Treatment', s.dimensions.treatment);
|
|
1988
2042
|
html += item('Run', s.dimensions.run);
|
|
1989
2043
|
html += item('Session', (s.meta.session_id || '\u2014').slice(0, 12));
|
|
1990
2044
|
if (s.meta.uploaded_by) html += item('Uploaded by', s.meta.uploaded_by);
|
|
@@ -2013,6 +2067,7 @@ function renderSession(i) {
|
|
|
2013
2067
|
if (s.stats.loop_groups > 0) html += item('Retry Loops', s.stats.loop_groups);
|
|
2014
2068
|
if (s.stats.error_streak_groups > 0) html += item('Error Streaks', s.stats.error_streak_groups + ' (max ' + s.stats.max_error_streak + ')');
|
|
2015
2069
|
html += '</div>';
|
|
2070
|
+
html += renderSourceProvenance(metric);
|
|
2016
2071
|
html += renderExpectationMiniTable(s);
|
|
2017
2072
|
html += renderInfraSignals(metric);
|
|
2018
2073
|
if (!s.transcript_available) {
|