deepline 0.3.324 → 0.3.326

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.
Files changed (133) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +23 -25
  2. package/dist/bundling-sources/sdk/src/compat.ts +11 -6
  3. package/dist/bundling-sources/sdk/src/db/query.ts +172 -0
  4. package/dist/bundling-sources/sdk/src/errors.ts +35 -0
  5. package/dist/bundling-sources/sdk/src/index.ts +13 -0
  6. package/dist/bundling-sources/sdk/src/play.ts +34 -31
  7. package/dist/bundling-sources/sdk/src/plays/authoring-graph-path.ts +13 -0
  8. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +2 -1
  9. package/dist/bundling-sources/sdk/src/plays/local-play-execution.ts +189 -0
  10. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  11. package/dist/bundling-sources/sdk/src/tool-calls.ts +1 -1
  12. package/dist/bundling-sources/sdk/src/types.ts +6 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +2 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +7 -1
  15. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +1 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +5 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +84 -10
  18. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +9 -0
  19. package/dist/cli/auth-6STWK6UK.js +31 -0
  20. package/dist/cli/{auth-6KWNR6AI.mjs → auth-VON5FFUK.mjs} +4 -4
  21. package/dist/cli/{billing-VQ2NUJLB.mjs → billing-X6JUEFRE.mjs} +4 -4
  22. package/dist/cli/{billing-CLLWHIAT.js → billing-YI4RZI2O.js} +70 -70
  23. package/dist/cli/{chunk-NC2ZXG2Y.js → chunk-3NGWGFVL.js} +26 -26
  24. package/dist/cli/{chunk-5CQ554BM.mjs → chunk-4AB4Y6FF.mjs} +1 -1
  25. package/dist/cli/{chunk-EXKRHZRG.js → chunk-4LNBSQM4.js} +5928 -5730
  26. package/dist/cli/{chunk-G4F2AIQ5.js → chunk-5NXHSRRE.js} +6 -6
  27. package/dist/cli/{chunk-XNL3SEMC.js → chunk-AFNEQ43J.js} +8 -3
  28. package/dist/cli/{chunk-XSEMQ4II.js → chunk-AGH6YP2T.js} +2 -1
  29. package/dist/cli/chunk-AID3OYVJ.js +8 -0
  30. package/dist/cli/{chunk-HHZDWBSQ.mjs → chunk-BQJVMKWL.mjs} +1 -1
  31. package/dist/cli/{chunk-TJGJTB5T.mjs → chunk-BR7GGTAE.mjs} +24 -1
  32. package/dist/cli/{chunk-IXYR65PW.js → chunk-BUYZEUY4.js} +1 -1
  33. package/dist/cli/{chunk-GROXVGGW.js → chunk-CUUHQ3AO.js} +6 -6
  34. package/dist/cli/{chunk-NIOFMRYW.mjs → chunk-DFDXKOLR.mjs} +98 -113
  35. package/dist/cli/{chunk-GMO3NBE2.js → chunk-EMZ7Y5SW.js} +70 -67
  36. package/dist/cli/chunk-GVESPYSY.mjs +234 -0
  37. package/dist/cli/{chunk-N5E66DP3.js → chunk-GVYKY6T6.js} +344 -254
  38. package/dist/cli/{chunk-EHSI2DMO.mjs → chunk-IQCCGOQH.mjs} +4 -20
  39. package/dist/cli/{chunk-76VKBPOC.mjs → chunk-JOA6IKDE.mjs} +7 -2
  40. package/dist/cli/{chunk-3ZKAKQYC.mjs → chunk-KLWBAQ5A.mjs} +104 -14
  41. package/dist/cli/{chunk-PAA4FYCF.js → chunk-KZ4PCK4O.js} +29 -45
  42. package/dist/cli/chunk-LVEDPCLJ.js +234 -0
  43. package/dist/cli/{chunk-I7RLL7LN.mjs → chunk-M7CPVMDB.mjs} +1 -1
  44. package/dist/cli/{chunk-2UQUOUAW.js → chunk-MDQZQ3NY.js} +2 -2
  45. package/dist/cli/{chunk-V5PA6TCT.js → chunk-MKHSZA2X.js} +48 -48
  46. package/dist/cli/{chunk-LHJKYMTS.mjs → chunk-MOBZS4F3.mjs} +1 -1
  47. package/dist/cli/chunk-OVDNJAJN.mjs +8 -0
  48. package/dist/cli/{chunk-QM2Z4FQF.js → chunk-T33W6JUJ.js} +6 -6
  49. package/dist/cli/{chunk-DO2VA5UP.mjs → chunk-TDSNAC3C.mjs} +2 -2
  50. package/dist/cli/{chunk-D5YJHGST.js → chunk-TXVOB5J2.js} +29 -6
  51. package/dist/cli/{chunk-TZZNI2A4.js → chunk-TZQMFWLF.js} +147 -162
  52. package/dist/cli/{chunk-NQJQ3CLX.mjs → chunk-VGKVLADU.mjs} +3 -3
  53. package/dist/cli/{chunk-U2RPP53P.mjs → chunk-VKXGOQG5.mjs} +5674 -5476
  54. package/dist/cli/{chunk-AKM5JVPG.mjs → chunk-W74E5ETE.mjs} +12 -9
  55. package/dist/cli/{chunk-7PZFGB7L.mjs → chunk-YIY74KUF.mjs} +2 -1
  56. package/dist/cli/{chunk-5QZFWY7C.mjs → chunk-ZRN6YOF2.mjs} +2 -2
  57. package/dist/cli/client-TEBW2P24.js +20 -0
  58. package/dist/cli/{client-VHUKTDAZ.mjs → client-ZMOKUNL2.mjs} +3 -3
  59. package/dist/cli/{csv-5MZY7HU5.js → csv-HZRKEI7J.js} +12 -12
  60. package/dist/cli/{csv-7DA4APB6.mjs → csv-IICJHJZ4.mjs} +3 -3
  61. package/dist/cli/{db-ICG3FUVE.js → db-TM5NZF73.js} +226 -149
  62. package/dist/cli/{db-7UPW3N5U.mjs → db-X4B7YFNY.mjs} +214 -137
  63. package/dist/cli/{describe-VDRY2JCE.js → describe-BDBARWZJ.js} +28 -27
  64. package/dist/cli/{describe-ZAPGM5ND.mjs → describe-GMVS3LFC.mjs} +12 -11
  65. package/dist/cli/{executions-TK3C2FAQ.mjs → executions-447ZJMN4.mjs} +4 -4
  66. package/dist/cli/{executions-D5GYCY3A.js → executions-QX25UOQM.js} +6 -6
  67. package/dist/cli/{feedback-PZAZZUXF.js → feedback-4IXUTBX7.js} +6 -6
  68. package/dist/cli/{feedback-T4EIP5QR.mjs → feedback-JB7HHIC6.mjs} +3 -3
  69. package/dist/cli/git-C7C7DTEH.js +23 -0
  70. package/dist/cli/{git-WBFWIVO5.mjs → git-VID6KGAA.mjs} +4 -4
  71. package/dist/cli/index.js +105 -87
  72. package/dist/cli/index.mjs +65 -47
  73. package/dist/cli/{legacy-noops-LRBJWXRK.js → legacy-noops-3FYTCOZO.js} +7 -7
  74. package/dist/cli/{legacy-noops-DUCK7OKN.mjs → legacy-noops-SGR3G5WS.mjs} +4 -4
  75. package/dist/cli/{monitors-WYH5AQIO.mjs → monitors-SH4FOMBM.mjs} +4 -4
  76. package/dist/cli/{monitors-7S2SL62G.js → monitors-SP52UHS4.js} +85 -85
  77. package/dist/cli/{org-XCSMLTUW.mjs → org-B32MMIQT.mjs} +4 -4
  78. package/dist/cli/{org-EQNGGHPV.js → org-UQMX7JOR.js} +60 -60
  79. package/dist/cli/play-UCIWBN7U.js +153 -0
  80. package/dist/cli/{play-A5ISFBJM.mjs → play-XTE4LUP7.mjs} +11 -10
  81. package/dist/cli/{providers-DR2CLD3N.js → providers-JNMJJ2OH.js} +7 -7
  82. package/dist/cli/{providers-KHTZFQ5I.mjs → providers-RWLN6FUR.mjs} +4 -4
  83. package/dist/cli/{quickstart-NIRWI6YU.js → quickstart-HK6WZ342.js} +5 -5
  84. package/dist/cli/{quickstart-KT4LKORA.mjs → quickstart-IDB3Y375.mjs} +3 -3
  85. package/dist/cli/{search-WCEXPBAT.mjs → search-6D3IFNPT.mjs} +5 -5
  86. package/dist/cli/search-LUZ2S7DH.js +26 -0
  87. package/dist/cli/{secrets-QSFEZGVE.js → secrets-JOQB57IE.js} +13 -13
  88. package/dist/cli/{secrets-TN7DW3QR.mjs → secrets-TZ53CQ3D.mjs} +4 -4
  89. package/dist/cli/{sessions-WSE5FN4H.mjs → sessions-4MBDC4EK.mjs} +4 -4
  90. package/dist/cli/{sessions-LJS6W67T.js → sessions-QSAICDXX.js} +5 -5
  91. package/dist/cli/{settings-FGS3VYJN.js → settings-OTOCW7L7.js} +74 -74
  92. package/dist/cli/{settings-Z3V53A6J.mjs → settings-RKQFMLDU.mjs} +7 -7
  93. package/dist/cli/{setup-GMH4VJS3.mjs → setup-2S5TNTUB.mjs} +6 -6
  94. package/dist/cli/{setup-ZA234HEY.js → setup-AKZUDVYY.js} +41 -41
  95. package/dist/cli/skills-26LASHZF.js +28 -0
  96. package/dist/cli/{skills-7G2RZMYH.mjs → skills-AGZXDLSA.mjs} +4 -4
  97. package/dist/cli/{tools-7EE4BGXO.mjs → tools-7Y6RD6FY.mjs} +8 -7
  98. package/dist/cli/tools-L5VIJQWX.js +39 -0
  99. package/dist/cli/{update-O5QEWS7K.mjs → update-M7YGF67I.mjs} +6 -6
  100. package/dist/cli/update-MNHF6M2F.js +28 -0
  101. package/dist/cli/{workflow-KE54RUTR.mjs → workflow-CTVE7S7W.mjs} +5 -5
  102. package/dist/cli/{workflow-M5PAAW3O.js → workflow-NGMY425T.js} +15 -15
  103. package/dist/{client-BV68GMPo.d.ts → client-DHq8dJ56.d.ts} +45 -11
  104. package/dist/{client-D9ACjiRC.d.mts → client-wiWPZhnI.d.mts} +45 -11
  105. package/dist/{compiler-manifest-BXcZ4P4W.d.mts → compiler-manifest-9TkZ_ykI.d.mts} +717 -711
  106. package/dist/{compiler-manifest-BXcZ4P4W.d.ts → compiler-manifest-9TkZ_ykI.d.ts} +717 -711
  107. package/dist/index-B-5_Xhud.d.mts +75 -0
  108. package/dist/index-ykksoEyR.d.ts +75 -0
  109. package/dist/index.d.mts +52 -13
  110. package/dist/index.d.ts +52 -13
  111. package/dist/index.js +92 -28
  112. package/dist/index.mjs +91 -27
  113. package/dist/install-integrity.json +91 -84
  114. package/dist/plays/bundle-play-file.d.mts +7 -75
  115. package/dist/plays/bundle-play-file.d.ts +7 -75
  116. package/dist/plays/bundle-play-file.mjs +1 -1
  117. package/dist/plays/run-request.d.mts +2 -2
  118. package/dist/plays/run-request.d.ts +2 -2
  119. package/dist/release.d.mts +1 -1
  120. package/dist/release.d.ts +1 -1
  121. package/dist/release.js +2 -2
  122. package/dist/release.mjs +1 -1
  123. package/package.json +1 -1
  124. package/dist/cli/auth-LKSTC3YV.js +0 -31
  125. package/dist/cli/chunk-OWJZUE3Y.mjs +0 -103
  126. package/dist/cli/chunk-SDK3ZA2C.js +0 -103
  127. package/dist/cli/client-WMSTRUGP.js +0 -20
  128. package/dist/cli/git-73N6EUZ3.js +0 -23
  129. package/dist/cli/play-CLC2Z5SO.js +0 -152
  130. package/dist/cli/search-DM7IQS5F.js +0 -26
  131. package/dist/cli/skills-6APAQV6W.js +0 -28
  132. package/dist/cli/tools-EPYUFWPB.js +0 -38
  133. package/dist/cli/update-FPVX3XJC.js +0 -28
@@ -51,6 +51,12 @@ import { playInputExampleArgs } from './plays/input-example.js';
51
51
  */
52
52
  import { resolveConfig } from './config.js';
53
53
  import { DeeplineError } from './errors.js';
54
+ import {
55
+ planCustomerDbQuery,
56
+ queryCustomerDatabase,
57
+ type CustomerDbQueryOptions,
58
+ type CustomerDbQueryPlan,
59
+ } from './db/query.js';
54
60
  import {
55
61
  ToolCalls,
56
62
  type ExecuteToolRawOptions,
@@ -1256,11 +1262,10 @@ export type StopAllRunsOptions = {
1256
1262
 
1257
1263
  /** Current mutable customer database namespace exposed as `client.db`. */
1258
1264
  export type DbNamespace = {
1259
- /** Run a bounded SQL query against the current customer data plane. */
1260
- query: (input: {
1261
- sql: string;
1262
- maxRows?: number;
1263
- }) => Promise<CustomerDbQueryResult>;
1265
+ /** Run a bounded SQL query; every request is attempted once. */
1266
+ query: (input: CustomerDbQueryOptions) => Promise<CustomerDbQueryResult>;
1267
+ /** Describe the request, effects and recovery policy without executing SQL. */
1268
+ planQuery: (input: CustomerDbQueryOptions) => CustomerDbQueryPlan;
1264
1269
  };
1265
1270
 
1266
1271
  /**
@@ -2921,6 +2926,7 @@ export class DeeplineClient {
2921
2926
  };
2922
2927
  this.db = {
2923
2928
  query: (input) => this.queryDb(input),
2929
+ planQuery: (input) => planCustomerDbQuery(input),
2924
2930
  };
2925
2931
  this.billing = {
2926
2932
  topUp: (options) => this.topUpBillingBalance(options),
@@ -3485,21 +3491,10 @@ export class DeeplineClient {
3485
3491
  return this.executeTool<TData, TMeta>(toolId, input, options);
3486
3492
  }
3487
3493
 
3488
- private async queryDb(input: {
3489
- sql: string;
3490
- maxRows?: number;
3491
- }): Promise<CustomerDbQueryResult> {
3492
- const result = await this.http.post<CustomerDbQueryResult>(
3493
- '/api/v2/db/query',
3494
- {
3495
- sql: input.sql,
3496
- ...(input.maxRows ? { max_rows: input.maxRows } : {}),
3497
- },
3498
- );
3499
- return {
3500
- ...result,
3501
- scope: { kind: 'database', mutability: 'current' },
3502
- };
3494
+ private async queryDb(
3495
+ input: CustomerDbQueryOptions,
3496
+ ): Promise<CustomerDbQueryResult> {
3497
+ return queryCustomerDatabase(this.http, input);
3503
3498
  }
3504
3499
 
3505
3500
  /**
@@ -3510,10 +3505,9 @@ export class DeeplineClient {
3510
3505
  *
3511
3506
  * @deprecated Use {@link DeeplineClient.db} `.query(...)`.
3512
3507
  */
3513
- async queryCustomerDb(input: {
3514
- sql: string;
3515
- maxRows?: number;
3516
- }): Promise<CustomerDbQueryResult> {
3508
+ async queryCustomerDb(
3509
+ input: CustomerDbQueryOptions,
3510
+ ): Promise<CustomerDbQueryResult> {
3517
3511
  return this.db.query(input);
3518
3512
  }
3519
3513
 
@@ -3627,6 +3621,8 @@ export class DeeplineClient {
3627
3621
  artifact: Record<string, unknown>;
3628
3622
  compilerManifest?: PlayCompilerManifest;
3629
3623
  publish?: boolean;
3624
+ /** Store execution content without changing a draft or live revision. */
3625
+ artifactOnly?: boolean;
3630
3626
  ownerType?: 'org' | 'deepline';
3631
3627
  scope?: 'org' | 'system';
3632
3628
  userId?: string;
@@ -3652,7 +3648,9 @@ export class DeeplineClient {
3652
3648
  artifact: input.artifact,
3653
3649
  }));
3654
3650
  return this.http.post(
3655
- '/api/v2/plays/artifacts',
3651
+ input.artifactOnly === true
3652
+ ? '/api/v2/plays/artifacts/immutable'
3653
+ : '/api/v2/plays/artifacts',
3656
3654
  {
3657
3655
  ...input,
3658
3656
  compilerManifest,
@@ -338,6 +338,8 @@ export async function checkSdkCompatibility(
338
338
  skillsVersion?: string | null;
339
339
  /** Blocking budget for the live request; defaults to the full timeout. */
340
340
  timeoutMs?: number;
341
+ /** Disable cache writes and invalidation for commands that permit no local maintenance. */
342
+ persistCache?: boolean;
341
343
  /** Optional read-only catalog result carried by the same live check. */
342
344
  catalog?: {
343
345
  toolId: string;
@@ -396,12 +398,14 @@ export async function checkSdkCompatibility(
396
398
  }
397
399
  // Catalog results belong to this command only, never the policy cache.
398
400
  const { catalog_metadata: catalogMetadata, ...data } = raw;
399
- writeCachedCompatibility(
400
- baseUrl,
401
- options.command,
402
- options.skillsVersion,
403
- data,
404
- );
401
+ if (options.persistCache !== false) {
402
+ writeCachedCompatibility(
403
+ baseUrl,
404
+ options.command,
405
+ options.skillsVersion,
406
+ data,
407
+ );
408
+ }
405
409
  if (
406
410
  options.catalog &&
407
411
  catalogMetadata &&
@@ -423,6 +427,7 @@ export async function checkSdkCompatibility(
423
427
  );
424
428
  if (cached) {
425
429
  if (
430
+ options.persistCache !== false &&
426
431
  options.timeoutMs !== undefined &&
427
432
  options.timeoutMs < CHECK_TIMEOUT_MS
428
433
  ) {
@@ -0,0 +1,172 @@
1
+ import {
2
+ CustomerDbQueryOutcomeUnknownError,
3
+ DeeplineError,
4
+ } from '../errors.js';
5
+ import type { HttpClient } from '../http.js';
6
+ import type { CustomerDbQueryResult } from '../types.js';
7
+
8
+ export type CustomerDbQueryOptions = {
9
+ sql: string;
10
+ maxRows?: number;
11
+ /** Reuse only to recover the original statement and options. */
12
+ operationKey?: string;
13
+ };
14
+
15
+ export type CustomerDbQueryPlan = {
16
+ request: {
17
+ method: 'POST';
18
+ path: '/api/v2/db/query';
19
+ body: { sql: string; max_rows?: number; operation_key?: string };
20
+ };
21
+ effects: {
22
+ cloudMutations: 'statement_dependent';
23
+ localWrites: 'none';
24
+ creditSpending: 'none';
25
+ recovery: 'original_operation_key' | 'unkeyed_unknown_outcome';
26
+ };
27
+ transport: { maxRetries: 0; urlFailover: 'disabled' };
28
+ };
29
+
30
+ /** Validate and describe SQL execution without sending it. */
31
+ export function planCustomerDbQuery(
32
+ input: CustomerDbQueryOptions,
33
+ ): CustomerDbQueryPlan {
34
+ if (typeof input.sql !== 'string' || !input.sql.trim())
35
+ throw new DeeplineError('sql must not be empty.', 400, 'INVALID_SQL');
36
+ if (
37
+ input.operationKey !== undefined &&
38
+ typeof input.operationKey !== 'string'
39
+ )
40
+ throw new DeeplineError(
41
+ 'operationKey must be a string containing 1–512 characters.',
42
+ 400,
43
+ 'INVALID_OPERATION_KEY',
44
+ );
45
+ // An operation key is an opaque identity shared with REST and tool callers.
46
+ // Trim only to reject blank input; changing a valid key creates new intent.
47
+ const operationKey = input.operationKey;
48
+ if (
49
+ operationKey !== undefined &&
50
+ (!operationKey.trim() || operationKey.length > 512)
51
+ ) {
52
+ throw new DeeplineError(
53
+ 'operationKey must contain 1–512 characters.',
54
+ 400,
55
+ 'INVALID_OPERATION_KEY',
56
+ );
57
+ }
58
+ if (
59
+ input.maxRows !== undefined &&
60
+ (!Number.isSafeInteger(input.maxRows) ||
61
+ input.maxRows < 1 ||
62
+ input.maxRows > 1000)
63
+ ) {
64
+ throw new DeeplineError(
65
+ 'maxRows must be a whole number from 1 to 1000.',
66
+ 400,
67
+ 'INVALID_MAX_ROWS',
68
+ );
69
+ }
70
+ return {
71
+ request: {
72
+ method: 'POST',
73
+ path: '/api/v2/db/query',
74
+ body: {
75
+ sql: input.sql,
76
+ ...(input.maxRows !== undefined ? { max_rows: input.maxRows } : {}),
77
+ ...(operationKey !== undefined ? { operation_key: operationKey } : {}),
78
+ },
79
+ },
80
+ effects: {
81
+ cloudMutations: 'statement_dependent',
82
+ localWrites: 'none',
83
+ creditSpending: 'none',
84
+ recovery:
85
+ operationKey === undefined
86
+ ? 'unkeyed_unknown_outcome'
87
+ : 'original_operation_key',
88
+ },
89
+ transport: {
90
+ maxRetries: 0,
91
+ urlFailover: 'disabled',
92
+ },
93
+ };
94
+ }
95
+
96
+ export async function queryCustomerDatabase(
97
+ http: HttpClient,
98
+ input: CustomerDbQueryOptions,
99
+ ): Promise<CustomerDbQueryResult> {
100
+ const plan = planCustomerDbQuery(input);
101
+ let result: CustomerDbQueryResult;
102
+ try {
103
+ result = await http.post<CustomerDbQueryResult>(
104
+ plan.request.path,
105
+ plan.request.body,
106
+ undefined,
107
+ {
108
+ maxRetries: plan.transport.maxRetries,
109
+ exactUrlOnly: plan.transport.urlFailover === 'disabled',
110
+ },
111
+ );
112
+ } catch (error) {
113
+ if (
114
+ error instanceof DeeplineError &&
115
+ (error.code?.startsWith('NETWORK_') ||
116
+ // Older API readers return PostgreSQL errors as HTTP 400, including
117
+ // lost connections and explicitly unknown transaction resolution.
118
+ /^08[A-Z0-9]{3}$/.test(error.code ?? '') ||
119
+ ['57P01', '57P02', '57P03'].includes(error.code ?? '') ||
120
+ error.statusCode === 408 ||
121
+ (error.statusCode ?? 0) >= 500)
122
+ ) {
123
+ throw new CustomerDbQueryOutcomeUnknownError(
124
+ error,
125
+ plan.request.body.operation_key,
126
+ );
127
+ }
128
+ throw error;
129
+ }
130
+ if (
131
+ !result ||
132
+ typeof result !== 'object' ||
133
+ Array.isArray(result) ||
134
+ typeof result.command !== 'string' ||
135
+ !Array.isArray(result.columns) ||
136
+ !Array.isArray(result.rows) ||
137
+ typeof result.truncated !== 'boolean' ||
138
+ (result.row_count !== null &&
139
+ (!Number.isSafeInteger(result.row_count) || result.row_count < 0)) ||
140
+ !Number.isSafeInteger(result.row_count_returned) ||
141
+ result.row_count_returned < 0
142
+ ) {
143
+ throw new CustomerDbQueryOutcomeUnknownError(
144
+ new DeeplineError(
145
+ 'The SQL response did not contain a valid result.',
146
+ 200,
147
+ 'CUSTOMER_DB_QUERY_RESPONSE_INVALID',
148
+ ),
149
+ plan.request.body.operation_key,
150
+ );
151
+ }
152
+ const operation = result.operation;
153
+ if (
154
+ input.operationKey !== undefined &&
155
+ (!operation ||
156
+ operation.operation_key !== input.operationKey ||
157
+ !Number.isSafeInteger(operation.completed_at_ms) ||
158
+ operation.completed_at_ms < 0 ||
159
+ !['executed', 'operation_recovery'].includes(operation.source))
160
+ ) {
161
+ throw new CustomerDbQueryOutcomeUnknownError(
162
+ new DeeplineError(
163
+ 'The server did not confirm the original atomic SQL operation.',
164
+ 200,
165
+ 'CUSTOMER_DB_OPERATION_ACK_INVALID',
166
+ ),
167
+ input.operationKey,
168
+ { recoveryAvailable: false },
169
+ );
170
+ }
171
+ return { ...result, scope: { kind: 'database', mutability: 'current' } };
172
+ }
@@ -18,6 +18,41 @@ import {
18
18
  type ToolExecutionPublicDetails,
19
19
  } from '../../shared_libs/plays/tool-execution-error';
20
20
 
21
+ /** SQL may have committed, but its response was not confirmed. */
22
+ export class CustomerDbQueryOutcomeUnknownError extends DeeplineError {
23
+ declare readonly cause: DeeplineError;
24
+ readonly outcome = 'unknown' as const;
25
+ readonly operationKey?: string;
26
+ readonly retryable: boolean;
27
+
28
+ constructor(
29
+ cause: DeeplineError,
30
+ operationKey?: string,
31
+ options: { recoveryAvailable?: boolean } = {},
32
+ ) {
33
+ const recoveryAvailable =
34
+ operationKey !== undefined && options.recoveryAvailable !== false;
35
+ super(
36
+ operationKey === undefined
37
+ ? 'SQL outcome is unknown. The unkeyed request was attempted once; inspect the database before issuing another write. An operation key added afterwards cannot recover this request.'
38
+ : recoveryAvailable
39
+ ? 'SQL outcome is unknown. Recover by submitting the same SQL and options with the original operation key; do not use a new key.'
40
+ : 'SQL outcome is unknown. The server did not confirm atomic recovery support. Do not resubmit this write; inspect the database and confirm reader support before recovering with the original operation key.',
41
+ cause.statusCode,
42
+ 'CUSTOMER_DB_QUERY_OUTCOME_UNKNOWN',
43
+ {
44
+ outcome: 'unknown',
45
+ recovery: recoveryAvailable ? 'original_operation_key' : 'unavailable',
46
+ causeCode: cause.code,
47
+ },
48
+ );
49
+ this.name = 'CustomerDbQueryOutcomeUnknownError';
50
+ this.operationKey = operationKey;
51
+ this.retryable = recoveryAvailable;
52
+ Object.defineProperty(this, 'cause', { value: cause, configurable: true });
53
+ }
54
+ }
55
+
21
56
  export {
22
57
  DeeplineError,
23
58
  ProviderTransientError,
@@ -41,6 +41,7 @@ export type {
41
41
  * export default definePlay('my-play', async (ctx, input: { domain: string }) => {
42
42
  * ctx.log(`Looking up ${input.domain}`);
43
43
  * const company = await ctx.tools.execute({
44
+ * staleAfterSeconds: 0,
44
45
  * id: 'company_search',
45
46
  * tool: 'test_company_search',
46
47
  * input: { domain: input.domain },
@@ -76,6 +77,17 @@ export {
76
77
  MONITOR_JOB_RECONCILIATION_STATES,
77
78
  MONITOR_JOB_STATES,
78
79
  } from './client.js';
80
+ export type {
81
+ CustomerDbQueryOptions,
82
+ CustomerDbQueryPlan,
83
+ } from './db/query.js';
84
+ export { planCustomerDbQuery } from './db/query.js';
85
+ export type { DeeplineToolCallOptions } from './play.js';
86
+ export {
87
+ planLocalPlayExecution,
88
+ pinLocalPlayImports,
89
+ } from './plays/local-play-execution.js';
90
+ export type { LocalPlayGraph } from './plays/local-play-execution.js';
79
91
  export { CtxFetchHttpError } from './play.js';
80
92
  export { RunObserveTransportUnavailableError } from './runs/observe-transport.js';
81
93
  export { RunEventQueryInputError } from '../../shared_libs/play-runtime/run-event-query';
@@ -258,6 +270,7 @@ export {
258
270
  // ——— Errors ———
259
271
  export {
260
272
  DeeplineError,
273
+ CustomerDbQueryOutcomeUnknownError,
261
274
  ProviderTransientError,
262
275
  ToolExecutionError,
263
276
  getProviderUnavailableReason,
@@ -29,6 +29,7 @@
29
29
  * export default definePlay('my-play', async (ctx, input: { domain: string }) => {
30
30
  * ctx.log(`Looking up ${input.domain}`);
31
31
  * const company = await ctx.tools.execute({
32
+ * staleAfterSeconds: 0,
32
33
  * id: 'company_search',
33
34
  * tool: 'test_company_search',
34
35
  * input: { domain: input.domain },
@@ -59,6 +60,7 @@
59
60
  *
60
61
  * export default definePlay('daily-sync', async (ctx) => {
61
62
  * const data = await ctx.tools.execute({
63
+ * staleAfterSeconds: 0,
62
64
  * id: 'crm_export',
63
65
  * tool: 'crm_export',
64
66
  * input: {},
@@ -115,6 +117,7 @@ import type {
115
117
  ExecutionRecovery,
116
118
  ToolExecution,
117
119
  } from './client.js';
120
+ import type { ExecuteToolRawOptions } from './tool-calls.js';
118
121
  import type {
119
122
  DurableCallStaleAfterSeconds,
120
123
  PlayAuthoringBindings,
@@ -638,6 +641,12 @@ export interface DeeplineNamedPlay<
638
641
  ): Promise<TOutput>;
639
642
  }
640
643
 
644
+ /** Per-call HTTP deadline and recovery identity for a direct tool operation. */
645
+ export type DeeplineToolCallOptions = Pick<
646
+ ExecuteToolRawOptions,
647
+ 'timeout' | 'idempotencyKey' | 'recover' | 'onExecution' | 'recoveryTimeoutMs'
648
+ >;
649
+
641
650
  /**
642
651
  * Tool/provider operations available from a connected {@link DeeplineContext}.
643
652
  *
@@ -652,6 +661,12 @@ export type DeeplineToolsNamespace = {
652
661
  list(): Promise<ToolDefinition[]>;
653
662
  /** Get detailed metadata for one provider-backed tool. */
654
663
  get(toolId: string): Promise<ToolMetadata>;
664
+ /** Call one tool. A key or recover enables same-execution recovery after a lost response. */
665
+ call(
666
+ toolId: string,
667
+ input: Record<string, unknown>,
668
+ options?: DeeplineToolCallOptions,
669
+ ): Promise<DeeplineToolExecuteResult>;
655
670
  /**
656
671
  * Execute a provider-backed tool from a regular SDK process.
657
672
  *
@@ -661,14 +676,7 @@ export type DeeplineToolsNamespace = {
661
676
  execute(
662
677
  toolId: string,
663
678
  input: Record<string, unknown>,
664
- options?: {
665
- idempotencyKey?: string;
666
- recover?: boolean;
667
- onExecution?: (execution: {
668
- idempotencyKey: string;
669
- }) => void | Promise<void>;
670
- recoveryTimeoutMs?: number;
671
- },
679
+ options?: DeeplineToolCallOptions,
672
680
  ): Promise<DeeplineToolExecuteResult>;
673
681
  };
674
682
 
@@ -1100,35 +1108,30 @@ export class DeeplineContext {
1100
1108
  * ```
1101
1109
  */
1102
1110
  get tools(): DeeplineToolsNamespace {
1111
+ const call: DeeplineToolsNamespace['call'] = async (
1112
+ toolId,
1113
+ input,
1114
+ options,
1115
+ ) => {
1116
+ const response = await this.client.executeTool(toolId, input, {
1117
+ includeToolMetadata: true,
1118
+ responseIntent: 'dataset',
1119
+ ...options,
1120
+ });
1121
+ return toolExecutionEnvelopeToResult(toolId, response, {
1122
+ client: this.client,
1123
+ input,
1124
+ });
1125
+ };
1103
1126
  return {
1104
1127
  /** List all available tools. */
1105
1128
  list: (): Promise<ToolDefinition[]> => this.client.listTools(),
1106
1129
  /** Get detailed metadata for a tool. */
1107
1130
  get: (toolId: string): Promise<ToolMetadata> =>
1108
1131
  this.client.getTool(toolId),
1109
- /** Execute a tool and return the standard execution envelope. */
1110
- execute: async (
1111
- toolId: string,
1112
- input: Record<string, unknown>,
1113
- options?: {
1114
- idempotencyKey?: string;
1115
- recover?: boolean;
1116
- onExecution?: (execution: {
1117
- idempotencyKey: string;
1118
- }) => void | Promise<void>;
1119
- recoveryTimeoutMs?: number;
1120
- },
1121
- ): Promise<DeeplineToolExecuteResult> => {
1122
- const response = await this.client.executeTool(toolId, input, {
1123
- includeToolMetadata: true,
1124
- responseIntent: 'dataset',
1125
- ...options,
1126
- });
1127
- return toolExecutionEnvelopeToResult(toolId, response, {
1128
- client: this.client,
1129
- input,
1130
- });
1131
- },
1132
+ call,
1133
+ /** Compatibility spelling for the same tool operation. */
1134
+ execute: call,
1132
1135
  };
1133
1136
  }
1134
1137
 
@@ -0,0 +1,13 @@
1
+ import { dirname, isAbsolute, join, relative } from 'node:path';
2
+
3
+ /** Transport a child path in its importing artifact's source identity frame. */
4
+ export function playAuthoringGraphPath(
5
+ parent: { filePath: string; artifact: { entryFile: string } },
6
+ filePath: string,
7
+ ): string {
8
+ if (isAbsolute(parent.artifact.entryFile)) return filePath;
9
+ return join(
10
+ dirname(parent.artifact.entryFile),
11
+ relative(dirname(parent.filePath), filePath),
12
+ ).replaceAll('\\', '/');
13
+ }
@@ -141,7 +141,7 @@ export function createSdkPlayBundlingAdapter(): PlayBundlingAdapter {
141
141
 
142
142
  export async function bundlePlayFile(
143
143
  filePath: string,
144
- options: BundlePlayFileOptions = {},
144
+ options: BundlePlayFileOptions & { cache?: boolean } = {},
145
145
  ): Promise<BundledPlayFileResult> {
146
146
  // The SDK sends this graph to a remote checker/runtime. Its file identities
147
147
  // therefore must describe the authoring workspace, rather than the local
@@ -159,6 +159,7 @@ export async function bundlePlayFile(
159
159
  adapter: {
160
160
  ...createSdkPlayBundlingAdapter(),
161
161
  sourceIdentityRoot,
162
+ ...(options.cache === false ? { cacheDir: null } : {}),
162
163
  },
163
164
  });
164
165
  if (result.success)