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.
- package/README.md +2 -1
- package/dist/cli/index.js +10 -13
- package/dist/cli/index.mjs +10 -13
- package/dist/index.js +8 -8
- package/dist/index.mjs +8 -8
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +1 -1
- package/dist/repo/apps/play-runner-workers/src/entry.ts +258 -250
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-http-errors.ts +43 -1
- package/dist/repo/sdk/src/client.ts +6 -6
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +10 -10
- package/package.json +1 -1
- package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +0 -149
|
@@ -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}: ${
|
|
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/
|
|
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(
|
|
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/
|
|
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/
|
|
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/
|
|
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.
|
|
53
|
+
version: '0.1.81',
|
|
54
54
|
apiContract: '2026-06-dataset-column-cell-stale-hard-cutover',
|
|
55
55
|
supportPolicy: {
|
|
56
|
-
latest: '0.1.
|
|
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
|
|
44
|
-
const
|
|
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.
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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,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
|
-
}
|