deepline 0.1.80 → 0.1.81

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.
@@ -139,6 +139,43 @@ function formatInsufficientCreditsMessage(input: {
139
139
  return `Workspace balance ${balance} < required ${required} for ${operation}.${addSuffix}`;
140
140
  }
141
141
 
142
+ function formatPublicToolErrorPayload(input: {
143
+ parsed: Record<string, unknown> | null;
144
+ bodyText: string;
145
+ }): string {
146
+ if (!input.parsed) {
147
+ return input.bodyText.slice(0, 500);
148
+ }
149
+
150
+ const selected: Record<string, unknown> = {};
151
+ for (const key of [
152
+ 'error',
153
+ 'message',
154
+ 'code',
155
+ 'failure_origin',
156
+ 'error_category',
157
+ 'failure_description',
158
+ 'operator_hint',
159
+ 'failure_hint',
160
+ 'details',
161
+ 'provider',
162
+ 'operation',
163
+ 'request_id',
164
+ 'requestId',
165
+ 'credential_source',
166
+ 'credential_owner',
167
+ ]) {
168
+ const value = input.parsed[key];
169
+ if (typeof value === 'string' && value.trim()) {
170
+ selected[key] = value;
171
+ }
172
+ }
173
+
174
+ return JSON.stringify(
175
+ Object.keys(selected).length > 0 ? selected : input.parsed,
176
+ ).slice(0, 1_500);
177
+ }
178
+
142
179
  export function normalizeToolHttpErrorMessage(input: {
143
180
  toolId: string;
144
181
  status: number;
@@ -183,7 +220,12 @@ export function normalizeToolHttpErrorMessage(input: {
183
220
  );
184
221
  }
185
222
  return new ToolHttpError(
186
- `tool ${input.toolId} ${input.status} attempt ${input.attempt}/${input.maxAttempts}: ${input.bodyText.slice(0, 500)}`,
223
+ `tool ${input.toolId} ${input.status} attempt ${input.attempt}/${input.maxAttempts}: ${formatPublicToolErrorPayload(
224
+ {
225
+ parsed,
226
+ bodyText: input.bodyText,
227
+ },
228
+ )}`,
187
229
  billing,
188
230
  );
189
231
  }
@@ -1297,7 +1297,7 @@ export class DeeplineClient {
1297
1297
  }
1298
1298
  const query = params.size > 0 ? `?${params.toString()}` : '';
1299
1299
  const response = await this.http.get<Record<string, unknown>>(
1300
- `/api/v2/plays/run/${encodeURIComponent(workflowId)}${query}`,
1300
+ `/api/v2/runs/${encodeURIComponent(workflowId)}${query}`,
1301
1301
  );
1302
1302
  return normalizePlayStatus(response);
1303
1303
  }
@@ -1320,10 +1320,10 @@ export class DeeplineClient {
1320
1320
  options?.lastEventId && options.lastEventId.trim()
1321
1321
  ? { 'Last-Event-ID': options.lastEventId.trim() }
1322
1322
  : undefined;
1323
- const params = new URLSearchParams({ stream: 'true' });
1323
+ const params = new URLSearchParams();
1324
1324
  params.set('mode', options?.mode ?? 'cli');
1325
1325
  for await (const event of this.http.streamSse<PlayLiveEvent>(
1326
- `/api/v2/plays/run/${encodeURIComponent(workflowId)}?${params.toString()}`,
1326
+ `/api/v2/runs/${encodeURIComponent(workflowId)}/tail?${params.toString()}`,
1327
1327
  { signal: options?.signal, headers },
1328
1328
  )) {
1329
1329
  if (event.scope === 'play') {
@@ -1346,7 +1346,7 @@ export class DeeplineClient {
1346
1346
  */
1347
1347
  async cancelPlay(workflowId: string): Promise<void> {
1348
1348
  await this.http.request(
1349
- `/api/v2/plays/run/${encodeURIComponent(workflowId)}/stop`,
1349
+ `/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
1350
1350
  { method: 'POST' },
1351
1351
  );
1352
1352
  }
@@ -1362,7 +1362,7 @@ export class DeeplineClient {
1362
1362
  options?: { reason?: string },
1363
1363
  ): Promise<StopPlayRunResult> {
1364
1364
  return this.http.post<StopPlayRunResult>(
1365
- `/api/v2/plays/run/${encodeURIComponent(workflowId)}/stop`,
1365
+ `/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
1366
1366
  options?.reason ? { reason: options.reason } : {},
1367
1367
  );
1368
1368
  }
@@ -1493,7 +1493,7 @@ export class DeeplineClient {
1493
1493
  runId: string,
1494
1494
  options?: RunsLogsOptions,
1495
1495
  ): Promise<RunsLogsResult> {
1496
- const status = await this.getRunStatus(runId);
1496
+ const status = await this.getRunStatus(runId, { full: true });
1497
1497
  const logs = status.progress?.logs ?? [];
1498
1498
  const limit =
1499
1499
  typeof options?.limit === 'number' && Number.isFinite(options.limit)
@@ -50,10 +50,10 @@ export type SdkRelease = {
50
50
  };
51
51
 
52
52
  export const SDK_RELEASE = {
53
- version: '0.1.80',
53
+ version: '0.1.81',
54
54
  apiContract: '2026-06-dataset-column-cell-stale-hard-cutover',
55
55
  supportPolicy: {
56
- latest: '0.1.80',
56
+ latest: '0.1.81',
57
57
  minimumSupported: '0.1.53',
58
58
  deprecatedBelow: '0.1.53',
59
59
  },
@@ -40,8 +40,8 @@ const LEASE_BLOCK_SIZE = 16;
40
40
  * of a rolled-over window. Discarding stale blocks bounds that to sub-window.
41
41
  */
42
42
  const LEASE_BLOCK_TTL_MS = 250;
43
- /** Cap on how long the backend will park waiting on a saturated window. */
44
- const MAX_ACQUIRE_WAIT_MS = 5_000;
43
+ /** Cap one coordinator-provided sleep hint; total wait is bounded by run timeout. */
44
+ const MAX_ACQUIRE_SLEEP_MS = 5_000;
45
45
 
46
46
  export interface CoordinatorRatePort {
47
47
  /**
@@ -123,7 +123,6 @@ export class CoordinatorRateStateBackend implements RateStateBackend {
123
123
  return noopPacingPermit();
124
124
  }
125
125
 
126
- const waitStartedAt = this.now();
127
126
  while (true) {
128
127
  if (signal?.aborted) {
129
128
  throw signal.reason instanceof Error
@@ -153,13 +152,14 @@ export class CoordinatorRateStateBackend implements RateStateBackend {
153
152
  }
154
153
  return noopPacingPermit();
155
154
  }
156
- // Window saturated. Park for the hint, then re-acquire. Cap total wait so
157
- // a stuck bucket surfaces through the Governor's wall-clock guard instead
158
- // of hanging forever.
159
- if (this.now() - waitStartedAt >= MAX_ACQUIRE_WAIT_MS) {
160
- return noopPacingPermit();
161
- }
162
- const waitMs = Math.max(1, Math.min(response.waitMs, MAX_ACQUIRE_WAIT_MS));
155
+ // Window saturated. Park for the hint, then re-acquire. This is not a
156
+ // degraded coordinator: the limiter answered and said "wait", so granting
157
+ // here would violate the provider request-rate contract. Overall wait is
158
+ // bounded by the play runtime deadline / abort signal.
159
+ const waitMs = Math.max(
160
+ 1,
161
+ Math.min(response.waitMs, MAX_ACQUIRE_SLEEP_MS),
162
+ );
163
163
  await this.sleep(waitMs);
164
164
  }
165
165
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.80",
3
+ "version": "0.1.81",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,149 +0,0 @@
1
- export type ToolBatchItem = {
2
- itemKey: string;
3
- payload: Record<string, unknown>;
4
- inputHash?: string | null;
5
- };
6
-
7
- export type ToolBatchRequest = {
8
- runId: string;
9
- orgId: string;
10
- toolId: string;
11
- operation: string;
12
- provider: string;
13
- items: ToolBatchItem[];
14
- waterfallId?: string | null;
15
- stageId?: string | null;
16
- fieldName?: string | null;
17
- mapName?: string | null;
18
- chunkIndex?: number | null;
19
- userProvidedRateLimitKey?: string | null;
20
- providerBatchSize: number;
21
- };
22
-
23
- export type ToolBatchItemResult = {
24
- itemKey: string;
25
- result: unknown;
26
- cached?: boolean;
27
- };
28
-
29
- export type ToolBatchResult = {
30
- runId: string;
31
- toolId: string;
32
- operation: string;
33
- provider: string;
34
- batchCount: number;
35
- itemCount: number;
36
- results: ToolBatchItemResult[];
37
- };
38
-
39
- export type ToolBatchExecutorTransport = {
40
- executeProviderBatch(input: {
41
- request: ToolBatchRequest;
42
- batchIndex: number;
43
- idempotencyKeys: string[];
44
- rateLimitKey: string;
45
- items: ToolBatchItem[];
46
- }): Promise<ToolBatchItemResult[]>;
47
- };
48
-
49
- export type ToolBatchExecutor = {
50
- executeToolBatch(request: ToolBatchRequest): Promise<ToolBatchResult>;
51
- };
52
-
53
- export function createToolBatchExecutor(
54
- transport: ToolBatchExecutorTransport,
55
- ): ToolBatchExecutor {
56
- return {
57
- async executeToolBatch(request) {
58
- const providerBatchSize = Math.max(
59
- 1,
60
- Math.floor(request.providerBatchSize),
61
- );
62
- const batches = chunkToolBatchItems(request.items, providerBatchSize);
63
- const results: ToolBatchItemResult[] = [];
64
- for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {
65
- const items = batches[batchIndex]!;
66
- results.push(
67
- ...(await transport.executeProviderBatch({
68
- request,
69
- batchIndex,
70
- items,
71
- rateLimitKey: buildToolBatchRateLimitKey(request),
72
- idempotencyKeys: items.map((item) =>
73
- buildToolBatchIdempotencyKey(request, item),
74
- ),
75
- })),
76
- );
77
- }
78
- return {
79
- runId: request.runId,
80
- toolId: request.toolId,
81
- operation: request.operation,
82
- provider: request.provider,
83
- batchCount: batches.length,
84
- itemCount: request.items.length,
85
- results,
86
- };
87
- },
88
- };
89
- }
90
-
91
- export function buildToolBatchIdempotencyKey(
92
- request: ToolBatchRequest,
93
- item: ToolBatchItem,
94
- ): string {
95
- return [
96
- request.runId,
97
- request.mapName ?? '',
98
- request.chunkIndex ?? '',
99
- item.itemKey,
100
- request.fieldName ?? '',
101
- request.waterfallId ?? '',
102
- request.stageId ?? '',
103
- item.inputHash ?? stableToolBatchHash(item.payload),
104
- ].join(':');
105
- }
106
-
107
- export function buildToolBatchRateLimitKey(request: ToolBatchRequest): string {
108
- return [
109
- request.orgId,
110
- request.provider,
111
- request.operation,
112
- request.userProvidedRateLimitKey ?? '',
113
- ].join(':');
114
- }
115
-
116
- function chunkToolBatchItems(
117
- items: readonly ToolBatchItem[],
118
- size: number,
119
- ): ToolBatchItem[][] {
120
- const chunks: ToolBatchItem[][] = [];
121
- for (let index = 0; index < items.length; index += size) {
122
- chunks.push(items.slice(index, index + size));
123
- }
124
- return chunks;
125
- }
126
-
127
- function stableToolBatchHash(value: unknown): string {
128
- const text = stableStringify(value);
129
- let hash = 2166136261;
130
- for (let index = 0; index < text.length; index += 1) {
131
- hash ^= text.charCodeAt(index);
132
- hash = Math.imul(hash, 16777619);
133
- }
134
- return (hash >>> 0).toString(36);
135
- }
136
-
137
- function stableStringify(value: unknown): string {
138
- if (value === null || typeof value !== 'object') {
139
- return JSON.stringify(value);
140
- }
141
- if (Array.isArray(value)) {
142
- return `[${value.map(stableStringify).join(',')}]`;
143
- }
144
- const record = value as Record<string, unknown>;
145
- return `{${Object.keys(record)
146
- .sort()
147
- .map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`)
148
- .join(',')}}`;
149
- }