deepline 0.3.238 → 0.3.240
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/dist/bundling-sources/sdk/src/client.ts +23 -4
- package/dist/bundling-sources/sdk/src/http.ts +10 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/tool-calls.ts +4 -0
- package/dist/bundling-sources/sdk/src/types.ts +2 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/opensosdata/execution-policy.ts +18 -0
- package/dist/bundling-sources/shared_libs/play-runtime/activity-observation.ts +45 -7
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +27 -7
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +8 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +56 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +17 -0
- package/dist/cli/index.js +106 -14
- package/dist/cli/index.mjs +106 -14
- package/dist/index.d.mts +20 -2
- package/dist/index.d.ts +20 -2
- package/dist/index.js +23 -5
- package/dist/index.mjs +23 -5
- package/dist/install-integrity.json +1 -0
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -1806,6 +1806,15 @@ export type TargetBillingStatusResult = {
|
|
|
1806
1806
|
payment_state: string;
|
|
1807
1807
|
recharge_state: string;
|
|
1808
1808
|
billing_email?: string | null;
|
|
1809
|
+
/** Omitted when unavailable; null when no address has been saved. */
|
|
1810
|
+
billing_address?: {
|
|
1811
|
+
line1: string | null;
|
|
1812
|
+
line2: string | null;
|
|
1813
|
+
city: string | null;
|
|
1814
|
+
state: string | null;
|
|
1815
|
+
postal_code: string | null;
|
|
1816
|
+
country: string | null;
|
|
1817
|
+
} | null;
|
|
1809
1818
|
collection_method?: 'charge_automatically' | 'send_invoice';
|
|
1810
1819
|
payment_access_policy?: 'payment_required' | 'net_30' | 'net_60';
|
|
1811
1820
|
plan_invoice?: {
|
|
@@ -2163,7 +2172,9 @@ export type BillingNamespace = {
|
|
|
2163
2172
|
options: TargetBillingPlanTransitionOptions,
|
|
2164
2173
|
) => Promise<TargetBillingMutationResult>;
|
|
2165
2174
|
/** Create a Stripe-hosted billing Portal session. */
|
|
2166
|
-
portalSession: (
|
|
2175
|
+
portalSession: (options?: {
|
|
2176
|
+
flow?: 'customer_update';
|
|
2177
|
+
}) => Promise<{ url: string }>;
|
|
2167
2178
|
};
|
|
2168
2179
|
|
|
2169
2180
|
function requireTargetBillingIdempotencyKey(value: string): string {
|
|
@@ -2713,7 +2724,8 @@ export class DeeplineClient {
|
|
|
2713
2724
|
recoverCreditPurchase: (options) =>
|
|
2714
2725
|
this.recoverTargetBillingCreditPurchase(options),
|
|
2715
2726
|
transitionPlan: (options) => this.transitionTargetBillingPlan(options),
|
|
2716
|
-
portalSession: () =>
|
|
2727
|
+
portalSession: (options) =>
|
|
2728
|
+
this.createTargetBillingPortalSession(options),
|
|
2717
2729
|
};
|
|
2718
2730
|
this.workspaces = {
|
|
2719
2731
|
create: (options) => this.createWorkspace(options),
|
|
@@ -6154,11 +6166,18 @@ export class DeeplineClient {
|
|
|
6154
6166
|
}
|
|
6155
6167
|
|
|
6156
6168
|
/** Create a Stripe-hosted portal session for payment recovery and invoices. */
|
|
6157
|
-
async createTargetBillingPortalSession(
|
|
6169
|
+
async createTargetBillingPortalSession(options?: {
|
|
6170
|
+
flow?: 'customer_update';
|
|
6171
|
+
}): Promise<{ url: string }> {
|
|
6158
6172
|
const response = await this.http.post<{
|
|
6159
6173
|
data: { url: string };
|
|
6160
6174
|
request_id?: string;
|
|
6161
|
-
}>(
|
|
6175
|
+
}>(
|
|
6176
|
+
options?.flow === 'customer_update'
|
|
6177
|
+
? '/api/v2/billing/portal-sessions?flow=customer_update'
|
|
6178
|
+
: '/api/v2/billing/portal-sessions',
|
|
6179
|
+
{},
|
|
6180
|
+
);
|
|
6162
6181
|
return response.data;
|
|
6163
6182
|
}
|
|
6164
6183
|
|
|
@@ -395,6 +395,11 @@ export class HttpClient {
|
|
|
395
395
|
let fetchAttempts = 0;
|
|
396
396
|
let lastRequestUrl = url;
|
|
397
397
|
let networkFailedAt: number | undefined;
|
|
398
|
+
let networkPhase:
|
|
399
|
+
| 'before_request'
|
|
400
|
+
| 'retry_wait'
|
|
401
|
+
| 'awaiting_headers'
|
|
402
|
+
| 'reading_body' = 'before_request';
|
|
398
403
|
|
|
399
404
|
const headers = this.authHeaders(options?.headers);
|
|
400
405
|
|
|
@@ -423,6 +428,7 @@ export class HttpClient {
|
|
|
423
428
|
? backoffMs
|
|
424
429
|
: Math.max(backoffMs, retryAfterDelayMs);
|
|
425
430
|
retryAfterDelayMs = null;
|
|
431
|
+
networkPhase = 'retry_wait';
|
|
426
432
|
try {
|
|
427
433
|
await sleep(delayMs, options?.signal);
|
|
428
434
|
} catch (error) {
|
|
@@ -450,6 +456,7 @@ export class HttpClient {
|
|
|
450
456
|
once: true,
|
|
451
457
|
});
|
|
452
458
|
|
|
459
|
+
networkPhase = 'before_request';
|
|
453
460
|
try {
|
|
454
461
|
const requestBody =
|
|
455
462
|
options?.formData !== undefined
|
|
@@ -461,6 +468,7 @@ export class HttpClient {
|
|
|
461
468
|
: undefined;
|
|
462
469
|
fetchAttempts += 1;
|
|
463
470
|
lastRequestUrl = candidateUrl;
|
|
471
|
+
networkPhase = 'awaiting_headers';
|
|
464
472
|
const response = await fetch(candidateUrl, {
|
|
465
473
|
method,
|
|
466
474
|
headers,
|
|
@@ -468,6 +476,7 @@ export class HttpClient {
|
|
|
468
476
|
signal: controller.signal,
|
|
469
477
|
});
|
|
470
478
|
|
|
479
|
+
networkPhase = 'reading_body';
|
|
471
480
|
options?.onResponse?.(response);
|
|
472
481
|
if (response.status === 404 && options?.allowNotFound) {
|
|
473
482
|
clearTimeout(timeoutId);
|
|
@@ -671,6 +680,7 @@ export class HttpClient {
|
|
|
671
680
|
// Elapsed time covers the entire logical request, including retries.
|
|
672
681
|
elapsedMs: Math.max(0, failedAt - requestStartedAt),
|
|
673
682
|
attempts: fetchAttempts,
|
|
683
|
+
phase: networkPhase,
|
|
674
684
|
},
|
|
675
685
|
};
|
|
676
686
|
if (options?.toolId) {
|
|
@@ -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.
|
|
203
|
+
version: '0.3.240',
|
|
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: {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OPENSOSDATA_LOOKUP_CLIENT_TIMEOUT_MS } from '../../shared_libs/integration-contracts/opensosdata/execution-policy.js';
|
|
1
2
|
import type { ToolResultBilling } from '../../shared_libs/plays/tool-result-types.js';
|
|
2
3
|
import { resolveTheirstackClientTimeoutMs } from '../../shared_libs/integration-contracts/theirstack/execution-policy.js';
|
|
3
4
|
import { resolveWaterfallClientTimeoutMs } from '../../shared_libs/integration-contracts/waterfall/execution-policy.js';
|
|
@@ -172,6 +173,9 @@ function resolveToolExecuteTimeoutMs(
|
|
|
172
173
|
input: Record<string, unknown>,
|
|
173
174
|
): number | undefined {
|
|
174
175
|
const normalized = toolId.trim().toLowerCase();
|
|
176
|
+
if (normalized === 'opensosdata_business_lookup') {
|
|
177
|
+
return OPENSOSDATA_LOOKUP_CLIENT_TIMEOUT_MS;
|
|
178
|
+
}
|
|
175
179
|
if (normalized === 'apify_run_actor_sync') {
|
|
176
180
|
const requestedTimeoutMs = input.timeoutMs ?? APIFY_SYNC_DEFAULT_TIMEOUT_MS;
|
|
177
181
|
if (
|
|
@@ -228,6 +228,8 @@ export interface ToolDefinition extends ToolExecutionMetadataFields {
|
|
|
228
228
|
outputSchema?: Record<string, unknown>;
|
|
229
229
|
/** User-facing pricing summary. Internal provider/settlement costs are intentionally omitted. */
|
|
230
230
|
pricing?: ToolPricingSummary | null;
|
|
231
|
+
/** How to use the tool well: the provider's summary and the tool's own notes. */
|
|
232
|
+
guidance?: { provider?: string; tool?: string };
|
|
231
233
|
/** Copyable play-runtime guidance for V2 tool execution results. */
|
|
232
234
|
usageGuidance?: {
|
|
233
235
|
execute?: string;
|
package/dist/bundling-sources/shared_libs/integration-contracts/opensosdata/execution-policy.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** OpenSOSData's single-entity lookup can complete synchronously or poll a 202 job. */
|
|
2
|
+
export const OPENSOSDATA_LOOKUP_REQUEST_TIMEOUT_MS = 120_000;
|
|
3
|
+
export const OPENSOSDATA_POLL_INTERVAL_MS = 3_000;
|
|
4
|
+
export const OPENSOSDATA_POLL_TIMEOUT_MS = 90_000;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Preserve the provider's existing request and polling windows. A final poll
|
|
8
|
+
* can begin just before the poll window ends, so include that in-flight request
|
|
9
|
+
* as well as route/admission and response overhead. Explicit caller deadlines
|
|
10
|
+
* still take precedence; unrelated tools retain their existing budgets.
|
|
11
|
+
*/
|
|
12
|
+
export const OPENSOSDATA_LOOKUP_CLIENT_TIMEOUT_MS =
|
|
13
|
+
60_000 +
|
|
14
|
+
OPENSOSDATA_LOOKUP_REQUEST_TIMEOUT_MS +
|
|
15
|
+
OPENSOSDATA_POLL_TIMEOUT_MS +
|
|
16
|
+
OPENSOSDATA_POLL_INTERVAL_MS +
|
|
17
|
+
OPENSOSDATA_LOOKUP_REQUEST_TIMEOUT_MS +
|
|
18
|
+
15_000;
|
|
@@ -263,10 +263,40 @@ function targetLabel(target: PlayActivityTarget): string {
|
|
|
263
263
|
case 'step':
|
|
264
264
|
return target.label ?? target.stepId;
|
|
265
265
|
case 'capacity':
|
|
266
|
-
return target.
|
|
266
|
+
return target.pool === 'provider'
|
|
267
|
+
? providerCapacityLabel(target.label)
|
|
268
|
+
: (target.label ?? `${target.pool} capacity`);
|
|
267
269
|
}
|
|
268
270
|
}
|
|
269
271
|
|
|
272
|
+
/** Older waits carried a rate scope rather than a customer-facing provider. */
|
|
273
|
+
export function providerCapacityLabel(label?: string): string {
|
|
274
|
+
if (!label) return 'The provider';
|
|
275
|
+
if (label.startsWith('org:')) return label.split(':')[1] || 'The provider';
|
|
276
|
+
return label.includes(':') ? 'The provider' : label;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function publicProviderCapacityObservation(
|
|
280
|
+
observation: PlayActivityObservation,
|
|
281
|
+
): PlayActivityObservation {
|
|
282
|
+
if (
|
|
283
|
+
observation.target.kind !== 'capacity' ||
|
|
284
|
+
observation.target.pool !== 'provider'
|
|
285
|
+
)
|
|
286
|
+
return observation;
|
|
287
|
+
if (
|
|
288
|
+
!observation.target.label?.includes(':') &&
|
|
289
|
+
!observation.activityId.startsWith('capacity:provider:org:')
|
|
290
|
+
)
|
|
291
|
+
return observation;
|
|
292
|
+
const label = providerCapacityLabel(observation.target.label);
|
|
293
|
+
return {
|
|
294
|
+
...observation,
|
|
295
|
+
activityId: `capacity:provider:${label}`,
|
|
296
|
+
target: { ...observation.target, label },
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
270
300
|
export function summarizePlayActivity(
|
|
271
301
|
observation: PlayActivityObservation,
|
|
272
302
|
): string {
|
|
@@ -297,10 +327,10 @@ export function summarizePlayActivity(
|
|
|
297
327
|
if (state.reason.kind === 'lease') {
|
|
298
328
|
return `Contended: waiting for ${state.reason.resourceKind} lease ${state.reason.resourceLabel}.`;
|
|
299
329
|
}
|
|
300
|
-
return `
|
|
330
|
+
return `Waiting: ${label}.`;
|
|
301
331
|
case 'retrying':
|
|
302
332
|
if (state.reason === 'rate_limit') {
|
|
303
|
-
return `Waiting for ${label}
|
|
333
|
+
return `Waiting for ${label}'s rate limit to allow more calls. Completed work is saved; remaining calls will continue automatically.`;
|
|
304
334
|
}
|
|
305
335
|
return `Delayed: ${label} will retry automatically.`;
|
|
306
336
|
case 'scheduled':
|
|
@@ -385,6 +415,7 @@ export function projectPlayRunActivity(input: {
|
|
|
385
415
|
status: string;
|
|
386
416
|
updatedAt?: number | null;
|
|
387
417
|
waitKind?: string | null;
|
|
418
|
+
waitBoundaryId?: string | null;
|
|
388
419
|
waitUntil?: number | null;
|
|
389
420
|
eventKey?: string | null;
|
|
390
421
|
runtimeBackend?: string | null;
|
|
@@ -410,17 +441,24 @@ export function projectPlayRunActivity(input: {
|
|
|
410
441
|
const latestExplicit = [...(input.explicit ?? [])]
|
|
411
442
|
.filter((candidate) => !isTerminalActivityState(candidate.state))
|
|
412
443
|
.sort((left, right) => right.observedAt - left.observedAt)[0];
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
444
|
+
// Retry-After is the earliest retry, not evidence that execution resumed.
|
|
445
|
+
// Retain the reason while its provider boundary is still waiting, including
|
|
446
|
+
// lagging readers with no wait projection. A different durable wait wins.
|
|
447
|
+
const stillWaitingForProvider =
|
|
448
|
+
normalizedStatus === 'waiting' &&
|
|
449
|
+
(!input.waitKind ||
|
|
450
|
+
(input.waitKind === 'sleep' &&
|
|
451
|
+
input.waitBoundaryId?.includes(':provider-backpressure-') === true));
|
|
416
452
|
const explicit =
|
|
453
|
+
!stillWaitingForProvider &&
|
|
417
454
|
latestExplicit?.target.kind === 'capacity' &&
|
|
418
455
|
latestExplicit.target.pool === 'provider' &&
|
|
419
456
|
latestExplicit.state.kind === 'retrying' &&
|
|
420
457
|
latestExplicit.state.retryAt < now
|
|
421
458
|
? null
|
|
422
459
|
: latestExplicit;
|
|
423
|
-
if (explicit)
|
|
460
|
+
if (explicit)
|
|
461
|
+
return projection(publicProviderCapacityObservation(explicit), now);
|
|
424
462
|
|
|
425
463
|
if (input.waitKind === 'detached_runner') {
|
|
426
464
|
return projection(
|
|
@@ -57,6 +57,7 @@ import type {
|
|
|
57
57
|
} from './governor/rate-state-backend';
|
|
58
58
|
import type { MapRowOutcome } from './durability-store';
|
|
59
59
|
import { stringifyPostgresJson } from './postgres-json';
|
|
60
|
+
import { providerCapacityLabel } from './activity-observation';
|
|
60
61
|
import { RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE } from './runtime-sheet-row-transition';
|
|
61
62
|
import {
|
|
62
63
|
RuntimeSheetRowWriter,
|
|
@@ -204,7 +205,7 @@ import {
|
|
|
204
205
|
TOOL_EXECUTE_RUNNER_ACCEPTS_VALUE,
|
|
205
206
|
TOOL_EXECUTE_PROVIDER_RATE_SCOPE_HEADER,
|
|
206
207
|
TOOL_EXECUTE_PROVIDER_RATE_RETRY_SNAPSHOT_HEADER,
|
|
207
|
-
|
|
208
|
+
isAttestedProvider429Response,
|
|
208
209
|
classifyToolExecuteHttpFailure,
|
|
209
210
|
createToolExecuteHttpFailureAttemptTracker,
|
|
210
211
|
parseToolExecuteRetryAfterMs,
|
|
@@ -9143,6 +9144,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9143
9144
|
|
|
9144
9145
|
successfulCount = Math.max(0, successfulCount - staleCompletedKeys.size);
|
|
9145
9146
|
failedCount = Math.max(0, failedCount - staleFailedKeys.size);
|
|
9147
|
+
this.#options.onMapRowsSettled?.({
|
|
9148
|
+
playName: this.#options.playName,
|
|
9149
|
+
runId: this.#options.runId,
|
|
9150
|
+
tableNamespace: resolvedTableNamespace,
|
|
9151
|
+
succeededRows: successfulCount,
|
|
9152
|
+
failedRows: failedCount,
|
|
9153
|
+
});
|
|
9146
9154
|
|
|
9147
9155
|
// Isolated failures are a partial result only when at least one admitted
|
|
9148
9156
|
// row completed. A fully failed admission run is systemic: preserve the
|
|
@@ -9995,6 +10003,15 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9995
10003
|
});
|
|
9996
10004
|
}
|
|
9997
10005
|
|
|
10006
|
+
this.#options.onMapRowsSettled?.({
|
|
10007
|
+
playName: this.#options.playName,
|
|
10008
|
+
runId: this.#options.runId,
|
|
10009
|
+
tableNamespace: resolvedTableNamespace,
|
|
10010
|
+
succeededRows:
|
|
10011
|
+
previouslyCompletedRowKeys.length + visibleCompletedRows.length,
|
|
10012
|
+
failedRows: durableFailedRows,
|
|
10013
|
+
});
|
|
10014
|
+
|
|
9998
10015
|
// This map's terminal rows have already crossed the persistence barrier
|
|
9999
10016
|
// above. Keep that verified snapshot as the authored return value instead
|
|
10000
10017
|
// of immediately re-reading the Runtime Sheet projection. A second read
|
|
@@ -14532,11 +14549,12 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
14532
14549
|
retryAtMs: number,
|
|
14533
14550
|
): void {
|
|
14534
14551
|
const observedAt = Date.now();
|
|
14552
|
+
const label = providerCapacityLabel(provider);
|
|
14535
14553
|
this.emitExecutionEvent({
|
|
14536
14554
|
type: 'activity.observed',
|
|
14537
14555
|
observation: {
|
|
14538
|
-
activityId: `capacity:provider:${
|
|
14539
|
-
target: { kind: 'capacity', pool: 'provider', label
|
|
14556
|
+
activityId: `capacity:provider:${label}`,
|
|
14557
|
+
target: { kind: 'capacity', pool: 'provider', label },
|
|
14540
14558
|
state: {
|
|
14541
14559
|
kind: 'retrying',
|
|
14542
14560
|
reason: 'rate_limit',
|
|
@@ -19546,12 +19564,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19546
19564
|
: undefined;
|
|
19547
19565
|
}
|
|
19548
19566
|
if (
|
|
19549
|
-
dispatchedResponse
|
|
19550
|
-
dispatchedResponse.headers.get(
|
|
19551
|
-
TOOL_EXECUTE_PROVIDER_THROTTLE_HEADER,
|
|
19552
|
-
) === '1'
|
|
19567
|
+
isAttestedProvider429Response(dispatchedResponse)
|
|
19553
19568
|
) {
|
|
19554
19569
|
this.resourceGovernor.recordProvider429();
|
|
19570
|
+
}
|
|
19571
|
+
if (
|
|
19572
|
+
dispatchedResponse.status === 429 &&
|
|
19573
|
+
isAttestedProvider429Response(dispatchedResponse)
|
|
19574
|
+
) {
|
|
19555
19575
|
provider429RetryDiagnosticStartedAt =
|
|
19556
19576
|
performance.now();
|
|
19557
19577
|
provider429RetryDiagnosticNextInvocationAttempt =
|
|
@@ -931,6 +931,14 @@ export interface ContextOptions {
|
|
|
931
931
|
*/
|
|
932
932
|
supersededKeys?: string[];
|
|
933
933
|
}>;
|
|
934
|
+
/** Distinct terminal rows after the map's persistence barrier, across resumes. */
|
|
935
|
+
onMapRowsSettled?: (input: {
|
|
936
|
+
playName?: string;
|
|
937
|
+
runId?: string;
|
|
938
|
+
tableNamespace: string;
|
|
939
|
+
succeededRows: number;
|
|
940
|
+
failedRows: number;
|
|
941
|
+
}) => void;
|
|
934
942
|
/**
|
|
935
943
|
* Persists coalesced, non-terminal row patches before a map suspends.
|
|
936
944
|
* Terminal rows use onMapRowsCompleted; this narrow seam only preserves
|
|
@@ -328,6 +328,7 @@ export function buildPlayRunStatusSnapshot(input: {
|
|
|
328
328
|
status: projectedSnapshot.status,
|
|
329
329
|
updatedAt: projectedSnapshot.updatedAt,
|
|
330
330
|
waitKind: input.run.waitKind ?? input.run.wait?.kind ?? null,
|
|
331
|
+
waitBoundaryId: input.run.wait?.boundaryId ?? input.run.activeBoundaryId,
|
|
331
332
|
waitUntil: input.run.waitUntil,
|
|
332
333
|
eventKey: input.run.wait?.eventKey ?? null,
|
|
333
334
|
runtimeBackend: input.run.runtimeBackend,
|
|
@@ -496,6 +496,20 @@ export function runtimeSheetTerminalWriteCounts(input: {
|
|
|
496
496
|
};
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
/** Distinct settled counts include saved siblings, never skipped input duplicates. */
|
|
500
|
+
export function runtimeSheetTerminalMapCounts(
|
|
501
|
+
current: { persistedRows: number; succeededRows: number; failedRows: number },
|
|
502
|
+
map: { succeededRows: number; failedRows: number },
|
|
503
|
+
): { persistedRows: number; succeededRows: number; failedRows: number } {
|
|
504
|
+
const succeededRows = Math.max(current.succeededRows, map.succeededRows);
|
|
505
|
+
const failedRows = Math.max(current.failedRows, map.failedRows);
|
|
506
|
+
return {
|
|
507
|
+
persistedRows: Math.max(current.persistedRows, succeededRows + failedRows),
|
|
508
|
+
succeededRows,
|
|
509
|
+
failedRows,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
499
513
|
async function vercelBypassHeaders(
|
|
500
514
|
config: PlayRunnerExecutionConfig,
|
|
501
515
|
): Promise<Record<string, string>> {
|
|
@@ -2308,6 +2322,35 @@ async function run(
|
|
|
2308
2322
|
const MAP_ROW_UPDATED_EMIT_INTERVAL_MS = 200;
|
|
2309
2323
|
const MAP_ROW_UPDATED_EMIT_SAMPLE_RATE = 100;
|
|
2310
2324
|
return (event: PlayExecutionEvent) => {
|
|
2325
|
+
if (event.type === 'map.suspended') {
|
|
2326
|
+
const datasetId = createRuntimeDatasetId(
|
|
2327
|
+
config.context.playName!,
|
|
2328
|
+
event.artifactTableNamespace,
|
|
2329
|
+
);
|
|
2330
|
+
const settlement = runtimeMapDatasetSettlements.get(datasetId);
|
|
2331
|
+
if (settlement) {
|
|
2332
|
+
// This event follows the map writer's durability barrier. Only
|
|
2333
|
+
// report accepted writes, not progress (which includes duplicates).
|
|
2334
|
+
emitRunnerEvent(
|
|
2335
|
+
{
|
|
2336
|
+
type: 'execution_event',
|
|
2337
|
+
event: {
|
|
2338
|
+
type: 'dataset.lifecycle',
|
|
2339
|
+
datasetId,
|
|
2340
|
+
path: settlement.path,
|
|
2341
|
+
tableNamespace: settlement.tableNamespace,
|
|
2342
|
+
phase: 'registered',
|
|
2343
|
+
persistedRows: settlement.persistedRows,
|
|
2344
|
+
succeededRows: settlement.succeededRows,
|
|
2345
|
+
failedRows: settlement.failedRows,
|
|
2346
|
+
complete: false,
|
|
2347
|
+
at: event.at,
|
|
2348
|
+
},
|
|
2349
|
+
},
|
|
2350
|
+
options,
|
|
2351
|
+
);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2311
2354
|
if (event.type === 'map.row.updated') {
|
|
2312
2355
|
mapRowUpdatedCount++;
|
|
2313
2356
|
const now = Date.now();
|
|
@@ -2638,6 +2681,19 @@ async function run(
|
|
|
2638
2681
|
),
|
|
2639
2682
|
});
|
|
2640
2683
|
},
|
|
2684
|
+
onMapRowsSettled: (input) => {
|
|
2685
|
+
const datasetId = createRuntimeDatasetId(
|
|
2686
|
+
input.playName ?? config.context.playName!,
|
|
2687
|
+
input.tableNamespace,
|
|
2688
|
+
);
|
|
2689
|
+
const settlement = runtimeMapDatasetSettlements.get(datasetId);
|
|
2690
|
+
if (settlement && (!input.runId || settlement.runId === input.runId)) {
|
|
2691
|
+
Object.assign(
|
|
2692
|
+
settlement,
|
|
2693
|
+
runtimeSheetTerminalMapCounts(settlement, input),
|
|
2694
|
+
);
|
|
2695
|
+
}
|
|
2696
|
+
},
|
|
2641
2697
|
onMapRowsCompleted: async (input) => {
|
|
2642
2698
|
// Persist executed rows (data + cell meta) into the tenant sheet —
|
|
2643
2699
|
// the sheet is the source of truth for dataset state, and the
|
|
@@ -86,6 +86,23 @@ export const TOOL_EXECUTE_PROVIDER_THROTTLE_HEADER =
|
|
|
86
86
|
'x-deepline-provider-throttle';
|
|
87
87
|
export const TOOL_EXECUTE_PROVIDER_PACING_WAIT_CODE = 'PROVIDER_PACING_WAIT';
|
|
88
88
|
|
|
89
|
+
/** A trusted provider 429 remains observable if the gateway cannot commit its body. */
|
|
90
|
+
export function isAttestedProvider429Response(response: {
|
|
91
|
+
status: number;
|
|
92
|
+
headers: Pick<Headers, 'get'>;
|
|
93
|
+
}): boolean {
|
|
94
|
+
if (response.headers.get(TOOL_EXECUTE_PROVIDER_THROTTLE_HEADER) !== '1') {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (response.status === 429) return true;
|
|
98
|
+
const code = response.headers.get('x-deepline-error-code');
|
|
99
|
+
return (
|
|
100
|
+
response.status === 409 &&
|
|
101
|
+
(code === 'durable_invocation_outcome_unknown' ||
|
|
102
|
+
code === 'durable_invocation_commit_failed')
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
89
106
|
/**
|
|
90
107
|
* Parse the advertisement as a comma-separated token list so a later runner can
|
|
91
108
|
* add a capability without a second header. An absent or unparsable value means
|