deepline 0.3.49 → 0.3.50

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.
@@ -199,7 +199,7 @@ export const SDK_RELEASE = {
199
199
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
- version: '0.3.49',
202
+ version: '0.3.50',
203
203
  updateSummary:
204
204
  'Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.',
205
205
  packageCapabilities: {
@@ -657,6 +657,8 @@ export interface PlayRunPackage {
657
657
  playName: string;
658
658
  status: string;
659
659
  dashboardUrl?: string;
660
+ /** Durable acceptance time: the run record was created. */
661
+ acceptedAt?: number | null;
660
662
  updatedAt?: number | null;
661
663
  startedAt?: number | null;
662
664
  finishedAt?: number | null;
@@ -652,6 +652,7 @@ function isRetryableAppRuntimeAction(
652
652
  action === 'create_signed_staged_file_url' ||
653
653
  action === 'get_runtime_step_receipt' ||
654
654
  action === 'get_runtime_step_receipts' ||
655
+ action === 'governor_budget_charge' ||
655
656
  action === 'heartbeat_runtime_step_receipts' ||
656
657
  action === 'claim_runtime_step_receipt' ||
657
658
  action === 'claim_runtime_step_receipts' ||
@@ -2040,8 +2040,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
2040
2040
  #options: ContextOptions;
2041
2041
  private readonly executionScope: RunExecutionScope;
2042
2042
  private logBuffer: string[] = [];
2043
- private fixtureProviderPacingBypassLogged = false;
2044
- private fixtureProviderPacingEnforcementLogged = false;
2045
2043
  private checkpoint: PlayCheckpoint;
2046
2044
  private readonly durableCallCacheEpochMs: number;
2047
2045
  /**
@@ -8698,13 +8696,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
8698
8696
  }
8699
8697
  }
8700
8698
 
8701
- private fixtureProviderPacingDisabled(): boolean {
8702
- return (
8703
- this.#options.integrationMode === 'fixture' &&
8704
- this.#options.enforceFixtureProviderPacing !== true
8705
- );
8706
- }
8707
-
8708
8699
  private toolDispatchLane(request: ToolCallRequest): {
8709
8700
  key: string;
8710
8701
  readyCount: number;
@@ -11065,12 +11056,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11065
11056
  this.governor.policy.concurrency.toolCalls,
11066
11057
  Math.max(
11067
11058
  1,
11068
- this.fixtureProviderPacingDisabled()
11069
- ? this.governor.policy.concurrency.toolCalls
11070
- : await this.resourceGovernor.suggestedToolParallelism(
11071
- toolId,
11072
- this.governor.policy.concurrency.toolCalls,
11073
- ),
11059
+ await this.resourceGovernor.suggestedToolParallelism(
11060
+ toolId,
11061
+ this.governor.policy.concurrency.toolCalls,
11062
+ ),
11074
11063
  ),
11075
11064
  );
11076
11065
  const dispatchOwned = async (
@@ -11226,7 +11215,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11226
11215
  const batchParallelismCeiling =
11227
11216
  this.governor.policy.pacing.workerToolBatchDefaultParallelism;
11228
11217
  const batchSize =
11229
- compiledBatches.length > 0 && !this.fixtureProviderPacingDisabled()
11218
+ compiledBatches.length > 0
11230
11219
  ? await this.resourceGovernor.suggestedToolParallelism(
11231
11220
  compiledBatches[0]!.batchOperation,
11232
11221
  batchParallelismCeiling,
@@ -12501,8 +12490,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
12501
12490
  const batchParallelismCeiling =
12502
12491
  this.governor.policy.pacing.workerToolBatchDefaultParallelism;
12503
12492
  const batchSize =
12504
- compiledBatches.length > 0 &&
12505
- !this.fixtureProviderPacingDisabled()
12493
+ compiledBatches.length > 0
12506
12494
  ? await this.resourceGovernor.suggestedToolParallelism(
12507
12495
  compiledBatches[0]!.batchOperation,
12508
12496
  batchParallelismCeiling,
@@ -12756,23 +12744,18 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
12756
12744
  void flushCompletionBuffer();
12757
12745
  }, 0);
12758
12746
  });
12759
- // Seed the dispatch width from the governor's provider-shaped
12760
- // parallelism instead of the flat policy.concurrency.toolCalls
12761
- // ceiling. The flat width launched every pending row at once into
12762
- // the pacer, so unhinted providers 429'd on the first burst before
12763
- // AIMD could halve the rate. The shaped estimate is derived from the
12764
- // provider's RPS/maxConcurrency pacing rules (see
12765
- // suggestedParallelism in governor.ts), floored at 1 and capped by
12766
- // the global tool-call concurrency ceiling. The pacer still gates
12767
- // each in-flight call, so this only trims the launch burst.
12747
+ // Bound direct map dispatch separately from ordinary provider
12748
+ // residency. This prevents a blocked first chunk from launching
12749
+ // another chunk ahead of a provider's admitted start rate, while
12750
+ // preserving the wider resident-call capacity used by batched and
12751
+ // high-latency providers.
12768
12752
  const toolCallConcurrencyCeiling =
12769
12753
  this.governor.policy.concurrency.toolCalls;
12770
- const shapedToolParallelism = this.fixtureProviderPacingDisabled()
12771
- ? toolCallConcurrencyCeiling
12772
- : await this.resourceGovernor.suggestedToolParallelism(
12773
- toolId,
12774
- toolCallConcurrencyCeiling,
12775
- );
12754
+ const shapedToolParallelism =
12755
+ await this.resourceGovernor.suggestedDirectToolParallelism(
12756
+ toolId,
12757
+ toolCallConcurrencyCeiling,
12758
+ );
12776
12759
  const dispatchWidth = Math.min(
12777
12760
  toolCallConcurrencyCeiling,
12778
12761
  Math.max(1, shapedToolParallelism),
@@ -13339,44 +13322,17 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
13339
13322
  // is the fetch itself, so independently delayed runners cannot
13340
13323
  // compress real provider arrivals after their tickets.
13341
13324
  const protectionHeaders = await this.vercelProtectionHeaders();
13342
- // Use the mode carried by this physical execution request.
13343
- // A restored execution scope may predate integration-mode
13344
- // authority metadata, while the signed launch and every tool
13345
- // request still carry options.integrationMode. Pacing the
13346
- // latter as live would make fixture runs both slow and
13347
- // unauditable even though the app never dispatches a provider
13348
- // request.
13325
+ // Fixture responses simulate provider residence, but provider
13326
+ // admission remains real. This makes fixture volume results a
13327
+ // faithful measurement of the runtime controller without
13328
+ // spending provider credits.
13349
13329
  const fixtureExecution =
13350
13330
  this.#options.integrationMode === 'fixture';
13351
- const enforceFixtureProviderPacing =
13352
- fixtureExecution &&
13353
- this.#options.enforceFixtureProviderPacing === true;
13354
- const fixtureOnlyExecution =
13355
- this.fixtureProviderPacingDisabled();
13356
- if (
13357
- fixtureOnlyExecution &&
13358
- !this.fixtureProviderPacingBypassLogged
13359
- ) {
13360
- this.fixtureProviderPacingBypassLogged = true;
13361
- this.log(
13362
- 'Fixture mode: provider pacing bypassed because no provider request is dispatched.',
13363
- );
13364
- }
13365
- if (
13366
- enforceFixtureProviderPacing &&
13367
- !this.fixtureProviderPacingEnforcementLogged
13368
- ) {
13369
- this.fixtureProviderPacingEnforcementLogged = true;
13370
- this.log(
13371
- 'Fixture mode: provider pacing explicitly enforced for production-parity testing.',
13372
- );
13373
- }
13374
- const providerPermit = fixtureOnlyExecution
13375
- ? { release() {} }
13376
- : await this.resourceGovernor.acquireProviderPermit({
13377
- toolId,
13378
- signal: abortController?.signal,
13379
- });
13331
+ const providerPermit =
13332
+ await this.resourceGovernor.acquireProviderPermit({
13333
+ toolId,
13334
+ signal: abortController?.signal,
13335
+ });
13380
13336
  try {
13381
13337
  // Provider admission is our queue, not provider execution.
13382
13338
  // Start the tool deadline only after admission so a busy
@@ -619,8 +619,6 @@ export interface ContextOptions {
619
619
  docflowEnabled?: boolean;
620
620
  /** Internal fixture-only simulation of provider response residence. */
621
621
  fixtureBehavior?: FixtureBehavior | null;
622
- /** Preview/dev test seam that applies provider pacing to fixture responses. */
623
- enforceFixtureProviderPacing?: boolean;
624
622
  /**
625
623
  * Server-validated per-run ceiling for concurrently resident provider-tool
626
624
  * executions and direct ctx.fetch calls. Omitted uses the platform default.
@@ -137,6 +137,15 @@ export interface PlayExecutionGovernor {
137
137
  */
138
138
  suggestedParallelism(toolId: string, fallback: number): Promise<number>;
139
139
 
140
+ /**
141
+ * Suggested resident width for direct, unbatched tool dispatch.
142
+ * Provider permits, not this queue width, govern outbound starts.
143
+ */
144
+ suggestedDirectToolParallelism(
145
+ toolId: string,
146
+ fallback: number,
147
+ ): Promise<number>;
148
+
140
149
  /** Increment a monotonic budget counter; throws GovernorBudgetError on breach. */
141
150
  chargeBudget(kind: BudgetKind, amount?: number): Promise<void>;
142
151
 
@@ -479,14 +488,43 @@ export function createPlayExecutionGovernor(
479
488
 
480
489
  async suggestedParallelism(toolId, fallback) {
481
490
  const pacing = await resolveAdaptivePacing(toolId);
482
- const limits = pacing.rules.flatMap((rule) =>
483
- rule.maxConcurrency != null
484
- ? [rule.requestsPerWindow, rule.maxConcurrency]
485
- : [rule.requestsPerWindow],
491
+ const concurrencyLimits = pacing.rules.flatMap((rule) =>
492
+ rule.maxConcurrency != null ? [rule.maxConcurrency] : [],
486
493
  );
494
+ // A provider that declares only RPS has no resident-call contract, so
495
+ // retain the caller's bounded envelope; the rate-state backend still
496
+ // governs every outbound start.
497
+ const widthLimits =
498
+ concurrencyLimits.length > 0 ? concurrencyLimits : [fallback];
487
499
  return Math.max(
488
500
  1,
489
- Math.min(policy.pacing.suggestedMaxParallelism, ...limits),
501
+ Math.min(
502
+ Math.max(1, fallback),
503
+ policy.pacing.suggestedMaxParallelism,
504
+ ...widthLimits,
505
+ ),
506
+ );
507
+ },
508
+
509
+ async suggestedDirectToolParallelism(toolId, fallback) {
510
+ const pacing = await resolveAdaptivePacing(toolId);
511
+ const concurrencyLimits = pacing.rules.flatMap((rule) =>
512
+ rule.maxConcurrency != null ? [rule.maxConcurrency] : [],
513
+ );
514
+ // The shared rate backend controls every outbound start. An RPS-only
515
+ // provider needs enough resident work to cover response residence; using
516
+ // requestsPerWindow as this width turns, for example, a 25-RPS provider
517
+ // with 4-second responses into a 6.25-RPS lane. Only an explicit provider
518
+ // concurrency contract may tighten the resident envelope.
519
+ const widthLimits =
520
+ concurrencyLimits.length > 0 ? concurrencyLimits : [fallback];
521
+ return Math.max(
522
+ 1,
523
+ Math.min(
524
+ Math.max(1, fallback),
525
+ policy.pacing.suggestedMaxParallelism,
526
+ ...widthLimits,
527
+ ),
490
528
  );
491
529
  },
492
530
 
@@ -615,6 +653,8 @@ function createInlineChildGovernor(
615
653
  root.acquireProviderPermit(toolId, opts),
616
654
  suggestedParallelism: (toolId, fallback) =>
617
655
  root.suggestedParallelism(toolId, fallback),
656
+ suggestedDirectToolParallelism: (toolId, fallback) =>
657
+ root.suggestedDirectToolParallelism(toolId, fallback),
618
658
  chargeBudget: (kind, amount) => root.chargeBudget(kind, amount),
619
659
  resolveRowConcurrency: (requested) => root.resolveRowConcurrency(requested),
620
660
  reportProviderBackpressure: async (input) =>
@@ -80,7 +80,11 @@ export interface ResolvedExecutionPolicy {
80
80
  }
81
81
 
82
82
  export const DEFAULT_MAX_CONCURRENT_EXTERNAL_CALLS = 64;
83
- export const MAX_CONFIGURABLE_CONCURRENT_EXTERNAL_CALLS = 256;
83
+ // A 1,000-row Play may legitimately need 1,000 resident provider calls to
84
+ // sustain a declared start rate while responses are slow. This is a validated
85
+ // opt-in ceiling, not the default transport load: short runtime-to-app fetches
86
+ // remain guarded independently by `integrationRequests` below.
87
+ export const MAX_CONFIGURABLE_CONCURRENT_EXTERNAL_CALLS = 1_000;
84
88
  export const MAX_CONFIGURABLE_CONCURRENT_ROWS = 1_000;
85
89
  // Dispatch groups are only a scheduler envelope. The external-call semaphore
86
90
  // remains the resource bound, so do not impose a lower hidden ceiling here.
@@ -146,7 +150,7 @@ export const SHARED_EXECUTION_POLICY: ResolvedExecutionPolicy = {
146
150
  rowMax: 1_000,
147
151
  // Global logical-call backstop. The default is intentionally close to the
148
152
  // standard row cohort so slow small responses do not serialize most rows.
149
- // Runs may request a value through the validated 1..256 launch contract;
153
+ // Runs may request a value through the validated 1..1000 launch contract;
150
154
  // provider pacing and the runner-owned hard ceiling still apply.
151
155
  toolCalls: DEFAULT_MAX_CONCURRENT_EXTERNAL_CALLS,
152
156
  // Physical runtime-to-app fetch/body admission. Keep short socket bursts
@@ -173,7 +177,11 @@ export const SHARED_EXECUTION_POLICY: ResolvedExecutionPolicy = {
173
177
  pacing: {
174
178
  // Undeclared providers; declared providers (rate-limit-definitions.ts) win.
175
179
  defaultProviderRequestsPerSecond: 10,
176
- suggestedMaxParallelism: 256,
180
+ // This is the scheduler's resident-call envelope, not an RPS target.
181
+ // Keep it aligned with the explicit run ceiling so an RPS-only provider
182
+ // can retain the calls required by its observed residence time. A declared
183
+ // provider maxConcurrency still tightens this per lane.
184
+ suggestedMaxParallelism: MAX_CONFIGURABLE_CONCURRENT_EXTERNAL_CALLS,
177
185
  // Worker isolate pacing knobs. The budget module owns platform accounting;
178
186
  // the Governor owns the policy values that decide when work is chunked.
179
187
  workerYieldElapsedMs: 45_000,
@@ -138,8 +138,6 @@ export interface PlayRunnerContextConfig {
138
138
  docflowEnabled?: boolean;
139
139
  /** Validated internal fixture-only provider response simulation. */
140
140
  fixtureBehavior?: FixtureBehavior | null;
141
- /** Preview/dev test seam that applies provider pacing to fixture responses. */
142
- enforceFixtureProviderPacing?: boolean;
143
141
  /** Validated per-run ceiling for provider-tool executions and ctx.fetch. */
144
142
  maxConcurrentExternalCalls?: number | null;
145
143
  maxConcurrentRows?: number | null;
@@ -60,6 +60,10 @@ export interface RuntimeResourceGovernor {
60
60
  signal?: AbortSignal;
61
61
  }): Promise<RuntimeResourceLease>;
62
62
  suggestedToolParallelism(toolId: string, fallback: number): Promise<number>;
63
+ suggestedDirectToolParallelism(
64
+ toolId: string,
65
+ fallback: number,
66
+ ): Promise<number>;
63
67
  resolveRowConcurrency(requested?: number): number;
64
68
  reportProviderBackpressure(input: {
65
69
  provider: string;
@@ -228,6 +232,13 @@ export function createRuntimeResourceGovernor(input: {
228
232
  return input.executionGovernor.suggestedParallelism(toolId, fallback);
229
233
  },
230
234
 
235
+ suggestedDirectToolParallelism(toolId, fallback) {
236
+ return input.executionGovernor.suggestedDirectToolParallelism(
237
+ toolId,
238
+ fallback,
239
+ );
240
+ },
241
+
231
242
  resolveRowConcurrency(requested) {
232
243
  return input.executionGovernor.resolveRowConcurrency(requested);
233
244
  },
@@ -36,8 +36,6 @@ type ValidatedRuntimeTestFaultHeader =
36
36
  export type RuntimeTestPolicyOverrides = {
37
37
  /** Opt-in bounded runner map latency profile for local/preview diagnosis. */
38
38
  mapLatencyProfile?: boolean;
39
- /** Exercise provider pacing during fixture runs without dispatching provider traffic. */
40
- enforceFixtureProviderPacing?: boolean;
41
39
  receiptLeaseTtlMs?: number;
42
40
  sheetAttemptLeaseMs?: number;
43
41
  heartbeatIntervalMs?: number;
@@ -258,8 +256,7 @@ function parseRuntimeTestPolicyOverrides(
258
256
  (key) =>
259
257
  !RUNTIME_TEST_POLICY_MS_FIELDS.has(key) &&
260
258
  key !== 'workBudgetYieldLimits' &&
261
- key !== 'mapLatencyProfile' &&
262
- key !== 'enforceFixtureProviderPacing',
259
+ key !== 'mapLatencyProfile',
263
260
  );
264
261
  if (unknownKeys.length > 0) {
265
262
  return {
@@ -276,16 +273,6 @@ function parseRuntimeTestPolicyOverrides(
276
273
  }
277
274
  overrides.mapLatencyProfile = record.mapLatencyProfile;
278
275
  }
279
- if ('enforceFixtureProviderPacing' in record) {
280
- if (typeof record.enforceFixtureProviderPacing !== 'boolean') {
281
- return {
282
- error:
283
- 'testPolicyOverrides.enforceFixtureProviderPacing must be a boolean.',
284
- };
285
- }
286
- overrides.enforceFixtureProviderPacing =
287
- record.enforceFixtureProviderPacing;
288
- }
289
276
  for (const field of RUNTIME_TEST_POLICY_MS_FIELDS) {
290
277
  if (!(field in record)) continue;
291
278
  const parsed = readPositiveIntegerField({
@@ -105,15 +105,25 @@ export type ToolResultReceipts = {
105
105
  }): Promise<void>;
106
106
  };
107
107
 
108
+ export type AlwaysFreshToolCallDispatch = {
109
+ call: ToolCallInput;
110
+ /** An always-fresh call must not claim a provider idempotency identity. */
111
+ providerOperationKey: null;
112
+ /** Receiptless means structurally absent, not a nullable lease. */
113
+ receipt?: never;
114
+ };
115
+
116
+ export type ReceiptBackedToolCallDispatch = {
117
+ call: ToolCallInput;
118
+ providerOperationKey: string;
119
+ receipt: ToolCallReceiptLease;
120
+ };
121
+
108
122
  /** Direct and map execution are Adapter choices, never separate public jobs. */
109
123
  export type ToolCallDispatcher = {
110
- dispatch(input: {
111
- call: ToolCallInput;
112
- /** Null means the adapter must not emit a provider-idempotency identity. */
113
- providerOperationKey: string | null;
114
- /** Null means this is a receiptless, always-fresh physical call. */
115
- receipt: ToolCallReceiptLease | null;
116
- }): Promise<ToolExecuteResult>;
124
+ dispatch(
125
+ input: AlwaysFreshToolCallDispatch | ReceiptBackedToolCallDispatch,
126
+ ): Promise<ToolExecuteResult>;
117
127
  };
118
128
 
119
129
  export type ToolCallDependencies = {
@@ -160,7 +160,6 @@ export function createToolCallJob(
160
160
  return await dependencies.dispatcher.dispatch({
161
161
  call: input,
162
162
  providerOperationKey: null,
163
- receipt: null,
164
163
  });
165
164
  }
166
165