deepline 0.3.224 → 0.3.226

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.
@@ -3401,6 +3401,9 @@ export class DeeplineClient {
3401
3401
  if (options.searchTerms?.trim()) {
3402
3402
  params.set('search_terms', options.searchTerms.trim());
3403
3403
  }
3404
+ if (options.task?.trim()) {
3405
+ params.set('task', options.task.trim());
3406
+ }
3404
3407
  return this.http.get<ToolSearchResult>(
3405
3408
  `/api/v2/tools/search?${params.toString()}`,
3406
3409
  );
@@ -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.224',
203
+ version: '0.3.226',
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: {
@@ -476,6 +476,8 @@ export interface ToolSearchOptions {
476
476
  categories?: string;
477
477
  /** Optional explicit search terms used by agent/CLI callers. */
478
478
  searchTerms?: string;
479
+ /** One sentence: the input you have and the result you need (not the query restated). */
480
+ task?: string;
479
481
  /** Search algorithm/version. Defaults to the current ranked mode. */
480
482
  searchMode?: 'v1' | 'v2';
481
483
  /** Include backend debug metadata in the search response. */
@@ -51,9 +51,11 @@ import {
51
51
  import { PLAY_RUNTIME_API_COMPAT_PATH } from './/runtime-api-paths';
52
52
  import {
53
53
  buildRunLedgerEventsIdempotencyKey,
54
+ isRunLedgerProjectionMismatchDiagnostic,
54
55
  isRunLedgerProjectionLeaseLostReason,
55
56
  type RunLedgerProjectionChunk,
56
57
  type RunLedgerProjectionLeaseLostReason,
58
+ type RunLedgerProjectionMismatchDiagnostic,
57
59
  } from './run-ledger-projection-contract';
58
60
  import { partitionRunEventsForAppRuntime } from './run-ledger-event-transport';
59
61
  import {
@@ -851,6 +853,21 @@ function appRuntimeFailureReason(
851
853
  }
852
854
  }
853
855
 
856
+ function appRuntimeProjectionMismatch(
857
+ responseCode: string | null,
858
+ body: string,
859
+ ): RunLedgerProjectionMismatchDiagnostic | null {
860
+ if (responseCode !== 'RUN_LEDGER_DELIVERY_LEASE_LOST') return null;
861
+ try {
862
+ const parsed = JSON.parse(body) as { projectionMismatch?: unknown };
863
+ return isRunLedgerProjectionMismatchDiagnostic(parsed.projectionMismatch)
864
+ ? parsed.projectionMismatch
865
+ : null;
866
+ } catch {
867
+ return null;
868
+ }
869
+ }
870
+
854
871
  export function isTransientAppRuntimeFailureBody(body: string): boolean {
855
872
  return /WorkerOverloaded|"\s*code\s*"\s*:\s*"\s*InternalServerError\s*"|Your request couldn't be completed\. Try again later\.|timeout exceeded when trying to connect|timed out|fetch failed|ECONNRESET|ECONNREFUSED|UND_ERR_CONNECT_TIMEOUT|tuple concurrently updated|RUNTIME_SCHEDULER_(?:SATURATED|UNAVAILABLE|SCHEMA_NOT_READY)|Runtime scheduler DB pool is saturated|Runtime scheduler DB circuit breaker is open|Runtime scheduler schema .* is not ready|OptimisticConcurrencyControlFailure|changed while this mutation was being run|Documents read from or written to the .* table changed while this mutation/i.test(
856
873
  body,
@@ -1264,6 +1281,7 @@ export class AppRuntimeApiResponseError extends Error {
1264
1281
  readonly status: number;
1265
1282
  readonly code: string | null;
1266
1283
  readonly failureReason: RunLedgerProjectionLeaseLostReason | null;
1284
+ readonly projectionMismatch: RunLedgerProjectionMismatchDiagnostic | null;
1267
1285
  readonly requestId: string | null;
1268
1286
  readonly retryable: boolean;
1269
1287
  /** Server-requested delay, retained for durable callers after local retries end. */
@@ -1275,6 +1293,7 @@ export class AppRuntimeApiResponseError extends Error {
1275
1293
  status: number;
1276
1294
  code?: string | null;
1277
1295
  failureReason?: RunLedgerProjectionLeaseLostReason | null;
1296
+ projectionMismatch?: RunLedgerProjectionMismatchDiagnostic | null;
1278
1297
  requestId?: string | null;
1279
1298
  retryable: boolean;
1280
1299
  retryAfterMs?: number | null;
@@ -1292,6 +1311,7 @@ export class AppRuntimeApiResponseError extends Error {
1292
1311
  this.status = input.status;
1293
1312
  this.code = input.code?.trim() || null;
1294
1313
  this.failureReason = input.failureReason ?? null;
1314
+ this.projectionMismatch = input.projectionMismatch ?? null;
1295
1315
  this.requestId = input.requestId?.trim() || null;
1296
1316
  this.retryable = input.retryable;
1297
1317
  this.retryAfterMs =
@@ -1757,6 +1777,7 @@ async function postAppRuntimeApi<TResponse>(
1757
1777
  status: response.status,
1758
1778
  code,
1759
1779
  failureReason: appRuntimeFailureReason(code, responseText),
1780
+ projectionMismatch: appRuntimeProjectionMismatch(code, responseText),
1760
1781
  requestId,
1761
1782
  // The structured response is authoritative even for a 5xx. Retrying an
1762
1783
  // explicitly deterministic database failure here turns one rejected SQL
@@ -45,6 +45,124 @@ export const RUN_LEDGER_PROJECTION_LEASE_LOST_REASONS = [
45
45
  'projected_events_mismatch',
46
46
  ] as const;
47
47
 
48
+ export const RUN_LEDGER_PROJECTION_MISMATCH_KINDS = [
49
+ 'expected_chunk_unavailable',
50
+ 'event_count_mismatch',
51
+ 'event_content_mismatch',
52
+ ] as const;
53
+
54
+ export const RUN_LEDGER_PROJECTION_MISMATCH_FIELDS = [
55
+ 'type',
56
+ 'runId',
57
+ 'occurredAt',
58
+ 'source',
59
+ 'opaque',
60
+ 'payload',
61
+ 'seq',
62
+ 'status',
63
+ 'playName',
64
+ 'runtimeBackend',
65
+ 'triggerSource',
66
+ 'inputSummary',
67
+ 'definitionScope',
68
+ 'result',
69
+ 'resultSummary',
70
+ 'error',
71
+ 'errorSummary',
72
+ 'retryAfterMs',
73
+ 'waitKind',
74
+ 'waitUntil',
75
+ 'nodeId',
76
+ 'progress',
77
+ 'stepId',
78
+ 'toolId',
79
+ 'provider',
80
+ 'operation',
81
+ 'lines',
82
+ 'channelOffset',
83
+ 'producerAttempt',
84
+ 'other',
85
+ ] as const;
86
+
87
+ export type RunLedgerProjectionMismatchKind =
88
+ (typeof RUN_LEDGER_PROJECTION_MISMATCH_KINDS)[number];
89
+
90
+ export type RunLedgerProjectionMismatchField =
91
+ (typeof RUN_LEDGER_PROJECTION_MISMATCH_FIELDS)[number];
92
+
93
+ /** Payload-free comparison facts safe to persist in the operator diagnostics. */
94
+ export type RunLedgerProjectionMismatchDiagnostic = {
95
+ kind: RunLedgerProjectionMismatchKind;
96
+ expectedEventCount: number | null;
97
+ projectedEventCount: number;
98
+ chunkIndex: number | null;
99
+ chunkCount: number | null;
100
+ firstMismatchIndex: number | null;
101
+ eventTypeMatches: boolean | null;
102
+ mismatchedFields: RunLedgerProjectionMismatchField[];
103
+ };
104
+
105
+ export function isRunLedgerProjectionMismatchDiagnostic(
106
+ value: unknown,
107
+ ): value is RunLedgerProjectionMismatchDiagnostic {
108
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
109
+ const candidate = value as Record<string, unknown>;
110
+ const diagnosticKeys = [
111
+ 'kind',
112
+ 'expectedEventCount',
113
+ 'projectedEventCount',
114
+ 'chunkIndex',
115
+ 'chunkCount',
116
+ 'firstMismatchIndex',
117
+ 'eventTypeMatches',
118
+ 'mismatchedFields',
119
+ ];
120
+ const keys = Object.keys(candidate);
121
+ if (
122
+ keys.length !== diagnosticKeys.length ||
123
+ keys.some((key) => !diagnosticKeys.includes(key))
124
+ ) {
125
+ return false;
126
+ }
127
+ return (
128
+ typeof candidate.kind === 'string' &&
129
+ RUN_LEDGER_PROJECTION_MISMATCH_KINDS.includes(
130
+ candidate.kind as RunLedgerProjectionMismatchKind,
131
+ ) &&
132
+ (candidate.expectedEventCount === null ||
133
+ (Number.isSafeInteger(candidate.expectedEventCount) &&
134
+ Number(candidate.expectedEventCount) >= 0)) &&
135
+ Number.isSafeInteger(candidate.projectedEventCount) &&
136
+ Number(candidate.projectedEventCount) >= 0 &&
137
+ (candidate.chunkIndex === null ||
138
+ (Number.isSafeInteger(candidate.chunkIndex) &&
139
+ Number(candidate.chunkIndex) >= 0)) &&
140
+ (candidate.chunkCount === null ||
141
+ (Number.isSafeInteger(candidate.chunkCount) &&
142
+ Number(candidate.chunkCount) > 1)) &&
143
+ ((candidate.chunkIndex === null && candidate.chunkCount === null) ||
144
+ (Number.isSafeInteger(candidate.chunkIndex) &&
145
+ Number.isSafeInteger(candidate.chunkCount) &&
146
+ Number(candidate.chunkIndex) < Number(candidate.chunkCount))) &&
147
+ (candidate.firstMismatchIndex === null ||
148
+ (Number.isSafeInteger(candidate.firstMismatchIndex) &&
149
+ Number(candidate.firstMismatchIndex) >= 0)) &&
150
+ (candidate.eventTypeMatches === null ||
151
+ typeof candidate.eventTypeMatches === 'boolean') &&
152
+ Array.isArray(candidate.mismatchedFields) &&
153
+ candidate.mismatchedFields.length <= 8 &&
154
+ candidate.mismatchedFields.every(
155
+ (field) =>
156
+ typeof field === 'string' &&
157
+ RUN_LEDGER_PROJECTION_MISMATCH_FIELDS.includes(
158
+ field as RunLedgerProjectionMismatchField,
159
+ ),
160
+ ) &&
161
+ new Set(candidate.mismatchedFields).size ===
162
+ candidate.mismatchedFields.length
163
+ );
164
+ }
165
+
48
166
  export type RunLedgerProjectionLeaseLostReason =
49
167
  (typeof RUN_LEDGER_PROJECTION_LEASE_LOST_REASONS)[number];
50
168
 
@@ -61,13 +179,16 @@ export function isRunLedgerProjectionLeaseLostReason(
61
179
 
62
180
  export class RunLedgerProjectionLeaseLostError extends Error {
63
181
  readonly reason: RunLedgerProjectionLeaseLostReason;
182
+ readonly projectionMismatch: RunLedgerProjectionMismatchDiagnostic | null;
64
183
 
65
184
  constructor(
66
185
  reason: RunLedgerProjectionLeaseLostReason = 'delivery_lease_not_current',
186
+ projectionMismatch: RunLedgerProjectionMismatchDiagnostic | null = null,
67
187
  ) {
68
188
  super('Run Ledger projection requires the current outbox delivery lease.');
69
189
  this.name = 'RunLedgerProjectionLeaseLostError';
70
190
  this.reason = reason;
191
+ this.projectionMismatch = projectionMismatch;
71
192
  }
72
193
  }
73
194
 
@@ -0,0 +1,151 @@
1
+ import { stableStringify } from '../plays/row-identity';
2
+ import type {
3
+ AcceptedPlayRunLedgerEvent,
4
+ PlayRunLedgerIngressEvent,
5
+ } from './run-ledger';
6
+ import { isPlayRunLedgerOpaqueEvent } from './run-ledger';
7
+ import {
8
+ RUN_LEDGER_PROJECTION_MISMATCH_FIELDS,
9
+ type RunLedgerProjectionChunk,
10
+ type RunLedgerProjectionMismatchDiagnostic,
11
+ type RunLedgerProjectionMismatchField,
12
+ } from './run-ledger-projection-contract';
13
+
14
+ type ComparableRunLedgerEvent =
15
+ | AcceptedPlayRunLedgerEvent
16
+ | PlayRunLedgerIngressEvent;
17
+
18
+ /**
19
+ * A newer app may receive a projection from a worker that predates optional
20
+ * wait metadata. Normalize only those absent fields before the exact compare.
21
+ */
22
+ function normalizeLegacyRunWaitingProjectionFields(
23
+ projectedEvents: readonly AcceptedPlayRunLedgerEvent[],
24
+ expectedEvents: readonly ComparableRunLedgerEvent[],
25
+ ): AcceptedPlayRunLedgerEvent[] {
26
+ return projectedEvents.map((event, index) => {
27
+ const expected = expectedEvents[index];
28
+ if (
29
+ isPlayRunLedgerOpaqueEvent(event) ||
30
+ event.type !== 'run.waiting' ||
31
+ expected?.type !== 'run.waiting' ||
32
+ ('opaque' in expected && expected.opaque === true)
33
+ ) {
34
+ return event;
35
+ }
36
+ const expectedEvent = expected as Record<string, unknown>;
37
+ const expectedWaitKind = expectedEvent.waitKind;
38
+ const expectedWaitUntil = expectedEvent.waitUntil;
39
+ return {
40
+ ...event,
41
+ ...(event.waitKind === undefined &&
42
+ (typeof expectedWaitKind === 'string' || expectedWaitKind === null)
43
+ ? { waitKind: expectedWaitKind }
44
+ : {}),
45
+ ...(event.waitUntil === undefined &&
46
+ (typeof expectedWaitUntil === 'number' || expectedWaitUntil === null)
47
+ ? { waitUntil: expectedWaitUntil }
48
+ : {}),
49
+ };
50
+ });
51
+ }
52
+
53
+ function eventType(event: ComparableRunLedgerEvent | undefined): string | null {
54
+ if (!event) return null;
55
+ return typeof event.type === 'string'
56
+ ? event.type
57
+ : typeof event.key === 'string'
58
+ ? event.key
59
+ : null;
60
+ }
61
+
62
+ function safeMismatchedFields(
63
+ projected: ComparableRunLedgerEvent,
64
+ expected: ComparableRunLedgerEvent,
65
+ ): RunLedgerProjectionMismatchField[] {
66
+ const projectedRecord = projected as Record<string, unknown>;
67
+ const expectedRecord = expected as Record<string, unknown>;
68
+ const allowedFields = new Set<string>(RUN_LEDGER_PROJECTION_MISMATCH_FIELDS);
69
+ const fields = new Set<RunLedgerProjectionMismatchField>();
70
+ const keys = new Set([
71
+ ...Object.keys(projectedRecord),
72
+ ...Object.keys(expectedRecord),
73
+ ]);
74
+ for (const key of [...keys].sort()) {
75
+ if (
76
+ stableStringify(projectedRecord[key]) ===
77
+ stableStringify(expectedRecord[key])
78
+ ) {
79
+ continue;
80
+ }
81
+ fields.add(
82
+ allowedFields.has(key)
83
+ ? (key as RunLedgerProjectionMismatchField)
84
+ : 'other',
85
+ );
86
+ if (fields.size === 8) break;
87
+ }
88
+ return [...fields];
89
+ }
90
+
91
+ /**
92
+ * Compare one received chunk with its canonical outbox slice and return only
93
+ * bounded structural facts. Event values, IDs, and opaque payload keys never
94
+ * leave this module.
95
+ */
96
+ export function runLedgerProjectionMismatch(input: {
97
+ projectedEvents: readonly AcceptedPlayRunLedgerEvent[];
98
+ expectedEvents: readonly ComparableRunLedgerEvent[] | null;
99
+ chunk?: RunLedgerProjectionChunk;
100
+ }): RunLedgerProjectionMismatchDiagnostic | null {
101
+ const chunkIndex = input.chunk?.index ?? null;
102
+ const chunkCount = input.chunk?.count ?? null;
103
+ const projectedEventCount = input.projectedEvents.length;
104
+ if (input.expectedEvents === null) {
105
+ return {
106
+ kind: 'expected_chunk_unavailable',
107
+ expectedEventCount: null,
108
+ projectedEventCount,
109
+ chunkIndex,
110
+ chunkCount,
111
+ firstMismatchIndex: null,
112
+ eventTypeMatches: null,
113
+ mismatchedFields: [],
114
+ };
115
+ }
116
+
117
+ const normalizedProjectedEvents = normalizeLegacyRunWaitingProjectionFields(
118
+ input.projectedEvents,
119
+ input.expectedEvents,
120
+ );
121
+ const expectedEventCount = input.expectedEvents.length;
122
+ const sharedEventCount = Math.min(projectedEventCount, expectedEventCount);
123
+ for (let index = 0; index < sharedEventCount; index += 1) {
124
+ const projected = normalizedProjectedEvents[index]!;
125
+ const expected = input.expectedEvents[index]!;
126
+ if (stableStringify(projected) === stableStringify(expected)) continue;
127
+ return {
128
+ kind: 'event_content_mismatch',
129
+ expectedEventCount,
130
+ projectedEventCount,
131
+ chunkIndex,
132
+ chunkCount,
133
+ firstMismatchIndex: index,
134
+ eventTypeMatches: eventType(projected) === eventType(expected),
135
+ mismatchedFields: safeMismatchedFields(projected, expected),
136
+ };
137
+ }
138
+ if (projectedEventCount !== expectedEventCount) {
139
+ return {
140
+ kind: 'event_count_mismatch',
141
+ expectedEventCount,
142
+ projectedEventCount,
143
+ chunkIndex,
144
+ chunkCount,
145
+ firstMismatchIndex: sharedEventCount,
146
+ eventTypeMatches: null,
147
+ mismatchedFields: [],
148
+ };
149
+ }
150
+ return null;
151
+ }
@@ -78,7 +78,6 @@ import {
78
78
  } from '../work-receipts';
79
79
  import type { PlayStaticPipeline } from '../../plays/static-pipeline';
80
80
  import {
81
- isPlayRunLedgerOpaqueEvent,
82
81
  LOG_TAIL_LIMIT,
83
82
  type AcceptedPlayRunLedgerEvent,
84
83
  type PlayRunLedgerEvent,
@@ -98,9 +97,11 @@ import {
98
97
  RunLedgerProjectionLeaseLostError,
99
98
  type RunLedgerProjectionChunk,
100
99
  type RunLedgerProjectionLeaseLostReason,
100
+ type RunLedgerProjectionMismatchDiagnostic,
101
101
  buildRunLedgerStartIdempotencyKey,
102
102
  buildRunLedgerTerminalIdempotencyKey,
103
103
  } from '../run-ledger-projection-contract';
104
+ import { runLedgerProjectionMismatch } from '../run-ledger-projection-diagnostics';
104
105
  import { selectRunEventsForAppRuntimeProjectionChunk } from '../run-ledger-event-transport';
105
106
  import {
106
107
  assertTerminalRunResultWithinLimit,
@@ -15938,64 +15939,6 @@ async function appendRunLedgerOutboxFact(
15938
15939
 
15939
15940
  export { RunLedgerProjectionLeaseLostError } from '../run-ledger-projection-contract';
15940
15941
 
15941
- /**
15942
- * A newer app can receive a projection from a worker that predates optional
15943
- * wait metadata. Treat only those absent fields as their canonical values;
15944
- * lease identity, event ordering, and every field the worker did send remain
15945
- * exact.
15946
- */
15947
- function normalizeLegacyRunWaitingProjectionFields(
15948
- projectedEvents: readonly AcceptedPlayRunLedgerEvent[],
15949
- expectedEvents: readonly (
15950
- | AcceptedPlayRunLedgerEvent
15951
- | PlayRunLedgerIngressEvent
15952
- )[],
15953
- ): AcceptedPlayRunLedgerEvent[] {
15954
- return projectedEvents.map((event, index) => {
15955
- const expected = expectedEvents[index];
15956
- if (
15957
- isPlayRunLedgerOpaqueEvent(event) ||
15958
- event.type !== 'run.waiting' ||
15959
- expected?.type !== 'run.waiting' ||
15960
- ('opaque' in expected && expected.opaque === true)
15961
- ) {
15962
- return event;
15963
- }
15964
- const expectedEvent = expected as Record<string, unknown>;
15965
- const expectedWaitKind = expectedEvent.waitKind;
15966
- const expectedWaitUntil = expectedEvent.waitUntil;
15967
- return {
15968
- ...event,
15969
- ...(event.waitKind === undefined &&
15970
- (typeof expectedWaitKind === 'string' || expectedWaitKind === null)
15971
- ? { waitKind: expectedWaitKind }
15972
- : {}),
15973
- ...(event.waitUntil === undefined &&
15974
- (typeof expectedWaitUntil === 'number' || expectedWaitUntil === null)
15975
- ? { waitUntil: expectedWaitUntil }
15976
- : {}),
15977
- };
15978
- });
15979
- }
15980
-
15981
- function runLedgerProjectionMatchesCanonicalPrefix(
15982
- projectedEvents: readonly AcceptedPlayRunLedgerEvent[],
15983
- expectedEvents: readonly (
15984
- | AcceptedPlayRunLedgerEvent
15985
- | PlayRunLedgerIngressEvent
15986
- )[],
15987
- ): boolean {
15988
- if (projectedEvents.length !== expectedEvents.length) return false;
15989
- return (
15990
- stableStringify(
15991
- normalizeLegacyRunWaitingProjectionFields(
15992
- projectedEvents,
15993
- expectedEvents,
15994
- ),
15995
- ) === stableStringify(expectedEvents)
15996
- );
15997
- }
15998
-
15999
15942
  /** Extend only our still-live lease before another bounded transport piece. */
16000
15943
  export async function renewPostgresRunLedgerDelivery(
16001
15944
  client: PostgresSchedulerQueryClient,
@@ -16183,16 +16126,17 @@ export async function assertPostgresRunLedgerDelivery(
16183
16126
  ? input.sanitizeExpectedProjectionEvents(prefixEvents)
16184
16127
  : prefixEvents;
16185
16128
  }
16186
- if (
16187
- expectedProjectionEvents !== undefined &&
16188
- runLedgerProjectionMatchesCanonicalPrefix(
16189
- input.projectedEvents,
16190
- expectedProjectionEvents,
16191
- )
16192
- ) {
16193
- return;
16194
- }
16195
- throw new RunLedgerProjectionLeaseLostError('projected_events_mismatch');
16129
+ const projectionMismatch: RunLedgerProjectionMismatchDiagnostic | null =
16130
+ runLedgerProjectionMismatch({
16131
+ projectedEvents: input.projectedEvents,
16132
+ expectedEvents: expectedProjectionEvents ?? null,
16133
+ ...(input.projectionChunk ? { chunk: input.projectionChunk } : {}),
16134
+ });
16135
+ if (projectionMismatch === null) return;
16136
+ throw new RunLedgerProjectionLeaseLostError(
16137
+ 'projected_events_mismatch',
16138
+ projectionMismatch,
16139
+ );
16196
16140
  }
16197
16141
 
16198
16142
  if (
@@ -16728,6 +16672,7 @@ function runLedgerDeliveryFailure(input: { error: unknown }): {
16728
16672
  status: number | null;
16729
16673
  retryable: boolean;
16730
16674
  failureReason: RunLedgerProjectionLeaseLostReason | null;
16675
+ projectionMismatch: RunLedgerProjectionMismatchDiagnostic | null;
16731
16676
  retryAfterMs: number | null;
16732
16677
  } {
16733
16678
  if (input.error instanceof AppRuntimeApiResponseError) {
@@ -16748,6 +16693,7 @@ function runLedgerDeliveryFailure(input: { error: unknown }): {
16748
16693
  status: input.error.status,
16749
16694
  retryable,
16750
16695
  failureReason: input.error.failureReason,
16696
+ projectionMismatch: input.error.projectionMismatch,
16751
16697
  retryAfterMs:
16752
16698
  input.error.retryAfterMs === null
16753
16699
  ? null
@@ -16764,6 +16710,7 @@ function runLedgerDeliveryFailure(input: { error: unknown }): {
16764
16710
  status: null,
16765
16711
  retryable: true,
16766
16712
  failureReason: null,
16713
+ projectionMismatch: null,
16767
16714
  retryAfterMs: null,
16768
16715
  };
16769
16716
  }
@@ -16775,6 +16722,7 @@ function runLedgerDeliveryFailure(input: { error: unknown }): {
16775
16722
  status: null,
16776
16723
  retryable: true,
16777
16724
  failureReason: null,
16725
+ projectionMismatch: null,
16778
16726
  retryAfterMs: null,
16779
16727
  };
16780
16728
  }
@@ -16874,6 +16822,9 @@ export async function settlePostgresSchedulerOutboxFailure(
16874
16822
  ...(failure.failureReason
16875
16823
  ? { failureReason: failure.failureReason }
16876
16824
  : {}),
16825
+ ...(failure.projectionMismatch
16826
+ ? { projectionMismatch: failure.projectionMismatch }
16827
+ : {}),
16877
16828
  retryAfterMs: failure.retryAfterMs,
16878
16829
  recordedAt: new Date().toISOString(),
16879
16830
  }),
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.224",
3054
+ version: "0.3.226",
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
@@ -7603,6 +7603,9 @@ var DeeplineClient = class _DeeplineClient {
7603
7603
  if (options.searchTerms?.trim()) {
7604
7604
  params.set("search_terms", options.searchTerms.trim());
7605
7605
  }
7606
+ if (options.task?.trim()) {
7607
+ params.set("task", options.task.trim());
7608
+ }
7606
7609
  return this.http.get(
7607
7610
  `/api/v2/tools/search?${params.toString()}`
7608
7611
  );
@@ -50068,6 +50071,7 @@ async function searchTools(queryInput, options = {}) {
50068
50071
  query,
50069
50072
  categories: options.categories,
50070
50073
  searchTerms: options.searchTerms,
50074
+ task: options.task,
50071
50075
  limit: options.limit,
50072
50076
  offset: options.offset,
50073
50077
  searchMode: options.searchMode,
@@ -50303,6 +50307,9 @@ Notes:
50303
50307
  supplied. Providing neither is a usage error. Both filters accept
50304
50308
  comma-separated values. Use --limit and --offset to page through ranked
50305
50309
  results (limit 1-50, offset is zero-based); JSON includes next_offset.
50310
+ Pass --task with one sentence on what you are trying to accomplish right
50311
+ now: the input you have and the result you need, not a restatement of the
50312
+ query. It materially improves ranking, especially for short queries.
50306
50313
  Use a provider name in the query; --prefix is not a supported option.
50307
50314
  The grep alias is the same ranked retrieval surface with a more literal name
50308
50315
  for agents that are filtering a registry rather than choosing a workflow.
@@ -50310,6 +50317,7 @@ Notes:
50310
50317
  Examples:
50311
50318
  deepline tools search email --limit 10 --json
50312
50319
  deepline tools search email --limit 10 --offset 10 --json
50320
+ deepline tools search linkedin --task "I have 200 LinkedIn profile URLs and need each person's current title and company" --json
50313
50321
  deepline tools search --categories company_search --search_terms "investors,funding"
50314
50322
  deepline tools grep "company enrichment" --categories enrichment --json
50315
50323
  deepline tools search verifier --search-mode v2 --json
@@ -50320,7 +50328,10 @@ Examples:
50320
50328
  ).option(
50321
50329
  "--search_terms <terms>",
50322
50330
  "Comma-separated structured search terms; may be used without a query"
50323
- ).option("--search-terms <terms>", "Alias for --search_terms").option("--limit <count>", "Maximum ranked results to return (1-50)").option("--offset <count>", "Zero-based ranked result offset").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
50331
+ ).option("--search-terms <terms>", "Alias for --search_terms").option(
50332
+ "--task <sentence>",
50333
+ "What you are trying to accomplish: input you have -> result you need"
50334
+ ).option("--limit <count>", "Maximum ranked results to return (1-50)").option("--offset <count>", "Zero-based ranked result offset").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
50324
50335
  process.exitCode = await searchTools(query, {
50325
50336
  json: options.json,
50326
50337
  compact: options.compact,
@@ -50328,6 +50339,7 @@ Examples:
50328
50339
  offset: options.offset !== void 0 ? Number.parseInt(options.offset, 10) : void 0,
50329
50340
  categories: options.categories,
50330
50341
  searchTerms: options.searchTerms ?? options.search_terms,
50342
+ task: options.task,
50331
50343
  searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
50332
50344
  includeSearchDebug: Boolean(options.includeSearchDebug)
50333
50345
  });
@@ -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.224",
3049
+ version: "0.3.226",
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
@@ -7598,6 +7598,9 @@ var DeeplineClient = class _DeeplineClient {
7598
7598
  if (options.searchTerms?.trim()) {
7599
7599
  params.set("search_terms", options.searchTerms.trim());
7600
7600
  }
7601
+ if (options.task?.trim()) {
7602
+ params.set("task", options.task.trim());
7603
+ }
7601
7604
  return this.http.get(
7602
7605
  `/api/v2/tools/search?${params.toString()}`
7603
7606
  );
@@ -50216,6 +50219,7 @@ async function searchTools(queryInput, options = {}) {
50216
50219
  query,
50217
50220
  categories: options.categories,
50218
50221
  searchTerms: options.searchTerms,
50222
+ task: options.task,
50219
50223
  limit: options.limit,
50220
50224
  offset: options.offset,
50221
50225
  searchMode: options.searchMode,
@@ -50451,6 +50455,9 @@ Notes:
50451
50455
  supplied. Providing neither is a usage error. Both filters accept
50452
50456
  comma-separated values. Use --limit and --offset to page through ranked
50453
50457
  results (limit 1-50, offset is zero-based); JSON includes next_offset.
50458
+ Pass --task with one sentence on what you are trying to accomplish right
50459
+ now: the input you have and the result you need, not a restatement of the
50460
+ query. It materially improves ranking, especially for short queries.
50454
50461
  Use a provider name in the query; --prefix is not a supported option.
50455
50462
  The grep alias is the same ranked retrieval surface with a more literal name
50456
50463
  for agents that are filtering a registry rather than choosing a workflow.
@@ -50458,6 +50465,7 @@ Notes:
50458
50465
  Examples:
50459
50466
  deepline tools search email --limit 10 --json
50460
50467
  deepline tools search email --limit 10 --offset 10 --json
50468
+ deepline tools search linkedin --task "I have 200 LinkedIn profile URLs and need each person's current title and company" --json
50461
50469
  deepline tools search --categories company_search --search_terms "investors,funding"
50462
50470
  deepline tools grep "company enrichment" --categories enrichment --json
50463
50471
  deepline tools search verifier --search-mode v2 --json
@@ -50468,7 +50476,10 @@ Examples:
50468
50476
  ).option(
50469
50477
  "--search_terms <terms>",
50470
50478
  "Comma-separated structured search terms; may be used without a query"
50471
- ).option("--search-terms <terms>", "Alias for --search_terms").option("--limit <count>", "Maximum ranked results to return (1-50)").option("--offset <count>", "Zero-based ranked result offset").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
50479
+ ).option("--search-terms <terms>", "Alias for --search_terms").option(
50480
+ "--task <sentence>",
50481
+ "What you are trying to accomplish: input you have -> result you need"
50482
+ ).option("--limit <count>", "Maximum ranked results to return (1-50)").option("--offset <count>", "Zero-based ranked result offset").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
50472
50483
  process.exitCode = await searchTools(query, {
50473
50484
  json: options.json,
50474
50485
  compact: options.compact,
@@ -50476,6 +50487,7 @@ Examples:
50476
50487
  offset: options.offset !== void 0 ? Number.parseInt(options.offset, 10) : void 0,
50477
50488
  categories: options.categories,
50478
50489
  searchTerms: options.searchTerms ?? options.search_terms,
50490
+ task: options.task,
50479
50491
  searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
50480
50492
  includeSearchDebug: Boolean(options.includeSearchDebug)
50481
50493
  });
package/dist/index.d.mts CHANGED
@@ -1492,6 +1492,8 @@ interface ToolSearchOptions {
1492
1492
  categories?: string;
1493
1493
  /** Optional explicit search terms used by agent/CLI callers. */
1494
1494
  searchTerms?: string;
1495
+ /** One sentence: the input you have and the result you need (not the query restated). */
1496
+ task?: string;
1495
1497
  /** Search algorithm/version. Defaults to the current ranked mode. */
1496
1498
  searchMode?: 'v1' | 'v2';
1497
1499
  /** Include backend debug metadata in the search response. */
package/dist/index.d.ts CHANGED
@@ -1492,6 +1492,8 @@ interface ToolSearchOptions {
1492
1492
  categories?: string;
1493
1493
  /** Optional explicit search terms used by agent/CLI callers. */
1494
1494
  searchTerms?: string;
1495
+ /** One sentence: the input you have and the result you need (not the query restated). */
1496
+ task?: string;
1495
1497
  /** Search algorithm/version. Defaults to the current ranked mode. */
1496
1498
  searchMode?: 'v1' | 'v2';
1497
1499
  /** Include backend debug metadata in the search response. */
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.224",
867
+ version: "0.3.226",
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
@@ -5275,6 +5275,9 @@ var DeeplineClient = class _DeeplineClient {
5275
5275
  if (options.searchTerms?.trim()) {
5276
5276
  params.set("search_terms", options.searchTerms.trim());
5277
5277
  }
5278
+ if (options.task?.trim()) {
5279
+ params.set("task", options.task.trim());
5280
+ }
5278
5281
  return this.http.get(
5279
5282
  `/api/v2/tools/search?${params.toString()}`
5280
5283
  );
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.224",
771
+ version: "0.3.226",
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
@@ -5179,6 +5179,9 @@ var DeeplineClient = class _DeeplineClient {
5179
5179
  if (options.searchTerms?.trim()) {
5180
5180
  params.set("search_terms", options.searchTerms.trim());
5181
5181
  }
5182
+ if (options.task?.trim()) {
5183
+ params.set("task", options.task.trim());
5184
+ }
5182
5185
  return this.http.get(
5183
5186
  `/api/v2/tools/search?${params.toString()}`
5184
5187
  );
@@ -295,6 +295,7 @@
295
295
  "dist/bundling-sources/shared_libs/play-runtime/run-identity.ts",
296
296
  "dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts",
297
297
  "dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-contract.ts",
298
+ "dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-diagnostics.ts",
298
299
  "dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts",
299
300
  "dist/bundling-sources/shared_libs/play-runtime/run-lifecycle-policy.ts",
300
301
  "dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts",
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.224";
152
+ readonly version: "0.3.226";
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.224";
152
+ readonly version: "0.3.226";
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.224",
77
+ version: "0.3.226",
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.224",
51
+ version: "0.3.226",
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.224",
3
+ "version": "0.3.226",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",