deepline 0.1.91 → 0.1.94

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.
@@ -3211,8 +3211,22 @@ function formatTailLogPart(value: unknown): string {
3211
3211
  }
3212
3212
  }
3213
3213
 
3214
+ // Operator-diagnostic console lines that carry the [deepline-run:] prefix but
3215
+ // are not user-facing run output. The console scrape fans run-prefixed lines
3216
+ // back into the run's durable Run Log Stream ('system' channel), so harness/
3217
+ // coordinator plumbing noise is filtered at ingestion, never at read time.
3218
+ // User play log lines (runner-event echoes) intentionally pass through.
3219
+ const OPERATOR_NOISE_LOG_PATTERNS: readonly RegExp[] = [
3220
+ /\[perf-trace\]/,
3221
+ /\[harness-probe\]/,
3222
+ /TenantWorkflow\.run entered/,
3223
+ /TenantWorkflow\.run threw/,
3224
+ /failed to forward runner perf trace/,
3225
+ /failed to forward TenantWorkflow\.run error/,
3226
+ ];
3227
+
3214
3228
  function parseRunLogLine(line: string): { runId: string; line: string } | null {
3215
- if (line.includes('[perf-trace]')) {
3229
+ if (OPERATOR_NOISE_LOG_PATTERNS.some((pattern) => pattern.test(line))) {
3216
3230
  return null;
3217
3231
  }
3218
3232
  const prefixed = line.match(RUN_LOG_PREFIX_RE);
@@ -3661,26 +3675,79 @@ async function handleWorkflowRoute(input: {
3661
3675
  }
3662
3676
  try {
3663
3677
  if (action === 'cancel') {
3664
- if (!instance) {
3665
- return Response.json({ runId, status: 'cancelled' });
3678
+ if (instance) {
3679
+ try {
3680
+ await instance.terminate();
3681
+ } catch (error) {
3682
+ const message =
3683
+ error instanceof Error ? error.message : String(error);
3684
+ // Tolerate four classes of error here:
3685
+ // - already-terminal (complete / errored / terminated)
3686
+ // - "Cannot terminate instance since its on a finite state"
3687
+ // (the runtime's wording for "already finished")
3688
+ // - "not implemented" (wrangler dev local mode doesn't support
3689
+ // instance.terminate() yet — silently no-op there)
3690
+ // - "not found" (instance never existed)
3691
+ if (
3692
+ !/complete|terminated|errored|finite state|cannot[ _]terminate|not[ _]implemented|not[ _]found|404/i.test(
3693
+ message,
3694
+ )
3695
+ ) {
3696
+ throw error;
3697
+ }
3698
+ }
3666
3699
  }
3667
- try {
3668
- await instance.terminate();
3669
- } catch (error) {
3670
- const message = error instanceof Error ? error.message : String(error);
3671
- // Tolerate four classes of error here:
3672
- // - already-terminal (complete / errored / terminated)
3673
- // - "Cannot terminate instance since its on a finite state"
3674
- // (the runtime's wording for "already finished")
3675
- // - "not implemented" (wrangler dev local mode doesn't support
3676
- // instance.terminate() yet silently no-op there)
3677
- // - "not found" (instance never existed)
3678
- if (
3679
- !/complete|terminated|errored|finite state|cannot[ _]terminate|not[ _]implemented|not[ _]found|404/i.test(
3680
- message,
3681
- )
3682
- ) {
3683
- throw error;
3700
+ // terminate() kills the dynamic worker before its run() wrapper can
3701
+ // write terminal state (the only place completed/failed land), so
3702
+ // without this write /tail reports 'running' forever and any
3703
+ // start-stream watcher hangs after a cancel. Land the cancelled
3704
+ // terminal state here terminal-set appends a 'terminal' run event
3705
+ // and wakes the dedup DO's long-poll waiters, which unblocks tails.
3706
+ //
3707
+ // Idempotency: first-wins from this side — if the run already went
3708
+ // terminal (completed/failed/cancelled) we keep that state. The DO
3709
+ // stores the cached terminal state under a single storage key
3710
+ // (last-wins on raw writes), but the run-event log is append-only
3711
+ // and /tail truncates at the FIRST terminal event, so a racing
3712
+ // completed/failed write from a dying worker can at worst replace
3713
+ // the cached key with another terminal status — it can never
3714
+ // resurrect 'running'.
3715
+ const existingTerminal = await readCoordinatorTerminalState(
3716
+ env,
3717
+ runId,
3718
+ ).catch((error: unknown) => {
3719
+ // Tolerated: better to risk a harmless terminal-over-terminal
3720
+ // overwrite than to skip the cancelled write and hang watchers.
3721
+ console.warn('[coordinator] terminal state read before cancel failed', {
3722
+ runId,
3723
+ error: error instanceof Error ? error.message : String(error),
3724
+ });
3725
+ return null;
3726
+ });
3727
+ if (!existingTerminal) {
3728
+ try {
3729
+ await writeCoordinatorTerminalState(env, {
3730
+ runId,
3731
+ status: 'cancelled',
3732
+ error: 'Run cancelled',
3733
+ });
3734
+ } catch (error) {
3735
+ // Fail loudly: the workflow was terminated but watchers would
3736
+ // hang on 'running' forever without the terminal event.
3737
+ const message =
3738
+ error instanceof Error ? error.message : String(error);
3739
+ console.error('[coordinator] cancel terminal state write failed', {
3740
+ runId,
3741
+ error: message,
3742
+ });
3743
+ return Response.json(
3744
+ {
3745
+ runId,
3746
+ status: 'error',
3747
+ error: `workflow terminated but cancelled terminal state write failed: ${message}`,
3748
+ },
3749
+ { status: 500 },
3750
+ );
3684
3751
  }
3685
3752
  }
3686
3753
  return Response.json({ runId, status: 'cancelled' });
@@ -1206,7 +1206,10 @@ async function waitForSyntheticIntegrationEvent(
1206
1206
  {
1207
1207
  type: 'log.appended',
1208
1208
  runId: req.runId,
1209
- source: 'worker',
1209
+ // 'system' (windowed text-dedupe channel), NOT 'worker': this line is
1210
+ // emitted outside the harness log buffer, so it has no positional
1211
+ // channelOffset and must not pollute the worker channel cursor.
1212
+ source: 'system',
1210
1213
  occurredAt: nowMs(),
1211
1214
  lines: [
1212
1215
  `Waiting for integration_event:${eventKey} for up to ${timeoutMs}ms.`,
@@ -1334,20 +1337,35 @@ async function callToolDirect(
1334
1337
 
1335
1338
  function toolMetadataFallback(toolId: string): ToolResultMetadataInput {
1336
1339
  if (toolId === 'test_rate_limit') {
1340
+ // Batched members resolve metadata through this fallback because the lean
1341
+ // worker does not bundle the catalog. It MUST mirror the same
1342
+ // `email_status: emailStatus({...})` contract registered in
1343
+ // src/lib/integrations/test/index.ts so batched results normalize to the
1344
+ // same rich email_status OBJECT (status from statusMap, catch_all as a
1345
+ // signal) that the single-execute real-metadata path produces. The legacy
1346
+ // `transforms:['emailStatus']` + mx_security_gateway→'catch_all' string
1347
+ // override coarsened email_status into a bare string and predates the
1348
+ // emailStatus object contract (#1466).
1337
1349
  return {
1338
1350
  toolId,
1339
1351
  extractors: {
1340
1352
  email_status: {
1341
1353
  paths: ['email_status'],
1342
- transforms: ['emailStatus'],
1343
- enum: ['valid', 'invalid', 'catch_all', 'unknown'],
1344
- overrides: [
1345
- {
1346
- paths: ['mx_security_gateway'],
1347
- equals: true,
1348
- value: 'catch_all',
1354
+ emailStatus: {
1355
+ provider: 'test',
1356
+ rawStatus: ['email_status'],
1357
+ catchAll: ['mx_security_gateway'],
1358
+ statusMap: {
1359
+ valid: { status: 'valid', verdict: 'send', verified: true },
1360
+ invalid: { status: 'invalid', verdict: 'drop', verified: false },
1361
+ catch_all: {
1362
+ status: 'catch_all',
1363
+ verdict: 'verify_next',
1364
+ verified: false,
1365
+ },
1366
+ unknown: { status: 'unknown', verdict: 'hold', verified: false },
1349
1367
  },
1350
- ],
1368
+ },
1351
1369
  },
1352
1370
  },
1353
1371
  targetGetters: {
@@ -5402,6 +5420,14 @@ async function executeRunRequest(
5402
5420
  const abortSignal = abortController.signal;
5403
5421
  let runLogBuffer: string[] = [];
5404
5422
  let pendingRunLogLines: string[] = [];
5423
+ // Monotonic count of every line ever appended to this run's worker log
5424
+ // channel. runLogBuffer/pendingRunLogLines are rotating tails of those
5425
+ // lines (RUN_LOG_BUFFER_LIMIT is the coordinator transport cache only), so
5426
+ // each log.appended batch can carry the absolute channelOffset of its first
5427
+ // line: totalEmittedLogLines - pendingRunLogLines.length. Run Log Stream
5428
+ // ingestion skips re-sent prefixes positionally (exactly-once, repeated
5429
+ // identical lines preserved) instead of text-deduping.
5430
+ let totalEmittedLogLines = 0;
5405
5431
  let stepProgressByNodeId: LiveNodeProgressMap = {};
5406
5432
  let dirtyProgressNodeIds = new Set<string>();
5407
5433
  let pendingLedgerEvents: PlayRunLedgerEvent[] = [
@@ -5424,6 +5450,7 @@ async function executeRunRequest(
5424
5450
  const appendRunLogLine = (line: string) => {
5425
5451
  const trimmed = redactSecretsFromLogString(line.trim());
5426
5452
  if (!trimmed) return;
5453
+ totalEmittedLogLines += 1;
5427
5454
  runLogBuffer = [...runLogBuffer, trimmed].slice(-RUN_LOG_BUFFER_LIMIT);
5428
5455
  pendingRunLogLines = [...pendingRunLogLines, trimmed].slice(
5429
5456
  -RUN_LOG_BUFFER_LIMIT,
@@ -5614,6 +5641,12 @@ async function executeRunRequest(
5614
5641
  source: 'worker',
5615
5642
  occurredAt,
5616
5643
  lines: pendingRunLogLines,
5644
+ // Positional cursor: pendingRunLogLines always holds the LAST
5645
+ // pending lines emitted on this channel, so the offset of its first
5646
+ // line is total-emitted minus pending length. This also covers the
5647
+ // terminal full-buffer re-send (pending = runLogBuffer), which
5648
+ // ingestion then skips positionally instead of via text dedupe.
5649
+ channelOffset: totalEmittedLogLines - pendingRunLogLines.length,
5617
5650
  });
5618
5651
  pendingRunLogLines = [];
5619
5652
  }
@@ -5709,6 +5742,9 @@ async function executeRunRequest(
5709
5742
  ): Promise<void> => {
5710
5743
  if (!options?.persistResultDatasets) return;
5711
5744
  const now = nowMs();
5745
+ // Terminal re-send of the full retained buffer. drainPendingLedgerEvents
5746
+ // stamps it with channelOffset = totalEmitted - buffer length, so Run Log
5747
+ // Stream ingestion drops the already-ingested prefix positionally.
5712
5748
  pendingRunLogLines = runLogBuffer;
5713
5749
  dirtyProgressNodeIds = new Set([
5714
5750
  ...dirtyProgressNodeIds,
@@ -5859,6 +5895,25 @@ async function executeRunRequest(
5859
5895
  ms: nowMs() - resultDatasetStartedAt,
5860
5896
  });
5861
5897
  const parentSignal = startParentTerminalSignal();
5898
+ // Capped runs settle compute billing BEFORE declaring run.completed: a
5899
+ // per-run cap denial (422 billing_cap_exceeded) must fail the run as
5900
+ // its ONLY terminal. Flushing completed first opens a race — watchers
5901
+ // stream the ledger snapshot and exit on the transient completed
5902
+ // before the demoting run.failed lands.
5903
+ const capped = extractMaxCreditsPerRun(req.contractSnapshot) !== null;
5904
+ if (capped) {
5905
+ const billingStartedAt = nowMs();
5906
+ await finalizeWorkerComputeBilling({
5907
+ req,
5908
+ success: true,
5909
+ actionEstimate: 4,
5910
+ });
5911
+ recordRunnerPerfTrace({
5912
+ req,
5913
+ phase: 'runner.compute_billing_finalize',
5914
+ ms: nowMs() - billingStartedAt,
5915
+ });
5916
+ }
5862
5917
  const terminalOccurredAt = nowMs();
5863
5918
  const terminalUpdateStartedAt = nowMs();
5864
5919
  await flushTerminalLedgerEvents({
@@ -5874,21 +5929,19 @@ async function executeRunRequest(
5874
5929
  ms: nowMs() - terminalUpdateStartedAt,
5875
5930
  });
5876
5931
 
5877
- const billingStartedAt = nowMs();
5878
- const billingPromise = finalizeWorkerComputeBilling({
5879
- req,
5880
- success: true,
5881
- actionEstimate: 4,
5882
- }).then(() => {
5883
- recordRunnerPerfTrace({
5932
+ if (!capped) {
5933
+ const billingStartedAt = nowMs();
5934
+ const billingPromise = finalizeWorkerComputeBilling({
5884
5935
  req,
5885
- phase: 'runner.compute_billing_finalize',
5886
- ms: nowMs() - billingStartedAt,
5936
+ success: true,
5937
+ actionEstimate: 4,
5938
+ }).then(() => {
5939
+ recordRunnerPerfTrace({
5940
+ req,
5941
+ phase: 'runner.compute_billing_finalize',
5942
+ ms: nowMs() - billingStartedAt,
5943
+ });
5887
5944
  });
5888
- });
5889
- if (extractMaxCreditsPerRun(req.contractSnapshot) !== null) {
5890
- await billingPromise;
5891
- } else {
5892
5945
  const nonBlockingBillingPromise = billingPromise.catch((error) => {
5893
5946
  console.error(
5894
5947
  `[play-harness] non-fatal compute billing finalize failed runId=${req.runId}: ${