deepline 0.3.74 → 0.3.75
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 +279 -21
- package/dist/bundling-sources/sdk/src/config.ts +21 -3
- package/dist/bundling-sources/sdk/src/index.ts +1 -0
- package/dist/bundling-sources/sdk/src/play.ts +3 -6
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +3 -2
- package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +186 -0
- package/dist/bundling-sources/shared_libs/monitors/monitor-fleet-limits.ts +41 -0
- package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +213 -55
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +172 -299
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +13 -32
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -1
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +7 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +11 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-incident-drills.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/native-batch.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/testkit.ts +5 -4
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +12 -2
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/deployment-status.ts +74 -0
- package/dist/cli/index.js +918 -167
- package/dist/cli/index.mjs +918 -167
- package/dist/{compiler-manifest-CMNgA_JQ.d.mts → compiler-manifest-Dbov16F7.d.mts} +1 -1
- package/dist/{compiler-manifest-CMNgA_JQ.d.ts → compiler-manifest-Dbov16F7.d.ts} +1 -1
- package/dist/index.d.mts +176 -23
- package/dist/index.d.ts +176 -23
- package/dist/index.js +109 -12
- package/dist/index.mjs +109 -12
- package/dist/install-integrity.json +4 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/package.json +1 -1
|
@@ -175,7 +175,7 @@ import {
|
|
|
175
175
|
buildDurableToolCallCacheKey,
|
|
176
176
|
buildLegacyRevisionedDurableToolCallCacheKey,
|
|
177
177
|
buildDurableToolPayloadProviderIdempotencyKey,
|
|
178
|
-
|
|
178
|
+
buildProviderOperationIdempotencyKey,
|
|
179
179
|
buildDurableToolReceiptPrefix,
|
|
180
180
|
resolveDurableCallCachePolicy,
|
|
181
181
|
} from './durable-call-cache';
|
|
@@ -219,11 +219,7 @@ import {
|
|
|
219
219
|
type DurableReceiptExecutionStore,
|
|
220
220
|
} from './durable-receipt-execution';
|
|
221
221
|
import {
|
|
222
|
-
asyncOperationDurableStartInput,
|
|
223
222
|
asyncOperationShouldWait,
|
|
224
|
-
classifyAsyncOperationResult,
|
|
225
|
-
executeAsyncOperationLifecycle,
|
|
226
|
-
resolveAsyncOperationPolling,
|
|
227
223
|
type AsyncOperationContractWire,
|
|
228
224
|
} from './async-operation';
|
|
229
225
|
import {
|
|
@@ -1248,27 +1244,6 @@ function publicToolResponseEnvelope(value: unknown): {
|
|
|
1248
1244
|
};
|
|
1249
1245
|
}
|
|
1250
1246
|
|
|
1251
|
-
function materializedAsyncToolResponse(
|
|
1252
|
-
response: ParsedToolExecuteResponse['toolResponse'] | undefined,
|
|
1253
|
-
result: unknown,
|
|
1254
|
-
): ParsedToolExecuteResponse['toolResponse'] {
|
|
1255
|
-
const hasRawV2 =
|
|
1256
|
-
response !== undefined &&
|
|
1257
|
-
Object.prototype.hasOwnProperty.call(response, 'rawV2');
|
|
1258
|
-
const materializedRawV2 =
|
|
1259
|
-
response?.view === 'data'
|
|
1260
|
-
? {
|
|
1261
|
-
...(recordOrNull(response.rawV2) ?? {}),
|
|
1262
|
-
data: result,
|
|
1263
|
-
}
|
|
1264
|
-
: result;
|
|
1265
|
-
return {
|
|
1266
|
-
...(response ?? {}),
|
|
1267
|
-
raw: result,
|
|
1268
|
-
...(hasRawV2 ? { rawV2: materializedRawV2 } : {}),
|
|
1269
|
-
};
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
1247
|
/**
|
|
1273
1248
|
* A batched provider request returns one envelope for several logical source
|
|
1274
1249
|
* tool calls. Each source call persists only its own item-shaped canonical
|
|
@@ -1398,13 +1373,11 @@ type ToolExecutionApiOptions = {
|
|
|
1398
1373
|
/** The receipt key is a completed-result cache for this read-only call. */
|
|
1399
1374
|
completedResultCache?: boolean;
|
|
1400
1375
|
executionAuthScopeDigest?: string | null;
|
|
1401
|
-
/**
|
|
1402
|
-
* Historical receipt identity used for the API's provider/billing
|
|
1403
|
-
* idempotency receipt. This can differ from the worker-owned durable cache
|
|
1404
|
-
* receipt while a response contract migrates.
|
|
1405
|
-
*/
|
|
1406
|
-
providerIdempotencyReceiptKey?: string | null;
|
|
1407
1376
|
providerIdempotencyKey?: string | null;
|
|
1377
|
+
/** Exact forced-member identities that participate in a native batch key. */
|
|
1378
|
+
providerOperationForceRefreshIdentities?: readonly string[];
|
|
1379
|
+
/** Presentation-only cache identity paired with a separate execution fence. */
|
|
1380
|
+
providerIdempotencyReceiptKey?: string | null;
|
|
1408
1381
|
receiptLeaseExpiresAt?: string | null;
|
|
1409
1382
|
beforeProviderCall?: () => Promise<void> | void;
|
|
1410
1383
|
heartbeatReceipt?: () => Promise<void> | void;
|
|
@@ -1429,6 +1402,13 @@ type ToolExecutionApiOptions = {
|
|
|
1429
1402
|
};
|
|
1430
1403
|
/** Internal recursion guard for lifecycle poll/finish calls. */
|
|
1431
1404
|
skipAsyncOperationResolution?: boolean;
|
|
1405
|
+
/**
|
|
1406
|
+
* A status/result request belonging to a live async lifecycle. It must not
|
|
1407
|
+
* create a result receipt or provider idempotency identity from a parent
|
|
1408
|
+
* cache entry: the job handle is process-local, while the outer tool-call
|
|
1409
|
+
* cache stores only its terminal materialized output.
|
|
1410
|
+
*/
|
|
1411
|
+
uncachedAsyncLifecycleCall?: boolean;
|
|
1432
1412
|
};
|
|
1433
1413
|
const IN_MEMORY_STEP_RESULT_PREVIEW_LIMIT = 25;
|
|
1434
1414
|
/**
|
|
@@ -2109,10 +2089,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
2109
2089
|
string,
|
|
2110
2090
|
{ resolve: (value: unknown) => void; reject: (reason: unknown) => void }
|
|
2111
2091
|
>();
|
|
2112
|
-
private readonly asyncOperationCapacity = new Map<
|
|
2113
|
-
string,
|
|
2114
|
-
{ active: number; waiters: Array<() => void> }
|
|
2115
|
-
>();
|
|
2116
2092
|
#options: ContextOptions;
|
|
2117
2093
|
private readonly rootRuntimeContract: PlayArtifactRuntimeContract;
|
|
2118
2094
|
private readonly executionScope: RunExecutionScope;
|
|
@@ -2160,6 +2136,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
2160
2136
|
boundaryId: string;
|
|
2161
2137
|
eventKey: string;
|
|
2162
2138
|
timeoutMs: number;
|
|
2139
|
+
messageRef?: { channel: string; ts: string };
|
|
2163
2140
|
}> = [];
|
|
2164
2141
|
private processedRowCount = 0;
|
|
2165
2142
|
private sleepBoundaryIndex = 0;
|
|
@@ -9388,9 +9365,18 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9388
9365
|
executionAuthScopeDigest,
|
|
9389
9366
|
staleAfterSeconds: toolCachePolicy.staleAfterSeconds,
|
|
9390
9367
|
});
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9368
|
+
const providerActionVersion =
|
|
9369
|
+
(await this.#options.getToolActionCacheVersion?.(toolId))?.trim() ?? '';
|
|
9370
|
+
// A provider operation is keyed by its requested semantic payload. The
|
|
9371
|
+
// durable receipt below remains a completed-result cache only.
|
|
9372
|
+
let providerIdempotencyKeyBase =
|
|
9373
|
+
buildDurableToolPayloadProviderIdempotencyKey({
|
|
9374
|
+
orgId: this.#options.orgId,
|
|
9375
|
+
toolId,
|
|
9376
|
+
executionAuthScopeDigest,
|
|
9377
|
+
providerActionVersion,
|
|
9378
|
+
payload: input,
|
|
9379
|
+
});
|
|
9394
9380
|
let directResultReceiptKey = durableCacheKey;
|
|
9395
9381
|
// A raw-v2 artifact must never read an older receipt that cannot render
|
|
9396
9382
|
// raw-v2. If both the primary and its revisioned recovery receipt are
|
|
@@ -9670,17 +9656,16 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9670
9656
|
...(toolRetryPolicy?.requiresExecutionFence === true
|
|
9671
9657
|
? {
|
|
9672
9658
|
providerIdempotencyReceiptKey:
|
|
9673
|
-
cacheableToolResult &&
|
|
9674
|
-
?
|
|
9659
|
+
cacheableToolResult && resultReceiptKey
|
|
9660
|
+
? resultReceiptKey
|
|
9675
9661
|
: physicalDirectKey,
|
|
9676
9662
|
providerIdempotencyKey:
|
|
9677
9663
|
this.providerIdempotencyKeyForToolCall({
|
|
9678
|
-
|
|
9664
|
+
operationKey:
|
|
9679
9665
|
useDirectResultReceipts && operationKey
|
|
9680
9666
|
? providerIdempotencyKeyBase
|
|
9681
9667
|
: physicalDirectKey,
|
|
9682
9668
|
force: cacheableToolResult && toolCachePolicy.force,
|
|
9683
|
-
leaseId: directReceiptLeaseId,
|
|
9684
9669
|
logicalCallId,
|
|
9685
9670
|
}),
|
|
9686
9671
|
}
|
|
@@ -9762,9 +9747,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9762
9747
|
dispatcher,
|
|
9763
9748
|
})
|
|
9764
9749
|
: null;
|
|
9765
|
-
const providerActionVersion =
|
|
9766
|
-
(await this.#options.getToolActionCacheVersion?.(toolId))?.trim() ??
|
|
9767
|
-
'';
|
|
9768
9750
|
const call: Omit<ToolCallInput, 'compatibility'> = {
|
|
9769
9751
|
scope: {
|
|
9770
9752
|
organizationId: this.#options.orgId ?? 'unknown-org',
|
|
@@ -9993,7 +9975,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9993
9975
|
executionAuthScopeDigest,
|
|
9994
9976
|
staleAfterSeconds: toolCachePolicy.staleAfterSeconds,
|
|
9995
9977
|
});
|
|
9996
|
-
providerIdempotencyKeyBase =
|
|
9978
|
+
providerIdempotencyKeyBase =
|
|
9979
|
+
buildDurableToolPayloadProviderIdempotencyKey({
|
|
9980
|
+
orgId: this.#options.orgId,
|
|
9981
|
+
toolId,
|
|
9982
|
+
executionAuthScopeDigest,
|
|
9983
|
+
providerActionVersion,
|
|
9984
|
+
payload: input,
|
|
9985
|
+
});
|
|
9997
9986
|
directResultReceiptKey = durableCacheKey;
|
|
9998
9987
|
bypassDirectResultCache = false;
|
|
9999
9988
|
checkpointCacheKeys.splice(
|
|
@@ -10048,6 +10037,21 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
10048
10037
|
const existing =
|
|
10049
10038
|
this.checkpoint.resolvedBoundaries?.[preparedBoundary.boundaryId];
|
|
10050
10039
|
if (existing?.kind === 'integration_event' && 'output' in existing) {
|
|
10040
|
+
const output = recordOrNull(existing.output);
|
|
10041
|
+
if (output?.timed_out === true) {
|
|
10042
|
+
await handler.onTimeout?.({
|
|
10043
|
+
payload: input,
|
|
10044
|
+
context: eventContext,
|
|
10045
|
+
boundary: {
|
|
10046
|
+
boundaryId: preparedBoundary.boundaryId,
|
|
10047
|
+
eventKey: preparedBoundary.eventKey,
|
|
10048
|
+
timeoutMs: preparedBoundary.timeoutMs,
|
|
10049
|
+
provider: existing.provider ?? handler.provider,
|
|
10050
|
+
toolId: existing.toolId ?? handler.toolId,
|
|
10051
|
+
...(existing.messageRef ? { messageRef: existing.messageRef } : {}),
|
|
10052
|
+
},
|
|
10053
|
+
});
|
|
10054
|
+
}
|
|
10051
10055
|
this.runtimeLog(
|
|
10052
10056
|
`Integration event ${preparedBoundary.boundaryId}: recovered response from checkpoint`,
|
|
10053
10057
|
);
|
|
@@ -10103,6 +10107,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
10103
10107
|
boundaryId: boundary.boundaryId,
|
|
10104
10108
|
eventKey: boundary.eventKey,
|
|
10105
10109
|
timeoutMs: boundary.timeoutMs,
|
|
10110
|
+
...(boundary.messageRef ? { messageRef: boundary.messageRef } : {}),
|
|
10106
10111
|
});
|
|
10107
10112
|
}
|
|
10108
10113
|
|
|
@@ -10111,6 +10116,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
10111
10116
|
boundaryId: boundary.boundaryId,
|
|
10112
10117
|
eventKey: boundary.eventKey,
|
|
10113
10118
|
timeoutMs: boundary.timeoutMs,
|
|
10119
|
+
...(boundary.messageRef ? { messageRef: boundary.messageRef } : {}),
|
|
10114
10120
|
});
|
|
10115
10121
|
}
|
|
10116
10122
|
|
|
@@ -12589,7 +12595,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12589
12595
|
dispatchPayload: owner.input,
|
|
12590
12596
|
resultReceiptKey: receiptKey,
|
|
12591
12597
|
providerOperationKey:
|
|
12592
|
-
|
|
12598
|
+
this.providerOperationKeyForQueuedToolCall(owner),
|
|
12593
12599
|
apiOptions: {
|
|
12594
12600
|
beforeProviderCall: () =>
|
|
12595
12601
|
this.assertRuntimeToolReceiptOwnership([owner]),
|
|
@@ -12597,18 +12603,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12597
12603
|
playNodeScope: playNodeScopeForToolCallRequest(owner),
|
|
12598
12604
|
executionAuthScopeDigest:
|
|
12599
12605
|
owner.executionAuthScopeDigest,
|
|
12600
|
-
providerIdempotencyReceiptKey:
|
|
12601
|
-
owner.providerIdempotencyKeyBase ?? owner.cacheKey,
|
|
12602
12606
|
receiptLeaseExpiresAt: owner.receiptLeaseExpiresAt,
|
|
12603
12607
|
heartbeatReceipt: () =>
|
|
12604
12608
|
this.renewRuntimeToolReceiptOwnership([owner]),
|
|
12605
12609
|
providerIdempotencyKey:
|
|
12606
12610
|
this.providerIdempotencyKeyForToolCall({
|
|
12607
|
-
|
|
12608
|
-
owner
|
|
12609
|
-
owner.cacheKey,
|
|
12611
|
+
operationKey:
|
|
12612
|
+
this.providerOperationKeyForQueuedToolCall(owner),
|
|
12610
12613
|
force: owner.force === true,
|
|
12611
|
-
leaseId: owner.receiptLeaseId,
|
|
12612
12614
|
logicalCallId: owner.logicalCallId,
|
|
12613
12615
|
}),
|
|
12614
12616
|
timeoutMs: resolveRuntimeTimeoutMsForClaimedOwners([
|
|
@@ -12942,7 +12944,17 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12942
12944
|
toolId: batch.batchOperation,
|
|
12943
12945
|
}),
|
|
12944
12946
|
});
|
|
12945
|
-
const
|
|
12947
|
+
const aggregateForceRefreshIdentities = batch.memberRequests
|
|
12948
|
+
.filter((request) => request.force === true)
|
|
12949
|
+
.map((request) =>
|
|
12950
|
+
this.providerIdempotencyKeyForToolCall({
|
|
12951
|
+
operationKey:
|
|
12952
|
+
this.providerOperationKeyForQueuedToolCall(request),
|
|
12953
|
+
force: true,
|
|
12954
|
+
logicalCallId: request.logicalCallId,
|
|
12955
|
+
}),
|
|
12956
|
+
);
|
|
12957
|
+
const aggregateProviderOperationKey =
|
|
12946
12958
|
buildDurableToolPayloadProviderIdempotencyKey({
|
|
12947
12959
|
orgId: this.#options.orgId,
|
|
12948
12960
|
toolId: batch.batchOperation,
|
|
@@ -12956,18 +12968,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12956
12968
|
)
|
|
12957
12969
|
)?.trim() ?? 'unversioned',
|
|
12958
12970
|
payload: batch.batchPayload,
|
|
12959
|
-
forceRefreshIdentities:
|
|
12960
|
-
.filter((request) => request.force === true)
|
|
12961
|
-
.map((request) =>
|
|
12962
|
-
this.providerIdempotencyKeyForToolCall({
|
|
12963
|
-
cacheKey:
|
|
12964
|
-
request.providerIdempotencyKeyBase ??
|
|
12965
|
-
request.cacheKey,
|
|
12966
|
-
force: true,
|
|
12967
|
-
leaseId: request.receiptLeaseId,
|
|
12968
|
-
logicalCallId: request.logicalCallId,
|
|
12969
|
-
}),
|
|
12970
|
-
),
|
|
12971
|
+
forceRefreshIdentities: aggregateForceRefreshIdentities,
|
|
12971
12972
|
});
|
|
12972
12973
|
let releaseToolSlot: () => void = () => undefined;
|
|
12973
12974
|
try {
|
|
@@ -12977,8 +12978,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12977
12978
|
dispatchToolId: batch.batchOperation,
|
|
12978
12979
|
dispatchPayload: batch.batchPayload,
|
|
12979
12980
|
resultReceiptKey: aggregateReceiptKey,
|
|
12980
|
-
providerOperationKey:
|
|
12981
|
-
aggregateProviderIdempotencyReceiptKey,
|
|
12981
|
+
providerOperationKey: aggregateProviderOperationKey,
|
|
12982
12982
|
apiOptions: {
|
|
12983
12983
|
durableCallReceiptKey: aggregateReceiptKey,
|
|
12984
12984
|
// A native batch is one physical provider request for
|
|
@@ -12991,10 +12991,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12991
12991
|
executionAuthScopeDigest:
|
|
12992
12992
|
batch.memberRequests[0]?.executionAuthScopeDigest ??
|
|
12993
12993
|
null,
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
aggregateProviderIdempotencyReceiptKey,
|
|
12994
|
+
providerIdempotencyKey: aggregateProviderOperationKey,
|
|
12995
|
+
providerOperationForceRefreshIdentities:
|
|
12996
|
+
aggregateForceRefreshIdentities,
|
|
12998
12997
|
receiptLeaseExpiresAt: batch.memberRequests.reduce<
|
|
12999
12998
|
string | null
|
|
13000
12999
|
>((earliest, request) => {
|
|
@@ -13197,15 +13196,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13197
13196
|
request,
|
|
13198
13197
|
dispatchToolId: toolId,
|
|
13199
13198
|
dispatchPayload: request.input,
|
|
13200
|
-
// Always-fresh map calls intentionally have no
|
|
13201
|
-
//
|
|
13202
|
-
//
|
|
13199
|
+
// Always-fresh map calls intentionally have no
|
|
13200
|
+
// result cache. Their provider-operation identity is
|
|
13201
|
+
// a unique forced semantic request, never a cache key.
|
|
13203
13202
|
resultReceiptKey:
|
|
13204
13203
|
request.receiptKey ?? request.cacheKey,
|
|
13205
13204
|
providerOperationKey:
|
|
13206
|
-
request
|
|
13207
|
-
request.receiptKey ??
|
|
13208
|
-
request.cacheKey,
|
|
13205
|
+
this.providerOperationKeyForQueuedToolCall(request),
|
|
13209
13206
|
apiOptions: {
|
|
13210
13207
|
beforeProviderCall: () =>
|
|
13211
13208
|
pendingReceiptHeartbeat
|
|
@@ -13221,16 +13218,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13221
13218
|
completedResultCache: true,
|
|
13222
13219
|
executionAuthScopeDigest:
|
|
13223
13220
|
request.executionAuthScopeDigest,
|
|
13224
|
-
providerIdempotencyReceiptKey:
|
|
13225
|
-
request.providerIdempotencyKeyBase ??
|
|
13226
|
-
request.receiptKey,
|
|
13227
13221
|
providerIdempotencyKey:
|
|
13228
13222
|
this.providerIdempotencyKeyForToolCall({
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13223
|
+
operationKey:
|
|
13224
|
+
this.providerOperationKeyForQueuedToolCall(
|
|
13225
|
+
request,
|
|
13226
|
+
),
|
|
13232
13227
|
force: request.force === true,
|
|
13233
|
-
leaseId: request.receiptLeaseId,
|
|
13234
13228
|
logicalCallId: request.logicalCallId,
|
|
13235
13229
|
}),
|
|
13236
13230
|
receiptLeaseExpiresAt:
|
|
@@ -13240,7 +13234,17 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13240
13234
|
request,
|
|
13241
13235
|
]),
|
|
13242
13236
|
}
|
|
13243
|
-
: {
|
|
13237
|
+
: {
|
|
13238
|
+
providerIdempotencyKey:
|
|
13239
|
+
this.providerIdempotencyKeyForToolCall({
|
|
13240
|
+
operationKey:
|
|
13241
|
+
this.providerOperationKeyForQueuedToolCall(
|
|
13242
|
+
request,
|
|
13243
|
+
),
|
|
13244
|
+
force: true,
|
|
13245
|
+
logicalCallId: request.logicalCallId,
|
|
13246
|
+
}),
|
|
13247
|
+
}),
|
|
13244
13248
|
timeoutMs: resolveRuntimeTimeoutMsForClaimedOwners([
|
|
13245
13249
|
request,
|
|
13246
13250
|
]),
|
|
@@ -13383,173 +13387,36 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13383
13387
|
}
|
|
13384
13388
|
|
|
13385
13389
|
private providerIdempotencyKeyForToolCall(input: {
|
|
13386
|
-
|
|
13390
|
+
operationKey: string;
|
|
13387
13391
|
force?: boolean;
|
|
13388
|
-
leaseId?: string | null;
|
|
13389
13392
|
logicalCallId?: string;
|
|
13390
13393
|
}): string {
|
|
13391
13394
|
let fallbackAttemptId: string | null = null;
|
|
13392
|
-
if (input.force === true
|
|
13395
|
+
if (input.force === true) {
|
|
13393
13396
|
if (!input.logicalCallId) {
|
|
13394
13397
|
throw new Error(
|
|
13395
|
-
'Forced tool execution
|
|
13398
|
+
'Forced tool execution requires a stable logical call identity.',
|
|
13396
13399
|
);
|
|
13397
13400
|
}
|
|
13398
13401
|
fallbackAttemptId = `${this.currentRunId}:${input.logicalCallId}`;
|
|
13399
13402
|
}
|
|
13400
|
-
return
|
|
13401
|
-
|
|
13403
|
+
return buildProviderOperationIdempotencyKey({
|
|
13404
|
+
operationKey: input.operationKey,
|
|
13402
13405
|
force: input.force,
|
|
13403
|
-
receiptLeaseId: input.leaseId,
|
|
13404
13406
|
fallbackAttemptId,
|
|
13405
13407
|
});
|
|
13406
13408
|
}
|
|
13407
13409
|
|
|
13408
|
-
private
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
}): Promise<() => void> {
|
|
13414
|
-
const scopeSuffix =
|
|
13415
|
-
input.contract.capacity.scope === 'organization_action'
|
|
13416
|
-
? input.toolId
|
|
13417
|
-
: input.contract.capacity.scope === 'organization_connection'
|
|
13418
|
-
? (input.authScopeDigest ?? 'default-connection')
|
|
13419
|
-
: input.provider;
|
|
13420
|
-
const key = `${this.#options.orgId ?? 'unknown-org'}:${input.provider}:${input.contract.capacity.scope}:${scopeSuffix}`;
|
|
13421
|
-
let limit = 1;
|
|
13422
|
-
if (input.contract.capacity.limit.kind === 'fixed') {
|
|
13423
|
-
limit = input.contract.capacity.limit.maxConcurrentJobs;
|
|
13424
|
-
} else {
|
|
13425
|
-
const hints =
|
|
13426
|
-
(await this.#options.getToolQueueHints?.(input.toolId)) ?? [];
|
|
13427
|
-
const declaredLimits = hints
|
|
13428
|
-
.map((hint) => hint.maxConcurrency)
|
|
13429
|
-
.filter(
|
|
13430
|
-
(value): value is number =>
|
|
13431
|
-
typeof value === 'number' && Number.isFinite(value) && value > 0,
|
|
13432
|
-
);
|
|
13433
|
-
limit = declaredLimits.length > 0 ? Math.min(...declaredLimits) : 1;
|
|
13434
|
-
}
|
|
13435
|
-
const state = this.asyncOperationCapacity.get(key) ?? {
|
|
13436
|
-
active: 0,
|
|
13437
|
-
waiters: [],
|
|
13438
|
-
};
|
|
13439
|
-
this.asyncOperationCapacity.set(key, state);
|
|
13440
|
-
if (state.active >= limit) {
|
|
13441
|
-
if (input.contract.capacity.onConflict === 'fail') {
|
|
13442
|
-
throw new Error(
|
|
13443
|
-
`Async provider capacity is full for ${input.provider}; the contract allows ${limit} active job(s).`,
|
|
13444
|
-
);
|
|
13445
|
-
}
|
|
13446
|
-
await new Promise<void>((resolve) => state.waiters.push(resolve));
|
|
13447
|
-
}
|
|
13448
|
-
state.active += 1;
|
|
13449
|
-
let released = false;
|
|
13450
|
-
return () => {
|
|
13451
|
-
if (released) return;
|
|
13452
|
-
released = true;
|
|
13453
|
-
state.active = Math.max(0, state.active - 1);
|
|
13454
|
-
state.waiters.shift()?.();
|
|
13455
|
-
if (state.active === 0 && state.waiters.length === 0) {
|
|
13456
|
-
this.asyncOperationCapacity.delete(key);
|
|
13457
|
-
}
|
|
13458
|
-
};
|
|
13459
|
-
}
|
|
13460
|
-
|
|
13461
|
-
private asyncOperationActionReceiptKey(input: {
|
|
13462
|
-
action: string;
|
|
13463
|
-
parentReceiptKey: string | null;
|
|
13464
|
-
jobId: string;
|
|
13465
|
-
phase: string;
|
|
13466
|
-
}): string | null {
|
|
13467
|
-
if (!input.parentReceiptKey) return null;
|
|
13468
|
-
return `${buildDurableToolReceiptPrefix({
|
|
13469
|
-
orgId: this.#options.orgId,
|
|
13470
|
-
toolId: input.action,
|
|
13471
|
-
})}${stableDigest(
|
|
13472
|
-
stableStringify({
|
|
13473
|
-
parentReceiptKey: input.parentReceiptKey,
|
|
13474
|
-
jobId: input.jobId,
|
|
13475
|
-
phase: input.phase,
|
|
13476
|
-
}),
|
|
13477
|
-
)}`;
|
|
13478
|
-
}
|
|
13479
|
-
|
|
13480
|
-
private async resolveAsyncOperation(input: {
|
|
13481
|
-
toolId: string;
|
|
13482
|
-
startInput: Record<string, unknown>;
|
|
13483
|
-
startResponse: ParsedToolExecuteResponse;
|
|
13484
|
-
contract: AsyncOperationContractWire;
|
|
13485
|
-
receiptKey: string | null;
|
|
13486
|
-
}): Promise<ParsedToolExecuteResponse> {
|
|
13487
|
-
const responseValue = (response: ParsedToolExecuteResponse): unknown => {
|
|
13488
|
-
if (response.toolResponse && 'raw' in response.toolResponse) {
|
|
13489
|
-
return response.toolResponse.raw;
|
|
13490
|
-
}
|
|
13491
|
-
const result = recordOrNull(response.result);
|
|
13492
|
-
return result && Object.prototype.hasOwnProperty.call(result, 'data')
|
|
13493
|
-
? result.data
|
|
13494
|
-
: response.result;
|
|
13495
|
-
};
|
|
13496
|
-
const startResult = responseValue(input.startResponse);
|
|
13497
|
-
const lifecycle = await executeAsyncOperationLifecycle({
|
|
13498
|
-
contract: input.contract,
|
|
13499
|
-
startInput: input.startInput,
|
|
13500
|
-
startResult,
|
|
13501
|
-
jobId: input.startResponse.jobId,
|
|
13502
|
-
sleep: async (delayMs) =>
|
|
13503
|
-
await this.sleepWithCheckpointHeartbeat(delayMs),
|
|
13504
|
-
responseValue,
|
|
13505
|
-
executeAction: async (request) => {
|
|
13506
|
-
const receiptKey = this.asyncOperationActionReceiptKey({
|
|
13507
|
-
action: request.action,
|
|
13508
|
-
parentReceiptKey: input.receiptKey,
|
|
13509
|
-
jobId: request.jobId,
|
|
13510
|
-
phase: `${request.phase}:${request.pollAttempt}:${request.page ?? ''}`,
|
|
13511
|
-
});
|
|
13512
|
-
return await this.callToolExecutionAPI(request.action, request.input, {
|
|
13513
|
-
skipAsyncOperationResolution: true,
|
|
13514
|
-
durableCallReceiptKey: receiptKey,
|
|
13515
|
-
providerIdempotencyReceiptKey: receiptKey,
|
|
13516
|
-
providerIdempotencyKey: receiptKey,
|
|
13517
|
-
});
|
|
13518
|
-
},
|
|
13519
|
-
});
|
|
13520
|
-
if (lifecycle.kind === 'timed_out') {
|
|
13521
|
-
const polling = resolveAsyncOperationPolling({
|
|
13522
|
-
contract: input.contract,
|
|
13523
|
-
startInput: input.startInput,
|
|
13524
|
-
});
|
|
13525
|
-
throw new Error(
|
|
13526
|
-
`Async operation ${input.toolId} (${lifecycle.jobId}) did not reach a terminal state within ${polling.timeoutMs}ms.`,
|
|
13527
|
-
);
|
|
13528
|
-
}
|
|
13529
|
-
if (
|
|
13530
|
-
lifecycle.classification.outcome === 'failed' ||
|
|
13531
|
-
lifecycle.classification.outcome === 'cancelled'
|
|
13532
|
-
) {
|
|
13410
|
+
private providerOperationKeyForQueuedToolCall(
|
|
13411
|
+
request: ToolCallRequest,
|
|
13412
|
+
): string {
|
|
13413
|
+
const operationKey = request.providerIdempotencyKeyBase?.trim();
|
|
13414
|
+
if (!operationKey) {
|
|
13533
13415
|
throw new Error(
|
|
13534
|
-
|
|
13535
|
-
`Async operation ${input.toolId} (${lifecycle.jobId}) ended ${lifecycle.classification.outcome}.`,
|
|
13416
|
+
`Queued tool call ${request.callId} is missing its semantic provider operation identity.`,
|
|
13536
13417
|
);
|
|
13537
13418
|
}
|
|
13538
|
-
|
|
13539
|
-
const selectedResponse = lifecycle.finishResponse ?? lifecycle.pollResponse;
|
|
13540
|
-
return {
|
|
13541
|
-
...selectedResponse,
|
|
13542
|
-
status:
|
|
13543
|
-
lifecycle.classification.outcome === 'no_result' ||
|
|
13544
|
-
materialized.outcome === 'no_result'
|
|
13545
|
-
? 'no_result'
|
|
13546
|
-
: 'completed',
|
|
13547
|
-
result: { data: materialized.result },
|
|
13548
|
-
toolResponse: materializedAsyncToolResponse(
|
|
13549
|
-
selectedResponse.toolResponse,
|
|
13550
|
-
materialized.result,
|
|
13551
|
-
),
|
|
13552
|
-
};
|
|
13419
|
+
return operationKey;
|
|
13553
13420
|
}
|
|
13554
13421
|
|
|
13555
13422
|
private async callToolExecutionAPI(
|
|
@@ -13565,7 +13432,29 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13565
13432
|
const requestsDurableInvocationFence =
|
|
13566
13433
|
this.#options.requestDurableInvocationFence === true ||
|
|
13567
13434
|
this.#options.durableInvocationFence === true;
|
|
13568
|
-
const
|
|
13435
|
+
const asyncContract = options?.skipAsyncOperationResolution
|
|
13436
|
+
? null
|
|
13437
|
+
: ((await this.#options.getToolAsyncOperation?.(toolId)) ?? null);
|
|
13438
|
+
const shouldWaitForAsyncOperation = Boolean(
|
|
13439
|
+
asyncContract && asyncOperationShouldWait(asyncContract, input),
|
|
13440
|
+
);
|
|
13441
|
+
const executionAuthScopeDigest = options?.executionAuthScopeDigest
|
|
13442
|
+
? options.executionAuthScopeDigest.trim() || null
|
|
13443
|
+
: ((await this.resolveToolAuthScopeDigest(toolId))?.trim() ?? null);
|
|
13444
|
+
const provider =
|
|
13445
|
+
(await this.#options.getToolProvider?.(toolId))?.trim() ||
|
|
13446
|
+
toolId.split(/[._]/)[0]?.trim() ||
|
|
13447
|
+
'provider';
|
|
13448
|
+
// A receipt is a terminal-output cache, never an async provider-job
|
|
13449
|
+
// record. Launch/poll/finish transport must therefore remain receiptless:
|
|
13450
|
+
// if this process stops, a later cache miss starts a new provider request
|
|
13451
|
+
// rather than attaching itself to this one.
|
|
13452
|
+
const uncachedAsyncLifecycleCall =
|
|
13453
|
+
options?.uncachedAsyncLifecycleCall === true ||
|
|
13454
|
+
shouldWaitForAsyncOperation;
|
|
13455
|
+
const usesDurableInvocationFence =
|
|
13456
|
+
requestsDurableInvocationFence && !uncachedAsyncLifecycleCall;
|
|
13457
|
+
const executeSuffix = usesDurableInvocationFence
|
|
13569
13458
|
? 'execute-fenced-v1'
|
|
13570
13459
|
: 'execute';
|
|
13571
13460
|
// Keep receipts, runner heartbeats, terminals, sheets, and runtime control
|
|
@@ -13580,17 +13469,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13580
13469
|
options?.timeoutMs,
|
|
13581
13470
|
this.currentAuthoringContractEdition,
|
|
13582
13471
|
);
|
|
13583
|
-
const provider = toolId.split(/[._]/)[0]?.trim() || 'provider';
|
|
13584
|
-
const asyncContract = options?.skipAsyncOperationResolution
|
|
13585
|
-
? null
|
|
13586
|
-
: ((await this.#options.getToolAsyncOperation?.(toolId)) ?? null);
|
|
13587
|
-
const shouldWaitForAsyncOperation = Boolean(
|
|
13588
|
-
asyncContract && asyncOperationShouldWait(asyncContract, input),
|
|
13589
|
-
);
|
|
13590
|
-
const effectiveInput =
|
|
13591
|
-
asyncContract && shouldWaitForAsyncOperation
|
|
13592
|
-
? asyncOperationDurableStartInput(asyncContract, input)
|
|
13593
|
-
: input;
|
|
13594
13472
|
const activityId = `provider:${toolId}`;
|
|
13595
13473
|
let retryActivityEmitted = false;
|
|
13596
13474
|
let toolCallSucceeded = false;
|
|
@@ -13599,16 +13477,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13599
13477
|
// execution. Per-provider rate admission is intentionally deferred until
|
|
13600
13478
|
// each physical fetch is ready to leave this process.
|
|
13601
13479
|
const admissionStartedAt = Date.now();
|
|
13602
|
-
const asyncCapacityRelease =
|
|
13603
|
-
asyncContract && shouldWaitForAsyncOperation
|
|
13604
|
-
? await this.acquireAsyncOperationCapacity({
|
|
13605
|
-
toolId,
|
|
13606
|
-
provider,
|
|
13607
|
-
contract: asyncContract,
|
|
13608
|
-
authScopeDigest:
|
|
13609
|
-
(await this.resolveToolAuthScopeDigest(toolId))?.trim() ?? null,
|
|
13610
|
-
})
|
|
13611
|
-
: null;
|
|
13612
13480
|
let toolSlot: RuntimeResourceLease;
|
|
13613
13481
|
try {
|
|
13614
13482
|
toolSlot = await this.resourceGovernor.acquireTool({
|
|
@@ -13617,7 +13485,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13617
13485
|
toolId,
|
|
13618
13486
|
});
|
|
13619
13487
|
} catch (error) {
|
|
13620
|
-
asyncCapacityRelease?.();
|
|
13621
13488
|
if (!(error instanceof ProviderExhaustedError)) throw error;
|
|
13622
13489
|
const retryAtMs = Date.parse(error.retryAt);
|
|
13623
13490
|
throw createToolHttpError(
|
|
@@ -13673,9 +13540,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13673
13540
|
// Snapshot the caller-controlled payload exactly once. The replay
|
|
13674
13541
|
// decision and every physical attempt must refer to the same bytes,
|
|
13675
13542
|
// even if the original object has getters or is later mutated.
|
|
13676
|
-
const toolInputSnapshot = JSON.parse(
|
|
13677
|
-
|
|
13678
|
-
|
|
13543
|
+
const toolInputSnapshot = JSON.parse(JSON.stringify(input)) as Record<
|
|
13544
|
+
string,
|
|
13545
|
+
unknown
|
|
13546
|
+
>;
|
|
13679
13547
|
const retryPolicy = await this.#options
|
|
13680
13548
|
.getToolRetryPolicy?.(toolId, toolInputSnapshot)
|
|
13681
13549
|
.catch(() => null);
|
|
@@ -13695,19 +13563,17 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13695
13563
|
const ambiguousTransportReplayAllowed =
|
|
13696
13564
|
readOnlyQuery || retrySafeTransientHttp;
|
|
13697
13565
|
const invocationOrgId = this.#options.orgId?.trim() ?? '';
|
|
13698
|
-
const durableCallReceiptKey =
|
|
13699
|
-
|
|
13700
|
-
(
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
? options.executionAuthScopeDigest.trim() || null
|
|
13710
|
-
: ((await this.resolveToolAuthScopeDigest(toolId))?.trim() ?? null);
|
|
13566
|
+
const durableCallReceiptKey = uncachedAsyncLifecycleCall
|
|
13567
|
+
? null
|
|
13568
|
+
: options?.durableCallReceiptKey?.trim() ||
|
|
13569
|
+
(usesDurableInvocationFence && invocationOrgId
|
|
13570
|
+
? `${buildDurableToolReceiptPrefix({
|
|
13571
|
+
orgId: invocationOrgId,
|
|
13572
|
+
toolId,
|
|
13573
|
+
})}${stableDigest(
|
|
13574
|
+
`transport:${this.currentRunId}:${toolId}:${crypto.randomUUID()}`,
|
|
13575
|
+
)}`
|
|
13576
|
+
: null);
|
|
13711
13577
|
const executionRequestNonce = crypto.randomUUID();
|
|
13712
13578
|
// This identifies one logical tool call to billing. Physical retry
|
|
13713
13579
|
// count remains in request metadata, so a transport retry cannot
|
|
@@ -13727,6 +13593,29 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13727
13593
|
`Tool ${toolId} requires a provider execution fence but no provider operation identity was supplied.`,
|
|
13728
13594
|
);
|
|
13729
13595
|
}
|
|
13596
|
+
const canonicalOperationActionVersion = providerExecutionFenceKey
|
|
13597
|
+
? (
|
|
13598
|
+
await this.#options.getToolActionCacheVersion?.(toolId)
|
|
13599
|
+
)?.trim() || null
|
|
13600
|
+
: null;
|
|
13601
|
+
const canonicalOperation =
|
|
13602
|
+
providerExecutionFenceKey && canonicalOperationActionVersion
|
|
13603
|
+
? {
|
|
13604
|
+
version: 1,
|
|
13605
|
+
tool_id: toolId,
|
|
13606
|
+
action_version: canonicalOperationActionVersion,
|
|
13607
|
+
play_scope: this.currentGovernance.currentPlayId || 'play',
|
|
13608
|
+
output_intent: options?.completedResultCache
|
|
13609
|
+
? 'dataset'
|
|
13610
|
+
: 'value',
|
|
13611
|
+
...(options?.providerOperationForceRefreshIdentities?.length
|
|
13612
|
+
? {
|
|
13613
|
+
force_refresh_identities:
|
|
13614
|
+
options.providerOperationForceRefreshIdentities,
|
|
13615
|
+
}
|
|
13616
|
+
: {}),
|
|
13617
|
+
}
|
|
13618
|
+
: null;
|
|
13730
13619
|
// Every runtime provider call carries at least a tool-scoped
|
|
13731
13620
|
// attribution. Callers that know the execution location (row-scoped
|
|
13732
13621
|
// map cells, batched owners) supply the fuller scope.
|
|
@@ -13738,7 +13627,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13738
13627
|
metadata: {
|
|
13739
13628
|
parent_run_id: this.#options.runId,
|
|
13740
13629
|
invocation_attempt: invocationAttempt,
|
|
13741
|
-
...(
|
|
13630
|
+
...(shouldWaitForAsyncOperation
|
|
13631
|
+
? { async_operation_wait: true }
|
|
13632
|
+
: {}),
|
|
13633
|
+
...(usesDurableInvocationFence
|
|
13742
13634
|
? { invocation_fence_version: 1 }
|
|
13743
13635
|
: {}),
|
|
13744
13636
|
...(durableCallReceiptKey
|
|
@@ -13763,6 +13655,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
13763
13655
|
: {}),
|
|
13764
13656
|
}
|
|
13765
13657
|
: {}),
|
|
13658
|
+
...(canonicalOperation
|
|
13659
|
+
? { canonical_operation: canonicalOperation }
|
|
13660
|
+
: {}),
|
|
13766
13661
|
...(options?.customerDbDataset
|
|
13767
13662
|
? {
|
|
13768
13663
|
query_result_dataset: {
|
|
@@ -14391,29 +14286,8 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
14391
14286
|
? 'array'
|
|
14392
14287
|
: typeof parsed.result,
|
|
14393
14288
|
});
|
|
14394
|
-
const parsedValue =
|
|
14395
|
-
parsed.toolResponse && 'raw' in parsed.toolResponse
|
|
14396
|
-
? parsed.toolResponse.raw
|
|
14397
|
-
: (recordOrNull(parsed.result)?.data ?? parsed.result);
|
|
14398
|
-
const asyncStartPending =
|
|
14399
|
-
asyncContract && shouldWaitForAsyncOperation
|
|
14400
|
-
? classifyAsyncOperationResult(asyncContract, parsedValue)
|
|
14401
|
-
.outcome === 'running'
|
|
14402
|
-
: false;
|
|
14403
|
-
const resolved =
|
|
14404
|
-
asyncContract &&
|
|
14405
|
-
shouldWaitForAsyncOperation &&
|
|
14406
|
-
(parsed.status === 'running' || asyncStartPending)
|
|
14407
|
-
? await this.resolveAsyncOperation({
|
|
14408
|
-
toolId,
|
|
14409
|
-
startInput: input,
|
|
14410
|
-
startResponse: parsed,
|
|
14411
|
-
contract: asyncContract,
|
|
14412
|
-
receiptKey: durableCallReceiptKey,
|
|
14413
|
-
})
|
|
14414
|
-
: parsed;
|
|
14415
14289
|
toolCallSucceeded = true;
|
|
14416
|
-
return
|
|
14290
|
+
return parsed;
|
|
14417
14291
|
}
|
|
14418
14292
|
},
|
|
14419
14293
|
);
|
|
@@ -14440,7 +14314,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
14440
14314
|
if (!toolSlotTransferred) {
|
|
14441
14315
|
toolSlot.release();
|
|
14442
14316
|
}
|
|
14443
|
-
asyncCapacityRelease?.();
|
|
14444
14317
|
}
|
|
14445
14318
|
}
|
|
14446
14319
|
|