deepline 0.1.265 → 0.1.267
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/compat.ts +3 -1
- package/dist/bundling-sources/sdk/src/release.ts +63 -10
- package/dist/bundling-sources/sdk/src/types.ts +58 -0
- package/dist/bundling-sources/sdk/src/version.ts +5 -1
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +38 -7
- package/dist/bundling-sources/shared_libs/play-runtime/csv-rename.ts +50 -4
- package/dist/bundling-sources/shared_libs/play-runtime/dataset-lifecycle-log.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/secret-resolution-retry-policy.ts +6 -0
- package/dist/cli/index.js +142 -42
- package/dist/cli/index.mjs +142 -42
- package/dist/index.d.mts +57 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +27 -3
- package/dist/index.mjs +27 -3
- package/package.json +3 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDK_API_CONTRACT, SDK_VERSION } from './version.js';
|
|
1
|
+
import { SDK_API_CONTRACT, SDK_API_MAJOR, SDK_VERSION } from './version.js';
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
@@ -87,6 +87,7 @@ function compatibilityCacheKey(
|
|
|
87
87
|
baseUrl: baseUrl.replace(/\/$/, ''),
|
|
88
88
|
version: SDK_VERSION,
|
|
89
89
|
apiContract: SDK_API_CONTRACT,
|
|
90
|
+
apiMajor: SDK_API_MAJOR,
|
|
90
91
|
command: command?.trim() || null,
|
|
91
92
|
skillsVersion: skillsVersion ?? null,
|
|
92
93
|
});
|
|
@@ -186,6 +187,7 @@ export async function checkSdkCompatibility(
|
|
|
186
187
|
headers: {
|
|
187
188
|
'User-Agent': `deepline-ts-sdk/${SDK_VERSION}`,
|
|
188
189
|
'X-Deepline-SDK-Version': SDK_VERSION,
|
|
190
|
+
'X-Deepline-API-Major': String(SDK_API_MAJOR),
|
|
189
191
|
'X-Deepline-API-Contract': SDK_API_CONTRACT,
|
|
190
192
|
},
|
|
191
193
|
signal: controller.signal,
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Edit THIS file by hand only for deliberate release decisions:
|
|
14
14
|
* - minor/major version bumps (set `version`),
|
|
15
|
-
* -
|
|
15
|
+
* - API-major cutovers (set `contracts.api.currentMajor`; leave `version` to the
|
|
16
|
+
* publish-time patch selector),
|
|
16
17
|
* - support-window moves (`minimumSupported` / `deprecatedBelow`).
|
|
17
|
-
* The automation never touches
|
|
18
|
+
* The automation never touches API compatibility policy, `minimumSupported`, or
|
|
18
19
|
* `deprecatedBelow`.
|
|
19
20
|
*
|
|
20
21
|
* Everything else derives from these values:
|
|
@@ -35,6 +36,37 @@
|
|
|
35
36
|
|
|
36
37
|
export type SdkReleaseChannel = 'latest' | 'next' | 'beta';
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The named public protocols. These are intentionally independent:
|
|
41
|
+
*
|
|
42
|
+
* - `api` is the HTTP SDK/CLI protocol. It is additive within a major.
|
|
43
|
+
* - `playArtifact` is the immutable client-bundled Play payload ABI.
|
|
44
|
+
* - `release` controls promotion/publishing; it is not a client protocol.
|
|
45
|
+
*
|
|
46
|
+
* Do not use an SDK package version or a date string as an artifact ABI.
|
|
47
|
+
*/
|
|
48
|
+
export type DeeplineContractPolicy = {
|
|
49
|
+
api: {
|
|
50
|
+
name: 'sdk-http-api';
|
|
51
|
+
currentMajor: number;
|
|
52
|
+
supportedMajors: readonly number[];
|
|
53
|
+
/** Transitional value for installed SDKs that only send the old header. */
|
|
54
|
+
legacyWireIds: readonly string[];
|
|
55
|
+
};
|
|
56
|
+
playArtifact: {
|
|
57
|
+
name: 'play-artifact-runtime';
|
|
58
|
+
currentVersion: number;
|
|
59
|
+
supportedVersions: readonly number[];
|
|
60
|
+
};
|
|
61
|
+
release: {
|
|
62
|
+
name: 'production-sdk-release';
|
|
63
|
+
/** npm may publish only from the active, healthy Production SHA. */
|
|
64
|
+
publishFrom: 'latest-successful-production-deployment';
|
|
65
|
+
/** A newer merge cancels an in-flight decision; reconciliation picks the last healthy SHA. */
|
|
66
|
+
coalesce: 'latest-healthy';
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
38
70
|
export type SdkSupportPolicy = {
|
|
39
71
|
/**
|
|
40
72
|
* Anything strictly below this returns `status: "unsupported"` from
|
|
@@ -57,6 +89,8 @@ export type SdkSupportPolicy = {
|
|
|
57
89
|
minimumSupported: string;
|
|
58
90
|
reason: string;
|
|
59
91
|
}>;
|
|
92
|
+
/** Previously published wire contracts that remain supported. */
|
|
93
|
+
compatibleApiContracts?: readonly string[];
|
|
60
94
|
/**
|
|
61
95
|
* Published package versions that must keep working for direct SDK tool
|
|
62
96
|
* callers. CI installs each package from npm and exercises `tools.get` and
|
|
@@ -77,12 +111,8 @@ export type SdkRelease = {
|
|
|
77
111
|
* publish time (auto-bump); edit by hand only for minor/major releases.
|
|
78
112
|
*/
|
|
79
113
|
version: string;
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
* changes between the installed SDK/CLI and the Deepline backend.
|
|
83
|
-
* See `docs/sdk-runtime-compatibility.md`.
|
|
84
|
-
*/
|
|
85
|
-
apiContract: string;
|
|
114
|
+
/** Named compatibility policies. This is the only authored contract policy. */
|
|
115
|
+
contracts: DeeplineContractPolicy;
|
|
86
116
|
/** Public support policy reported by `/api/v2/sdk/compat`. */
|
|
87
117
|
supportPolicy: SdkSupportPolicy;
|
|
88
118
|
};
|
|
@@ -125,8 +155,31 @@ export const SDK_RELEASE = {
|
|
|
125
155
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
126
156
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
127
157
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
128
|
-
version: '0.1.
|
|
129
|
-
|
|
158
|
+
version: '0.1.267',
|
|
159
|
+
contracts: {
|
|
160
|
+
api: {
|
|
161
|
+
name: 'sdk-http-api',
|
|
162
|
+
// API v2 is append-only. A breaking public request/response change needs
|
|
163
|
+
// v3 and an explicit v2 support-window decision, never a patch release.
|
|
164
|
+
currentMajor: 2,
|
|
165
|
+
supportedMajors: [2],
|
|
166
|
+
// Accepted only to bridge SDKs released before X-Deepline-API-Major.
|
|
167
|
+
legacyWireIds: [
|
|
168
|
+
'2026-07-admin-cli-local-cutover',
|
|
169
|
+
'2026-07-native-monitor-launch-hard-cutover',
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
playArtifact: {
|
|
173
|
+
name: 'play-artifact-runtime',
|
|
174
|
+
currentVersion: 2,
|
|
175
|
+
supportedVersions: [1, 2],
|
|
176
|
+
},
|
|
177
|
+
release: {
|
|
178
|
+
name: 'production-sdk-release',
|
|
179
|
+
publishFrom: 'latest-successful-production-deployment',
|
|
180
|
+
coalesce: 'latest-healthy',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
130
183
|
supportPolicy: {
|
|
131
184
|
minimumSupported: '0.1.53',
|
|
132
185
|
deprecatedBelow: '0.1.219',
|
|
@@ -677,6 +677,64 @@ export interface PlayStatus {
|
|
|
677
677
|
};
|
|
678
678
|
/** Exact ordinary `plays run` command that can rerun a failed execution. */
|
|
679
679
|
rerunCommand?: string;
|
|
680
|
+
/**
|
|
681
|
+
* Projected settled-charge billing for the run. Returned by `runs.get`.
|
|
682
|
+
* `totalCredits`/`providerEvents` describe THIS run only; `rollup` (present
|
|
683
|
+
* with `--full`) carries the true subtree cost including ctx.runPlay children.
|
|
684
|
+
* Deepline credits only — provider spend is never exposed.
|
|
685
|
+
*/
|
|
686
|
+
billing?: RunBillingSummary;
|
|
687
|
+
/**
|
|
688
|
+
* True subtree cost in Deepline credits (this run + every descendant run),
|
|
689
|
+
* mirrored to the top level for convenience. Present only with `--full`.
|
|
690
|
+
*/
|
|
691
|
+
billingTotalCreditsRollup?: number;
|
|
692
|
+
/** Deepline credits attributable to descendant runs only. Present with `--full`. */
|
|
693
|
+
billingChildCredits?: number;
|
|
694
|
+
/** True when the child-run billing rollup could not be fully resolved. */
|
|
695
|
+
billingRollupIncomplete?: boolean;
|
|
696
|
+
/** Durable summaries of ctx.runPlay children, returned by `runs.get --full`. */
|
|
697
|
+
childRuns?: ChildRunSummary[];
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/** One ctx.runPlay child run exposed on the parent's `--full` payload. */
|
|
701
|
+
export interface ChildRunSummary {
|
|
702
|
+
runId: string;
|
|
703
|
+
playName?: string | null;
|
|
704
|
+
status: string;
|
|
705
|
+
parentRunId?: string | null;
|
|
706
|
+
rootRunId?: string | null;
|
|
707
|
+
createdAt?: number | null;
|
|
708
|
+
startedAt?: number | null;
|
|
709
|
+
finishedAt?: number | null;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Rolled-up billing for a run subtree, projected from settled Charge Lifecycle
|
|
714
|
+
* facts. Deepline credits only — never provider spend.
|
|
715
|
+
*/
|
|
716
|
+
export interface RunBillingSummary {
|
|
717
|
+
runId: string;
|
|
718
|
+
/** THIS run's own charges (parent-only; excludes descendant runs). */
|
|
719
|
+
totalCalls: number;
|
|
720
|
+
totalCredits: number;
|
|
721
|
+
providerEvents: number;
|
|
722
|
+
computeEvents: number;
|
|
723
|
+
/** Subtree rollup including descendant ctx.runPlay runs. Present with `--full`. */
|
|
724
|
+
rollup?: {
|
|
725
|
+
totalCreditsRollup: number;
|
|
726
|
+
childCredits: number;
|
|
727
|
+
ownCredits: number;
|
|
728
|
+
totalCallsRollup: number;
|
|
729
|
+
providerEventsRollup: number;
|
|
730
|
+
computeEventsRollup: number;
|
|
731
|
+
childProviderEvents: number;
|
|
732
|
+
childComputeEvents: number;
|
|
733
|
+
descendantRunCount: number;
|
|
734
|
+
rollupComplete: boolean;
|
|
735
|
+
rollupError?: string;
|
|
736
|
+
};
|
|
737
|
+
[key: string]: unknown;
|
|
680
738
|
}
|
|
681
739
|
|
|
682
740
|
export type LiveEventScope = 'play' | 'agent';
|
|
@@ -3,4 +3,8 @@
|
|
|
3
3
|
import { SDK_RELEASE } from './release.js';
|
|
4
4
|
|
|
5
5
|
export const SDK_VERSION: string = SDK_RELEASE.version;
|
|
6
|
-
|
|
6
|
+
/** Numbered SDK HTTP API major sent by current SDK/CLI clients. */
|
|
7
|
+
export const SDK_API_MAJOR: number = SDK_RELEASE.contracts.api.currentMajor;
|
|
8
|
+
/** @deprecated Transitional wire id for pre-major-header SDKs only. */
|
|
9
|
+
export const SDK_API_CONTRACT: string =
|
|
10
|
+
SDK_RELEASE.contracts.api.legacyWireIds[0] ?? `api-v${SDK_API_MAJOR}`;
|
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
isRetryableSecretResolutionStatus,
|
|
52
52
|
secretResolutionRetryDecision,
|
|
53
53
|
SECRET_RESOLUTION_MAX_ATTEMPTS,
|
|
54
|
+
SECRET_RESOLUTION_ATTEMPT_TIMEOUT_MS,
|
|
54
55
|
type SecretResolutionRetryDecision,
|
|
55
56
|
} from './secret-resolution-retry-policy';
|
|
56
57
|
import {
|
|
@@ -307,6 +308,16 @@ const TOOL_BATCH_COALESCE_WINDOW_MS = 5;
|
|
|
307
308
|
const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
|
|
308
309
|
const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
309
310
|
const DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000;
|
|
311
|
+
// Every runtime-API tool fetch needs a client-side deadline. Without one, a
|
|
312
|
+
// stalled execute request (e.g. a credential-less call whose gateway connection
|
|
313
|
+
// hangs before the fast 403 can return) leaves the row "1 in flight" for minutes
|
|
314
|
+
// until the outer run deadline, violating loud-failure. The integrations execute
|
|
315
|
+
// route caps server work at maxDuration=900s, so this ceiling sits just above it:
|
|
316
|
+
// a healthy server (including the fast INTEGRATION_CREDENTIALS_MISSING 403) always
|
|
317
|
+
// responds first, and only a genuinely stuck socket trips the abort — surfacing as
|
|
318
|
+
// a bounded, repairable transport failure that row-isolation settles per row
|
|
319
|
+
// instead of hanging the whole run.
|
|
320
|
+
const DEFAULT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000 + 30_000;
|
|
310
321
|
const FETCH_TRANSPORT_MAX_ATTEMPTS = 3;
|
|
311
322
|
const FETCH_TRANSPORT_RETRY_DELAY_MS = 100;
|
|
312
323
|
// cloudflared returns this branded HTML when its connection to the local app
|
|
@@ -493,13 +504,17 @@ export function resolveToolRuntimeTimeoutMs(
|
|
|
493
504
|
return Math.max(1, Math.ceil(requestedTimeoutMs));
|
|
494
505
|
}
|
|
495
506
|
const normalized = toolId.trim().toLowerCase();
|
|
507
|
+
// Long-inference tools keep their explicit 15-minute budget. Every other tool
|
|
508
|
+
// gets the default ceiling so no runtime-API fetch is ever unbounded — a
|
|
509
|
+
// missing-credential or otherwise stuck request fails loudly and fast within
|
|
510
|
+
// the deadline instead of hanging "1 in flight".
|
|
496
511
|
return normalized === 'deeplineagent' ||
|
|
497
512
|
normalized === 'deeplineagent_deeplineagent' ||
|
|
498
513
|
normalized === 'ai_inference' ||
|
|
499
514
|
normalized === 'deeplineagent_ai_inference' ||
|
|
500
515
|
normalized === 'aiinference'
|
|
501
516
|
? DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS
|
|
502
|
-
:
|
|
517
|
+
: DEFAULT_TOOL_RUNTIME_TIMEOUT_MS;
|
|
503
518
|
}
|
|
504
519
|
|
|
505
520
|
function isDeeplineDeveloperTunnelOrigin502(input: {
|
|
@@ -1586,6 +1601,10 @@ export class PlayContextImpl {
|
|
|
1586
1601
|
try {
|
|
1587
1602
|
response = await fetch(url, {
|
|
1588
1603
|
method: 'POST',
|
|
1604
|
+
// Bound the control-plane call so a stalled connection aborts and is
|
|
1605
|
+
// caught below as a transport failure instead of hanging the tool
|
|
1606
|
+
// call "1 in flight" forever.
|
|
1607
|
+
signal: AbortSignal.timeout(SECRET_RESOLUTION_ATTEMPT_TIMEOUT_MS),
|
|
1589
1608
|
headers: {
|
|
1590
1609
|
Authorization: `Bearer ${this.#options.executorToken}`,
|
|
1591
1610
|
'Content-Type': 'application/json',
|
|
@@ -5413,13 +5432,13 @@ export class PlayContextImpl {
|
|
|
5413
5432
|
this.rowStates.get(idx)?.results.set(fieldName, cellValue);
|
|
5414
5433
|
const currentCellMeta =
|
|
5415
5434
|
this.activeMapCellMeta?.get(rowKey)?.[fieldName];
|
|
5416
|
-
const
|
|
5435
|
+
const currentCellRecord =
|
|
5417
5436
|
currentCellMeta &&
|
|
5418
5437
|
typeof currentCellMeta === 'object' &&
|
|
5419
|
-
!Array.isArray(currentCellMeta)
|
|
5420
|
-
|
|
5421
|
-
? (currentCellMeta as { status?: unknown }).status
|
|
5438
|
+
!Array.isArray(currentCellMeta)
|
|
5439
|
+
? (currentCellMeta as { status?: unknown; reused?: unknown })
|
|
5422
5440
|
: null;
|
|
5441
|
+
const currentCellStatus = currentCellRecord?.status ?? null;
|
|
5423
5442
|
if (currentCellStatus === 'skipped') {
|
|
5424
5443
|
if (
|
|
5425
5444
|
shouldPersistMapCellField(fieldName) &&
|
|
@@ -5436,13 +5455,25 @@ export class PlayContextImpl {
|
|
|
5436
5455
|
}
|
|
5437
5456
|
continue;
|
|
5438
5457
|
}
|
|
5458
|
+
// A cell whose underlying durable work was fully satisfied from
|
|
5459
|
+
// content-addressed receipts recorded a `cached`/`reused` cell-meta
|
|
5460
|
+
// marker while the body ran (see resolveRequestsFromReceipt). Emitting
|
|
5461
|
+
// an unconditional `completed` here would clobber that marker to a
|
|
5462
|
+
// non-reused `completed`, so the run's per-column `cached` counter
|
|
5463
|
+
// reads 0 on a full-reuse rerun even though provider spend was 0.
|
|
5464
|
+
// Preserve the reuse signal so `columnStats.cached` reflects real
|
|
5465
|
+
// receipt reuse consistent with the near-zero provider spend.
|
|
5466
|
+
const cellWasReused =
|
|
5467
|
+
currentCellStatus === 'cached' &&
|
|
5468
|
+
currentCellRecord?.reused === true;
|
|
5439
5469
|
this.emitScopedFieldMetaUpdate({
|
|
5440
5470
|
rowId: idx,
|
|
5441
5471
|
key: rowKey,
|
|
5442
5472
|
tableNamespace: normalizedTableNamespace,
|
|
5443
5473
|
fieldName,
|
|
5444
|
-
status: 'completed',
|
|
5445
|
-
stage: 'completed',
|
|
5474
|
+
status: cellWasReused ? 'cached' : 'completed',
|
|
5475
|
+
stage: cellWasReused ? 'cached' : 'completed',
|
|
5476
|
+
...(cellWasReused ? { reused: true } : {}),
|
|
5446
5477
|
completedAt: Date.now(),
|
|
5447
5478
|
dataPatch: shouldPersistMapCellField(fieldName)
|
|
5448
5479
|
? { [fieldName]: cellValue }
|
|
@@ -44,6 +44,29 @@ function sourceAliases(target: string, aliases: string | readonly string[]) {
|
|
|
44
44
|
return [target, ...(Array.isArray(aliases) ? aliases : [aliases])];
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* `required` is a HEADER-presence guarantee, not a per-row non-null check.
|
|
49
|
+
*
|
|
50
|
+
* A required target is satisfied when at least one of its source aliases exists
|
|
51
|
+
* as a column in the CSV row (present in the header), regardless of whether this
|
|
52
|
+
* particular row's cell is blank. Blank cells in a present column are DATA, not a
|
|
53
|
+
* schema violation: they must flow through to the dataset so `onRowError` (or the
|
|
54
|
+
* play's own branching) governs them per row, never guillotine the whole run.
|
|
55
|
+
* Only a column that is entirely absent from the CSV is a `required` violation.
|
|
56
|
+
*/
|
|
57
|
+
function hasAliasColumnPresent(
|
|
58
|
+
lookup: Map<string, unknown>,
|
|
59
|
+
target: string,
|
|
60
|
+
sourceNames: string | readonly string[],
|
|
61
|
+
): boolean {
|
|
62
|
+
for (const alias of sourceAliases(target, sourceNames)) {
|
|
63
|
+
if (lookup.has(alias) || lookup.has(normalizeCsvHeader(alias))) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
47
70
|
export function applyCsvRenameProjection<T extends Record<string, unknown>>(
|
|
48
71
|
rows: readonly T[],
|
|
49
72
|
options?: CsvRenameOptions,
|
|
@@ -52,11 +75,26 @@ export function applyCsvRenameProjection<T extends Record<string, unknown>>(
|
|
|
52
75
|
...(options?.rename ?? {}),
|
|
53
76
|
...(options?.columns ?? {}),
|
|
54
77
|
};
|
|
78
|
+
const required = new Set(options?.required ?? []);
|
|
79
|
+
|
|
55
80
|
if (Object.keys(aliases).length === 0) {
|
|
81
|
+
// No rename/alias projection requested. `required` is still a
|
|
82
|
+
// header-presence guarantee: assert each required column exists in the CSV
|
|
83
|
+
// (checked against the first row's shape), then pass rows through untouched.
|
|
84
|
+
// A present-but-blank cell is data, never a `required` violation.
|
|
85
|
+
if (required.size > 0 && rows.length > 0) {
|
|
86
|
+
const lookup = buildRowLookup(rows[0]!);
|
|
87
|
+
for (const target of required) {
|
|
88
|
+
if (!hasAliasColumnPresent(lookup, target, target)) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`ctx.csv(..., { required }) is missing required column "${target}". ` +
|
|
91
|
+
`Add a "${target}" column to the CSV header.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
56
96
|
return [...rows];
|
|
57
97
|
}
|
|
58
|
-
|
|
59
|
-
const required = new Set(options?.required ?? []);
|
|
60
98
|
return rows.map((row, index) => {
|
|
61
99
|
const lookup = buildRowLookup(row);
|
|
62
100
|
const projectedFields = new Set<string>();
|
|
@@ -88,9 +126,17 @@ export function applyCsvRenameProjection<T extends Record<string, unknown>>(
|
|
|
88
126
|
} else {
|
|
89
127
|
projected[target] = selected;
|
|
90
128
|
}
|
|
91
|
-
} else if (
|
|
129
|
+
} else if (
|
|
130
|
+
required.has(target) &&
|
|
131
|
+
!hasAliasColumnPresent(lookup, target, sourceNames)
|
|
132
|
+
) {
|
|
133
|
+
// The column is entirely absent from the CSV header — a schema/config
|
|
134
|
+
// error that is identical for every row. A present-but-blank cell is
|
|
135
|
+
// data and must NOT trip this: it flows through so onRowError can
|
|
136
|
+
// isolate that row instead of failing the whole run.
|
|
92
137
|
throw new Error(
|
|
93
|
-
`ctx.csv(..., {
|
|
138
|
+
`ctx.csv(..., { required }) is missing required column "${target}". ` +
|
|
139
|
+
`Add a "${target}" column (or one of its aliases) to the CSV header.`,
|
|
94
140
|
);
|
|
95
141
|
}
|
|
96
142
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type DatasetLogIdentity = {
|
|
2
|
+
path: string;
|
|
3
|
+
tableNamespace: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Dataset paths identify runtime state. They are not CLI export selectors: a
|
|
8
|
+
* returned result field (for example `result.rows`) is the supported export
|
|
9
|
+
* handle. Keep this distinction explicit in operator logs.
|
|
10
|
+
*/
|
|
11
|
+
export function formatDatasetRegistrationLog(input: {
|
|
12
|
+
dataset: DatasetLogIdentity;
|
|
13
|
+
rows: number;
|
|
14
|
+
}): string {
|
|
15
|
+
if (input.rows === 0) {
|
|
16
|
+
return `Dataset ${input.dataset.path} registered (0 rows); export unavailable: empty dataset`;
|
|
17
|
+
}
|
|
18
|
+
return `Dataset ${input.dataset.path} registered (${input.rows} rows); awaiting terminal persistence`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function formatDatasetAvailabilityLog(input: {
|
|
22
|
+
runId: string;
|
|
23
|
+
dataset: DatasetLogIdentity;
|
|
24
|
+
persistedRows: number;
|
|
25
|
+
}): string {
|
|
26
|
+
if (input.persistedRows === 0) {
|
|
27
|
+
return `Dataset ${input.dataset.path} available: 0 persisted rows; export unavailable: empty dataset`;
|
|
28
|
+
}
|
|
29
|
+
return `Dataset ${input.dataset.path} available: ${input.persistedRows} persisted rows; inspect deepline runs get ${input.runId} --full --json for the verified export action`;
|
|
30
|
+
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export const SECRET_RESOLUTION_MAX_ATTEMPTS = 3;
|
|
2
2
|
export const SECRET_RESOLUTION_MAX_RETRY_AFTER_MS = 2_000;
|
|
3
|
+
// Per-attempt client deadline for the secret-resolution gateway call. This is an
|
|
4
|
+
// internal control-plane fetch (resolve a named secret), not provider work, so it
|
|
5
|
+
// must return quickly. Without a bound, a stalled connection hangs the tool call
|
|
6
|
+
// "1 in flight" indefinitely; an abort here is caught as a transport failure and
|
|
7
|
+
// retried/failed loudly via secretResolutionRetryDecision.
|
|
8
|
+
export const SECRET_RESOLUTION_ATTEMPT_TIMEOUT_MS = 30_000;
|
|
3
9
|
|
|
4
10
|
const SECRET_RESOLUTION_RETRY_JITTER_CAPS_MS = [100, 250] as const;
|
|
5
11
|
|