deepline 0.3.172 → 0.3.173

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.
@@ -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.172',
203
+ version: '0.3.173',
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: {
@@ -83,6 +83,9 @@ export type AsyncOperationContractWire = {
83
83
  * Keep a default synchronous Play call in the runner process: launch the
84
84
  * provider job, expose its handle in run progress, then poll companion tools
85
85
  * until terminal. Direct tools.execute callers keep their own legacy policy.
86
+ * These calls receive the canonical raw-v2 response alongside the legacy
87
+ * projection, so terminal classification can consult it when every declared
88
+ * status path is absent from the projection.
86
89
  */
87
90
  runtimeManagedWait?: true;
88
91
  /** Preserve the provider's historical public async metadata exactly. */
@@ -671,16 +674,22 @@ function conditionMatches(
671
674
  export function classifyAsyncOperationResult(
672
675
  contract: AsyncOperationContractWire,
673
676
  result: unknown,
677
+ fallbackResult?: unknown,
674
678
  ): { outcome: AsyncOperationTerminalOutcome; message?: string } {
679
+ const classificationResult = resolveAsyncOperationClassificationResult(
680
+ contract,
681
+ result,
682
+ fallbackResult,
683
+ );
675
684
  for (const rule of contract.terminal.rules) {
676
685
  const matches = rule.conditions.map((condition) =>
677
- conditionMatches(result, condition),
686
+ conditionMatches(classificationResult, condition),
678
687
  );
679
688
  const matched =
680
689
  rule.mode === 'any' ? matches.some(Boolean) : matches.every(Boolean);
681
690
  if (!matched) continue;
682
691
  const message = rule.messagePath
683
- ? readAsyncOperationPath(result, rule.messagePath)
692
+ ? readAsyncOperationPath(classificationResult, rule.messagePath)
684
693
  : undefined;
685
694
  return {
686
695
  outcome: rule.outcome,
@@ -695,15 +704,52 @@ export function classifyAsyncOperationResult(
695
704
  export function hasExplicitAsyncOperationTerminalMatch(
696
705
  contract: AsyncOperationContractWire,
697
706
  result: unknown,
707
+ fallbackResult?: unknown,
698
708
  ): boolean {
709
+ const classificationResult = resolveAsyncOperationClassificationResult(
710
+ contract,
711
+ result,
712
+ fallbackResult,
713
+ );
699
714
  return contract.terminal.rules.some((rule) => {
700
715
  const matches = rule.conditions.map((condition) =>
701
- conditionMatches(result, condition),
716
+ conditionMatches(classificationResult, condition),
702
717
  );
703
718
  return rule.mode === 'any' ? matches.some(Boolean) : matches.every(Boolean);
704
719
  });
705
720
  }
706
721
 
722
+ /**
723
+ * Runtime-managed Play calls carry both the compatibility projection and the
724
+ * canonical provider response. Use the canonical view only when every path
725
+ * declared by the terminal rules is absent from the compatibility view. A
726
+ * present value (including null) remains authoritative, so a stale or
727
+ * transport-level rawV2 status cannot override an observed provider status.
728
+ */
729
+ function resolveAsyncOperationClassificationResult(
730
+ contract: AsyncOperationContractWire,
731
+ result: unknown,
732
+ fallbackResult: unknown,
733
+ ): unknown {
734
+ if (!contract.runtimeManagedWait || fallbackResult === undefined) {
735
+ return result;
736
+ }
737
+ const conditionPaths = new Set(
738
+ contract.terminal.rules.flatMap((rule) =>
739
+ rule.conditions.map((condition) => condition.path),
740
+ ),
741
+ );
742
+ if (
743
+ conditionPaths.size === 0 ||
744
+ [...conditionPaths].some(
745
+ (path) => readAsyncOperationPath(result, path) !== undefined,
746
+ )
747
+ ) {
748
+ return result;
749
+ }
750
+ return fallbackResult;
751
+ }
752
+
707
753
  function isEmptyAsyncResult(value: unknown): boolean {
708
754
  return (
709
755
  value == null ||
@@ -907,6 +953,8 @@ export async function executeAsyncOperationLifecycle<Response>(input: {
907
953
  abortSignal: AbortSignal;
908
954
  }) => Promise<Response>;
909
955
  responseValue: (response: Response) => unknown;
956
+ /** Canonical provider response used only when terminal paths are missing from responseValue. */
957
+ classificationFallback?: (response: Response) => unknown;
910
958
  sleep?: (ms: number) => Promise<void>;
911
959
  now?: () => number;
912
960
  /** Called after the provider handle is known and before the first poll. */
@@ -1111,6 +1159,7 @@ export async function executeAsyncOperationLifecycle<Response>(input: {
1111
1159
  const classification = classifyAsyncOperationResult(
1112
1160
  input.contract,
1113
1161
  previousPollResult,
1162
+ input.classificationFallback?.(pollResponse),
1114
1163
  );
1115
1164
  input.onPoll?.({
1116
1165
  jobId,
@@ -3915,6 +3915,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
3915
3915
  this.activeMapCheckpointMemory = null;
3916
3916
  }
3917
3917
 
3918
+ private activeMapCheckpointUpdatesForTable(
3919
+ tableNamespace: string,
3920
+ ): PlayRowUpdate[] {
3921
+ return [...(this.activeMapCheckpointUpdates?.values() ?? [])].filter(
3922
+ (update) => (update.tableNamespace ?? tableNamespace) === tableNamespace,
3923
+ );
3924
+ }
3925
+
3918
3926
  /**
3919
3927
  * Checkpoint updates merge at field grain. Re-serializing every row after
3920
3928
  * each cell would turn this safety measurement into O(rows x columns), so
@@ -11196,12 +11204,8 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11196
11204
  ]),
11197
11205
  ).values(),
11198
11206
  ];
11199
- const checkpointUpdates = [
11200
- ...(this.activeMapCheckpointUpdates?.values() ?? []),
11201
- ].filter(
11202
- (update) =>
11203
- (update.tableNamespace ?? normalizedTableNamespace) ===
11204
- normalizedTableNamespace,
11207
+ const checkpointUpdates = this.activeMapCheckpointUpdatesForTable(
11208
+ normalizedTableNamespace,
11205
11209
  );
11206
11210
  // A suspension is not observable until both terminal rows and partial
11207
11211
  // completed-cell patches cross the same writer's durability barrier.
@@ -12088,6 +12092,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
12088
12092
  );
12089
12093
  };
12090
12094
  if (!this.persistenceLatch.tripped) {
12095
+ // A run-fatal row error (for example a Deepline billing denial) unwinds
12096
+ // before it can produce a terminal MapRowOutcome. Persist its latest
12097
+ // row/cell checkpoint first so a previously enriched value cannot remain
12098
+ // reusable after this failed attempt. Terminal rows already accepted by
12099
+ // this writer win over same-key checkpoints.
12100
+ await incrementalPersistence?.checkpoint(
12101
+ this.activeMapCheckpointUpdatesForTable(input.tableNamespace),
12102
+ );
12091
12103
  await incrementalPersistence?.flush();
12092
12104
  const rows = unpersistedRows();
12093
12105
  const persistStartedAt = Date.now();
@@ -17853,14 +17865,17 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
17853
17865
  startResponse: ParsedToolExecuteResponse;
17854
17866
  }): Promise<ParsedToolExecuteResponse> {
17855
17867
  const startResult = input.startResponse.toolResponse?.raw;
17868
+ const startClassificationFallback = input.startResponse.toolResponse?.rawV2;
17856
17869
  const jobId = extractAsyncOperationJobId(input.contract, startResult);
17857
17870
  const hasTerminalMatch = hasExplicitAsyncOperationTerminalMatch(
17858
17871
  input.contract,
17859
17872
  startResult,
17873
+ startClassificationFallback,
17860
17874
  );
17861
17875
  const startClassification = classifyAsyncOperationResult(
17862
17876
  input.contract,
17863
17877
  startResult,
17878
+ startClassificationFallback,
17864
17879
  );
17865
17880
  const launchIsRunning =
17866
17881
  input.contract.launch?.unclassifiedJobOutcome === 'running' &&
@@ -17928,6 +17943,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
17928
17943
  uncachedAsyncLifecycleCall: true,
17929
17944
  }),
17930
17945
  responseValue: (response) => response.toolResponse?.raw,
17946
+ classificationFallback: (response) => response.toolResponse?.rawV2,
17931
17947
  onJobStarted: () => {
17932
17948
  this.runtimeLog(
17933
17949
  `Provider task ${jobId} is running. This Play remains synchronous while it checks for completion. ` +
@@ -16531,37 +16531,73 @@ export async function dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope(
16531
16531
  // late producer commits cannot split one run between different heads.
16532
16532
  await client.query('BEGIN');
16533
16533
  try {
16534
- const selected = await client.query<{ run_id: string }>(
16535
- `
16536
- WITH heads AS MATERIALIZED (
16537
- SELECT DISTINCT ON (pending.run_id)
16538
- pending.run_id,
16539
- pending.event_id,
16540
- pending.event_type,
16541
- pending.created_at,
16542
- pending.next_attempt_at,
16543
- pending.failed_at
16544
- FROM ${tableName('outbox', options)} AS pending
16545
- WHERE pending.delivered_at IS NULL
16546
- AND ($1::text IS NULL OR pending.run_id = $1)
16547
- ORDER BY pending.run_id, ${runLedgerOrderSql('pending')}
16548
- )
16549
- SELECT runs.run_id
16550
- FROM heads AS head
16551
- JOIN ${tableName('runs', options)} AS runs ON runs.run_id = head.run_id
16552
- WHERE head.failed_at IS NULL
16553
- AND coalesce(head.next_attempt_at, head.created_at) <= now()
16554
- AND NOT EXISTS (
16555
- SELECT 1 FROM ${tableName('outbox', options)} AS active
16556
- WHERE active.run_id = runs.run_id AND active.delivered_at IS NULL
16557
- AND active.lease_owner IS NOT NULL AND active.lease_expires_at > now()
16534
+ const targetRunId = input.runId?.trim() || null;
16535
+ // A worker fast path always names one run. Keep that lookup on the
16536
+ // run-scoped outbox prefix: combining it with global recovery through a
16537
+ // nullable predicate made PostgreSQL materialize every pending run head
16538
+ // for each lifecycle transition. Only the two dedicated projectors may
16539
+ // perform the global distinct-head scan below.
16540
+ const selected = targetRunId
16541
+ ? await client.query<{ run_id: string }>(
16542
+ `
16543
+ WITH head AS MATERIALIZED (
16544
+ SELECT pending.run_id,
16545
+ pending.event_id,
16546
+ pending.event_type,
16547
+ pending.created_at,
16548
+ pending.next_attempt_at,
16549
+ pending.failed_at
16550
+ FROM ${tableName('outbox', options)} AS pending
16551
+ WHERE pending.run_id = $1
16552
+ AND pending.delivered_at IS NULL
16553
+ ORDER BY ${runLedgerOrderSql('pending')}
16554
+ LIMIT 1
16555
+ )
16556
+ SELECT runs.run_id
16557
+ FROM head
16558
+ JOIN ${tableName('runs', options)} AS runs ON runs.run_id = head.run_id
16559
+ WHERE head.failed_at IS NULL
16560
+ AND coalesce(head.next_attempt_at, head.created_at) <= now()
16561
+ AND NOT EXISTS (
16562
+ SELECT 1 FROM ${tableName('outbox', options)} AS active
16563
+ WHERE active.run_id = runs.run_id
16564
+ AND active.delivered_at IS NULL
16565
+ AND active.lease_owner IS NOT NULL
16566
+ AND active.lease_expires_at > now()
16567
+ )
16568
+ FOR UPDATE OF runs SKIP LOCKED
16569
+ `,
16570
+ [targetRunId],
16558
16571
  )
16559
- ORDER BY CASE WHEN head.event_type = 'run.created' THEN 0 ELSE 1 END,
16560
- head.created_at, runs.run_id
16561
- FOR UPDATE OF runs SKIP LOCKED LIMIT 1
16562
- `,
16563
- [input.runId?.trim() || null],
16564
- );
16572
+ : await client.query<{ run_id: string }>(`
16573
+ WITH heads AS MATERIALIZED (
16574
+ SELECT DISTINCT ON (pending.run_id)
16575
+ pending.run_id,
16576
+ pending.event_id,
16577
+ pending.event_type,
16578
+ pending.created_at,
16579
+ pending.next_attempt_at,
16580
+ pending.failed_at
16581
+ FROM ${tableName('outbox', options)} AS pending
16582
+ WHERE pending.delivered_at IS NULL
16583
+ ORDER BY pending.run_id, ${runLedgerOrderSql('pending')}
16584
+ )
16585
+ SELECT runs.run_id
16586
+ FROM heads AS head
16587
+ JOIN ${tableName('runs', options)} AS runs ON runs.run_id = head.run_id
16588
+ WHERE head.failed_at IS NULL
16589
+ AND coalesce(head.next_attempt_at, head.created_at) <= now()
16590
+ AND NOT EXISTS (
16591
+ SELECT 1 FROM ${tableName('outbox', options)} AS active
16592
+ WHERE active.run_id = runs.run_id
16593
+ AND active.delivered_at IS NULL
16594
+ AND active.lease_owner IS NOT NULL
16595
+ AND active.lease_expires_at > now()
16596
+ )
16597
+ ORDER BY CASE WHEN head.event_type = 'run.created' THEN 0 ELSE 1 END,
16598
+ head.created_at, runs.run_id
16599
+ FOR UPDATE OF runs SKIP LOCKED LIMIT 1
16600
+ `);
16565
16601
  const runId = selected.rows[0]?.run_id;
16566
16602
  const claimed = runId
16567
16603
  ? await readPendingPostgresSchedulerOutboxEvents(
@@ -53,6 +53,13 @@ const MAX_TIMEOUT_MS = 2_147_483_647;
53
53
  // saturated the shared serverless scheduler pool before projection began.
54
54
  export const RUN_LEDGER_OUTBOX_RECOVERY_MAX_IN_FLIGHT = 32;
55
55
 
56
+ // Two production replicas compete for the same durable queue. Eight delivery
57
+ // slots per replica keep enough headroom to drain a webhook burst while
58
+ // bounding one notification to sixteen global head claims across the service.
59
+ // The higher exported ceiling remains available to isolated recovery callers,
60
+ // but it is not the steady-state production setting.
61
+ const RUN_LEDGER_OUTBOX_RECOVERY_PRODUCTION_IN_FLIGHT = 8;
62
+
56
63
  type RecoveryTimer = ReturnType<typeof setTimeout>;
57
64
 
58
65
  export type RunLedgerOutboxRecoveryLogger = Pick<Console, 'info' | 'warn'>;
@@ -385,10 +392,10 @@ export function startRunLedgerOutboxRecoveryController(input: {
385
392
  schedulerOptions,
386
393
  ),
387
394
  // `dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope` releases each
388
- // short scheduler checkout before it calls the Vercel gateway. Keep the
389
- // durable projection wave large enough for a webhook burst without
390
- // expanding the process' Postgres connection budget.
391
- parallelism: RUN_LEDGER_OUTBOX_RECOVERY_MAX_IN_FLIGHT,
395
+ // short scheduler checkout before it calls the Vercel gateway. The two
396
+ // replicas therefore drain up to sixteen independent runs concurrently
397
+ // without turning one outbox notification into sixty-four head scans.
398
+ parallelism: RUN_LEDGER_OUTBOX_RECOVERY_PRODUCTION_IN_FLIGHT,
392
399
  readNextDueAt: () =>
393
400
  withRuntimeSchedulerClient(input.poolOptions, (client) =>
394
401
  readPostgresSchedulerOutboxNextDueAt(client, schedulerOptions),
package/dist/cli/index.js CHANGED
@@ -3051,7 +3051,7 @@ var SDK_RELEASE = {
3051
3051
  // getters keep their established compatibility behavior.
3052
3052
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3053
3053
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3054
- version: "0.3.172",
3054
+ version: "0.3.173",
3055
3055
  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.",
3056
3056
  packageCapabilities: {
3057
3057
  updatePreferences: 1
@@ -3046,7 +3046,7 @@ var SDK_RELEASE = {
3046
3046
  // getters keep their established compatibility behavior.
3047
3047
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3048
3048
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3049
- version: "0.3.172",
3049
+ version: "0.3.173",
3050
3050
  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.",
3051
3051
  packageCapabilities: {
3052
3052
  updatePreferences: 1
package/dist/index.js CHANGED
@@ -864,7 +864,7 @@ var SDK_RELEASE = {
864
864
  // getters keep their established compatibility behavior.
865
865
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
866
866
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
867
- version: "0.3.172",
867
+ version: "0.3.173",
868
868
  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.",
869
869
  packageCapabilities: {
870
870
  updatePreferences: 1
package/dist/index.mjs CHANGED
@@ -768,7 +768,7 @@ var SDK_RELEASE = {
768
768
  // getters keep their established compatibility behavior.
769
769
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
770
770
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
771
- version: "0.3.172",
771
+ version: "0.3.173",
772
772
  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.",
773
773
  packageCapabilities: {
774
774
  updatePreferences: 1
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.172";
152
+ readonly version: "0.3.173";
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.172";
152
+ readonly version: "0.3.173";
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.172",
77
+ version: "0.3.173",
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.172",
51
+ version: "0.3.173",
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.172",
3
+ "version": "0.3.173",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",