deepline 0.1.91 → 0.1.93
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/cli/index.js +1333 -219
- package/dist/cli/index.mjs +1333 -219
- package/dist/index.d.mts +74 -5
- package/dist/index.d.ts +74 -5
- package/dist/index.js +1018 -62
- package/dist/index.mjs +1007 -62
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +87 -20
- package/dist/repo/apps/play-runner-workers/src/entry.ts +52 -14
- package/dist/repo/sdk/src/client.ts +289 -40
- package/dist/repo/sdk/src/index.ts +1 -0
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/runs/observe-transport.ts +481 -0
- package/dist/repo/sdk/src/stream-reconnect.ts +44 -0
- package/dist/repo/sdk/src/types.ts +10 -3
- package/dist/repo/shared_libs/play-runtime/live-events.ts +217 -0
- package/dist/repo/shared_libs/play-runtime/run-ledger.ts +1074 -0
- package/dist/repo/shared_libs/play-runtime/run-snapshot-stream.ts +581 -0
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -43,6 +53,7 @@ __export(src_exports, {
|
|
|
43
53
|
PLAY_BOOTSTRAP_TEMPLATES: () => PLAY_BOOTSTRAP_TEMPLATES,
|
|
44
54
|
PROD_URL: () => PROD_URL,
|
|
45
55
|
RateLimitError: () => RateLimitError,
|
|
56
|
+
RunObserveTransportUnavailableError: () => RunObserveTransportUnavailableError,
|
|
46
57
|
SDK_API_CONTRACT: () => SDK_API_CONTRACT,
|
|
47
58
|
SDK_VERSION: () => SDK_VERSION,
|
|
48
59
|
defineInput: () => defineInput,
|
|
@@ -246,10 +257,10 @@ var import_node_path2 = require("path");
|
|
|
246
257
|
|
|
247
258
|
// src/release.ts
|
|
248
259
|
var SDK_RELEASE = {
|
|
249
|
-
version: "0.1.
|
|
260
|
+
version: "0.1.93",
|
|
250
261
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
251
262
|
supportPolicy: {
|
|
252
|
-
latest: "0.1.
|
|
263
|
+
latest: "0.1.93",
|
|
253
264
|
minimumSupported: "0.1.53",
|
|
254
265
|
deprecatedBelow: "0.1.53"
|
|
255
266
|
}
|
|
@@ -604,6 +615,807 @@ function sleep(ms) {
|
|
|
604
615
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
605
616
|
}
|
|
606
617
|
|
|
618
|
+
// src/stream-reconnect.ts
|
|
619
|
+
var STREAM_RECONNECT_BASE_DELAY_MS = 500;
|
|
620
|
+
var STREAM_RECONNECT_MAX_DELAY_MS = 15e3;
|
|
621
|
+
var STREAM_HEALTHY_CONNECTION_MS = 3e4;
|
|
622
|
+
function streamReconnectDelayMs(attempt) {
|
|
623
|
+
const cappedExponentialMs = Math.min(
|
|
624
|
+
STREAM_RECONNECT_MAX_DELAY_MS,
|
|
625
|
+
STREAM_RECONNECT_BASE_DELAY_MS * 2 ** Math.max(0, attempt)
|
|
626
|
+
);
|
|
627
|
+
return Math.max(1, Math.floor(Math.random() * (cappedExponentialMs + 1)));
|
|
628
|
+
}
|
|
629
|
+
function isTransientPlayStreamError(error) {
|
|
630
|
+
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
631
|
+
return error.statusCode >= 500 && error.statusCode < 600;
|
|
632
|
+
}
|
|
633
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
634
|
+
return /auth validation backend timed out|fetch failed|eaddrnotavail|econnreset|etimedout|eai_again|socket hang up/i.test(
|
|
635
|
+
text
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// ../shared_libs/play-runtime/live-events.ts
|
|
640
|
+
function resolveTimingWindow(input) {
|
|
641
|
+
const startedAt = typeof input.startedAt === "number" && Number.isFinite(input.startedAt) ? input.startedAt : null;
|
|
642
|
+
const completedAt = typeof input.completedAt === "number" && Number.isFinite(input.completedAt) ? input.completedAt : null;
|
|
643
|
+
const updatedAt = typeof input.updatedAt === "number" && Number.isFinite(input.updatedAt) ? input.updatedAt : null;
|
|
644
|
+
return {
|
|
645
|
+
startedAt,
|
|
646
|
+
completedAt,
|
|
647
|
+
updatedAt
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// ../shared_libs/play-runtime/run-ledger.ts
|
|
652
|
+
var LOG_TAIL_LIMIT = 100;
|
|
653
|
+
function isRecord(value) {
|
|
654
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
655
|
+
}
|
|
656
|
+
function finiteNumber(value) {
|
|
657
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
658
|
+
}
|
|
659
|
+
function optionalFiniteNumber(value) {
|
|
660
|
+
const normalized = finiteNumber(value);
|
|
661
|
+
return normalized === null ? void 0 : normalized;
|
|
662
|
+
}
|
|
663
|
+
function optionalString(value) {
|
|
664
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
665
|
+
}
|
|
666
|
+
function optionalNullableString(value) {
|
|
667
|
+
if (value === null) return null;
|
|
668
|
+
return optionalString(value);
|
|
669
|
+
}
|
|
670
|
+
function normalizePlayRunLedgerStatus(value) {
|
|
671
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
672
|
+
switch (normalized) {
|
|
673
|
+
case "queued":
|
|
674
|
+
case "pending":
|
|
675
|
+
return "queued";
|
|
676
|
+
case "running":
|
|
677
|
+
case "started":
|
|
678
|
+
return "running";
|
|
679
|
+
case "waiting":
|
|
680
|
+
return "waiting";
|
|
681
|
+
case "completed":
|
|
682
|
+
case "complete":
|
|
683
|
+
case "succeeded":
|
|
684
|
+
return "completed";
|
|
685
|
+
case "failed":
|
|
686
|
+
case "error":
|
|
687
|
+
return "failed";
|
|
688
|
+
case "cancelled":
|
|
689
|
+
case "canceled":
|
|
690
|
+
return "cancelled";
|
|
691
|
+
case "terminated":
|
|
692
|
+
return "terminated";
|
|
693
|
+
case "timed_out":
|
|
694
|
+
case "timeout":
|
|
695
|
+
return "timed_out";
|
|
696
|
+
default:
|
|
697
|
+
return "unknown";
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function createEmptyPlayRunLedgerSnapshot(input) {
|
|
701
|
+
const status = normalizePlayRunLedgerStatus(input.status ?? "unknown");
|
|
702
|
+
const startedAt = finiteNumber(input.startedAt) ?? null;
|
|
703
|
+
const finishedAt = finiteNumber(input.finishedAt) ?? null;
|
|
704
|
+
return {
|
|
705
|
+
runId: input.runId,
|
|
706
|
+
playName: input.playName ?? null,
|
|
707
|
+
status,
|
|
708
|
+
error: optionalNullableString(input.error) ?? null,
|
|
709
|
+
createdAt: finiteNumber(input.createdAt) ?? null,
|
|
710
|
+
startedAt,
|
|
711
|
+
updatedAt: finiteNumber(input.updatedAt) ?? finishedAt ?? startedAt ?? finiteNumber(input.createdAt) ?? null,
|
|
712
|
+
finishedAt,
|
|
713
|
+
durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : null,
|
|
714
|
+
orderedStepIds: [],
|
|
715
|
+
stepsById: {},
|
|
716
|
+
logTail: [],
|
|
717
|
+
totalLogCount: 0,
|
|
718
|
+
logsTruncated: false,
|
|
719
|
+
activeStepId: null,
|
|
720
|
+
activeArtifactTableNamespace: null,
|
|
721
|
+
resultTableNamespace: null
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function normalizePlayRunLedgerSnapshot(value, fallback) {
|
|
725
|
+
if (!isRecord(value)) {
|
|
726
|
+
return createEmptyPlayRunLedgerSnapshot(fallback);
|
|
727
|
+
}
|
|
728
|
+
const orderedStepIds = Array.isArray(value.orderedStepIds) ? value.orderedStepIds.filter(
|
|
729
|
+
(entry) => typeof entry === "string" && Boolean(entry.trim())
|
|
730
|
+
) : [];
|
|
731
|
+
const rawSteps = isRecord(value.stepsById) ? value.stepsById : {};
|
|
732
|
+
const stepsById = {};
|
|
733
|
+
for (const [stepId, rawStep] of Object.entries(rawSteps)) {
|
|
734
|
+
if (!stepId.trim() || !isRecord(rawStep)) continue;
|
|
735
|
+
const rawStatus = normalizeStepStatus(rawStep.status);
|
|
736
|
+
if (!rawStatus) continue;
|
|
737
|
+
const completedAt = finiteNumber(rawStep.completedAt);
|
|
738
|
+
const status = rawStatus === "running" && completedAt !== null ? "completed" : rawStatus;
|
|
739
|
+
const rawProgress = isRecord(rawStep.progress) ? rawStep.progress : null;
|
|
740
|
+
stepsById[stepId] = {
|
|
741
|
+
stepId,
|
|
742
|
+
label: optionalString(rawStep.label),
|
|
743
|
+
kind: optionalString(rawStep.kind),
|
|
744
|
+
status,
|
|
745
|
+
artifactTableNamespace: optionalNullableString(
|
|
746
|
+
rawStep.artifactTableNamespace
|
|
747
|
+
),
|
|
748
|
+
startedAt: finiteNumber(rawStep.startedAt),
|
|
749
|
+
completedAt,
|
|
750
|
+
updatedAt: finiteNumber(rawStep.updatedAt),
|
|
751
|
+
progress: rawProgress ? normalizeStepProgress(rawProgress) : null
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
const createdAt = finiteNumber(value.createdAt) ?? fallback.createdAt ?? null;
|
|
755
|
+
const startedAt = finiteNumber(value.startedAt) ?? fallback.startedAt ?? null;
|
|
756
|
+
const finishedAt = finiteNumber(value.finishedAt) ?? fallback.finishedAt ?? null;
|
|
757
|
+
const updatedAt = finiteNumber(value.updatedAt) ?? fallback.updatedAt ?? finishedAt ?? startedAt ?? createdAt ?? null;
|
|
758
|
+
const error = Object.prototype.hasOwnProperty.call(value, "error") ? optionalNullableString(value.error) ?? null : fallback.error ?? null;
|
|
759
|
+
const rawTail = Array.isArray(value.logTail) ? value.logTail : value.logs;
|
|
760
|
+
const logTail = Array.isArray(rawTail) ? rawTail.filter((line) => typeof line === "string") : [];
|
|
761
|
+
return {
|
|
762
|
+
runId: optionalString(value.runId) ?? fallback.runId,
|
|
763
|
+
playName: optionalNullableString(value.playName) ?? fallback.playName ?? null,
|
|
764
|
+
status: normalizePlayRunLedgerStatus(value.status ?? fallback.status),
|
|
765
|
+
error,
|
|
766
|
+
createdAt,
|
|
767
|
+
startedAt,
|
|
768
|
+
updatedAt,
|
|
769
|
+
finishedAt,
|
|
770
|
+
durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : finiteNumber(value.durationMs),
|
|
771
|
+
orderedStepIds: orderedStepIds.filter((stepId) => stepsById[stepId]),
|
|
772
|
+
stepsById,
|
|
773
|
+
logTail: logTail.slice(-LOG_TAIL_LIMIT),
|
|
774
|
+
// Snapshots persisted before totalLogCount existed only know the retained
|
|
775
|
+
// tail, so the best lower bound for the cumulative count is the tail size.
|
|
776
|
+
totalLogCount: Math.max(
|
|
777
|
+
finiteNumber(value.totalLogCount) ?? logTail.length,
|
|
778
|
+
logTail.length
|
|
779
|
+
),
|
|
780
|
+
logsTruncated: value.logsTruncated === true,
|
|
781
|
+
activeStepId: optionalNullableString(value.activeStepId),
|
|
782
|
+
activeArtifactTableNamespace: optionalNullableString(
|
|
783
|
+
value.activeArtifactTableNamespace
|
|
784
|
+
),
|
|
785
|
+
resultTableNamespace: optionalNullableString(value.resultTableNamespace),
|
|
786
|
+
resultSummary: value.resultSummary,
|
|
787
|
+
result: value.result
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
function normalizeStepStatus(value) {
|
|
791
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
792
|
+
if (normalized === "running" || normalized === "completed" || normalized === "failed" || normalized === "skipped") {
|
|
793
|
+
return normalized;
|
|
794
|
+
}
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
function normalizeStepProgress(value) {
|
|
798
|
+
return {
|
|
799
|
+
...optionalFiniteNumber(value.completed) !== void 0 ? { completed: optionalFiniteNumber(value.completed) } : {},
|
|
800
|
+
...optionalFiniteNumber(value.total) !== void 0 ? { total: optionalFiniteNumber(value.total) } : {},
|
|
801
|
+
...optionalFiniteNumber(value.failed) !== void 0 ? { failed: optionalFiniteNumber(value.failed) } : {},
|
|
802
|
+
...optionalString(value.message) ? { message: optionalString(value.message) } : {},
|
|
803
|
+
...optionalNullableString(value.artifactTableNamespace) !== void 0 ? {
|
|
804
|
+
artifactTableNamespace: optionalNullableString(
|
|
805
|
+
value.artifactTableNamespace
|
|
806
|
+
)
|
|
807
|
+
} : {},
|
|
808
|
+
...finiteNumber(value.updatedAt) !== null ? { updatedAt: finiteNumber(value.updatedAt) } : {}
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// ../shared_libs/play-runtime/run-snapshot-stream.ts
|
|
813
|
+
function normalizePlayRunLiveStatus(value) {
|
|
814
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
815
|
+
switch (normalized) {
|
|
816
|
+
case "queued":
|
|
817
|
+
case "pending":
|
|
818
|
+
return "running";
|
|
819
|
+
case "running":
|
|
820
|
+
case "started":
|
|
821
|
+
return "running";
|
|
822
|
+
case "completed":
|
|
823
|
+
case "complete":
|
|
824
|
+
case "succeeded":
|
|
825
|
+
return "completed";
|
|
826
|
+
case "failed":
|
|
827
|
+
case "error":
|
|
828
|
+
return "failed";
|
|
829
|
+
case "cancelled":
|
|
830
|
+
case "canceled":
|
|
831
|
+
return "cancelled";
|
|
832
|
+
case "terminated":
|
|
833
|
+
return "terminated";
|
|
834
|
+
case "timed_out":
|
|
835
|
+
case "timeout":
|
|
836
|
+
return "timed_out";
|
|
837
|
+
default:
|
|
838
|
+
return "unknown";
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function isTerminalPlayRunLiveStatus(status) {
|
|
842
|
+
return status === "completed" || status === "failed" || status === "cancelled" || status === "terminated" || status === "timed_out";
|
|
843
|
+
}
|
|
844
|
+
function buildSnapshotFromLedger(snapshot) {
|
|
845
|
+
const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
|
|
846
|
+
nodeId: step.stepId,
|
|
847
|
+
status: step.status,
|
|
848
|
+
artifactTableNamespace: step.artifactTableNamespace ?? null,
|
|
849
|
+
progress: step.progress ? {
|
|
850
|
+
completed: step.progress.completed,
|
|
851
|
+
total: step.progress.total,
|
|
852
|
+
failed: step.progress.failed,
|
|
853
|
+
message: step.progress.message,
|
|
854
|
+
artifactTableNamespace: step.progress.artifactTableNamespace ?? step.artifactTableNamespace ?? null,
|
|
855
|
+
startedAt: step.startedAt ?? null,
|
|
856
|
+
completedAt: step.completedAt ?? null,
|
|
857
|
+
updatedAt: step.progress.updatedAt ?? step.updatedAt ?? null
|
|
858
|
+
} : null,
|
|
859
|
+
startedAt: step.startedAt ?? null,
|
|
860
|
+
completedAt: step.completedAt ?? null,
|
|
861
|
+
updatedAt: step.updatedAt ?? null
|
|
862
|
+
}));
|
|
863
|
+
return {
|
|
864
|
+
runId: snapshot.runId,
|
|
865
|
+
status: normalizePlayRunLiveStatus(snapshot.status),
|
|
866
|
+
updatedAt: snapshot.updatedAt ?? snapshot.finishedAt ?? snapshot.startedAt ?? null,
|
|
867
|
+
logs: snapshot.logTail,
|
|
868
|
+
totalLogCount: snapshot.totalLogCount,
|
|
869
|
+
...snapshot.logsTruncated ? { logsTruncated: true } : {},
|
|
870
|
+
activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
|
|
871
|
+
resultTableNamespace: snapshot.resultTableNamespace ?? null,
|
|
872
|
+
nodeStates,
|
|
873
|
+
activeNodeId: snapshot.activeStepId ?? null
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
function buildPlayRunStatusSnapshot(input) {
|
|
877
|
+
const ledgerSnapshot = normalizePlayRunLedgerSnapshot(input.run.runSnapshot, {
|
|
878
|
+
runId: input.run.workflowId,
|
|
879
|
+
playName: input.run.name ?? null,
|
|
880
|
+
status: input.run.status,
|
|
881
|
+
createdAt: input.run.createdAt ?? null,
|
|
882
|
+
startedAt: input.run.startedAt ?? null,
|
|
883
|
+
updatedAt: input.run.updatedAt ?? null,
|
|
884
|
+
finishedAt: input.run.finishedAt ?? null
|
|
885
|
+
});
|
|
886
|
+
return buildSnapshotFromLedger(ledgerSnapshot);
|
|
887
|
+
}
|
|
888
|
+
function makeRunStreamEvent(input) {
|
|
889
|
+
return {
|
|
890
|
+
...input,
|
|
891
|
+
scope: "play",
|
|
892
|
+
at: input.at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
var EMPTY_PLAY_RUN_STREAM_DIFF_STATE = {
|
|
896
|
+
runSignature: "",
|
|
897
|
+
snapshotSignature: "",
|
|
898
|
+
stepStatusSignature: "",
|
|
899
|
+
stepProgressSignature: "",
|
|
900
|
+
lastLogSeq: 0
|
|
901
|
+
};
|
|
902
|
+
function getSnapshotCursor(snapshot) {
|
|
903
|
+
return String(snapshot.updatedAt ?? Date.now());
|
|
904
|
+
}
|
|
905
|
+
function getRunSignature(snapshot) {
|
|
906
|
+
return [snapshot.runId, snapshot.status, snapshot.updatedAt ?? 0].join(":");
|
|
907
|
+
}
|
|
908
|
+
function getStepStatusSignature(snapshot) {
|
|
909
|
+
return snapshot.nodeStates.map(
|
|
910
|
+
(state) => [
|
|
911
|
+
state.nodeId,
|
|
912
|
+
state.status,
|
|
913
|
+
state.artifactTableNamespace ?? "",
|
|
914
|
+
state.startedAt ?? "",
|
|
915
|
+
state.completedAt ?? "",
|
|
916
|
+
state.progress?.startedAt ?? "",
|
|
917
|
+
state.progress?.completedAt ?? "",
|
|
918
|
+
state.updatedAt ?? "",
|
|
919
|
+
state.progress?.updatedAt ?? ""
|
|
920
|
+
].join(":")
|
|
921
|
+
).join("|");
|
|
922
|
+
}
|
|
923
|
+
function getStepProgressSignature(snapshot) {
|
|
924
|
+
return snapshot.nodeStates.map(
|
|
925
|
+
(state) => [
|
|
926
|
+
state.nodeId,
|
|
927
|
+
state.progress?.completed ?? "",
|
|
928
|
+
state.progress?.total ?? "",
|
|
929
|
+
state.progress?.failed ?? "",
|
|
930
|
+
state.progress?.artifactTableNamespace ?? "",
|
|
931
|
+
state.progress?.startedAt ?? "",
|
|
932
|
+
state.progress?.completedAt ?? "",
|
|
933
|
+
state.progress?.updatedAt ?? "",
|
|
934
|
+
state.progress?.message ?? ""
|
|
935
|
+
].join(":")
|
|
936
|
+
).join("|");
|
|
937
|
+
}
|
|
938
|
+
function getSnapshotSignature(snapshot) {
|
|
939
|
+
return JSON.stringify(snapshot);
|
|
940
|
+
}
|
|
941
|
+
function resolvePlayRunLogGap(snapshot, lastLogSeq) {
|
|
942
|
+
if (snapshot.totalLogCount <= lastLogSeq) {
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
const tailFirstSeq = snapshot.totalLogCount - snapshot.logs.length + 1;
|
|
946
|
+
if (lastLogSeq + 1 >= tailFirstSeq) {
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
return {
|
|
950
|
+
missingCount: tailFirstSeq - 1 - lastLogSeq,
|
|
951
|
+
tailFirstSeq
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
function diffLogLines(input) {
|
|
955
|
+
const { logs, totalLogCount } = input.snapshot;
|
|
956
|
+
if (totalLogCount <= input.lastLogSeq) {
|
|
957
|
+
return { lines: [], lastLogSeq: input.lastLogSeq, firstSeq: null };
|
|
958
|
+
}
|
|
959
|
+
const tailFirstSeq = totalLogCount - logs.length + 1;
|
|
960
|
+
if (input.lastLogSeq + 1 >= tailFirstSeq) {
|
|
961
|
+
return {
|
|
962
|
+
lines: logs.slice(input.lastLogSeq + 1 - tailFirstSeq),
|
|
963
|
+
lastLogSeq: totalLogCount,
|
|
964
|
+
firstSeq: input.lastLogSeq + 1
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
const missingCount = tailFirstSeq - 1 - input.lastLogSeq;
|
|
968
|
+
return {
|
|
969
|
+
lines: [
|
|
970
|
+
`[stream] ${missingCount} log lines not retained in the live window; full logs via runs logs`,
|
|
971
|
+
...logs
|
|
972
|
+
],
|
|
973
|
+
lastLogSeq: totalLogCount,
|
|
974
|
+
firstSeq: null
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
function diffPlayRunStreamEvents(input) {
|
|
978
|
+
const { snapshot, streamId, previous } = input;
|
|
979
|
+
const cursor = getSnapshotCursor(snapshot);
|
|
980
|
+
const logDiff = diffLogLines({
|
|
981
|
+
snapshot,
|
|
982
|
+
lastLogSeq: previous.lastLogSeq
|
|
983
|
+
});
|
|
984
|
+
const next = {
|
|
985
|
+
runSignature: getRunSignature(snapshot),
|
|
986
|
+
stepStatusSignature: getStepStatusSignature(snapshot),
|
|
987
|
+
stepProgressSignature: getStepProgressSignature(snapshot),
|
|
988
|
+
snapshotSignature: getSnapshotSignature(snapshot),
|
|
989
|
+
lastLogSeq: logDiff.lastLogSeq
|
|
990
|
+
};
|
|
991
|
+
const events = [];
|
|
992
|
+
if (next.stepStatusSignature !== previous.stepStatusSignature) {
|
|
993
|
+
for (const state of snapshot.nodeStates) {
|
|
994
|
+
if (state.status === "idle") {
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
const persistedStartedAt = state.startedAt ?? state.progress?.startedAt ?? null;
|
|
998
|
+
const persistedCompletedAt = state.completedAt ?? state.progress?.completedAt ?? null;
|
|
999
|
+
events.push(
|
|
1000
|
+
makeRunStreamEvent({
|
|
1001
|
+
cursor,
|
|
1002
|
+
streamId,
|
|
1003
|
+
type: "play.step.status",
|
|
1004
|
+
payload: {
|
|
1005
|
+
runId: snapshot.runId,
|
|
1006
|
+
stepId: state.nodeId,
|
|
1007
|
+
status: state.status,
|
|
1008
|
+
artifactTableNamespace: state.artifactTableNamespace ?? null,
|
|
1009
|
+
...resolveTimingWindow({
|
|
1010
|
+
startedAt: persistedStartedAt,
|
|
1011
|
+
completedAt: persistedCompletedAt,
|
|
1012
|
+
updatedAt: state.updatedAt ?? state.progress?.updatedAt ?? snapshot.updatedAt ?? null
|
|
1013
|
+
})
|
|
1014
|
+
}
|
|
1015
|
+
})
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (next.stepProgressSignature !== previous.stepProgressSignature) {
|
|
1020
|
+
for (const state of snapshot.nodeStates) {
|
|
1021
|
+
if (!state.progress) {
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
events.push(
|
|
1025
|
+
makeRunStreamEvent({
|
|
1026
|
+
cursor: String(
|
|
1027
|
+
state.progress.updatedAt ?? snapshot.updatedAt ?? Date.now()
|
|
1028
|
+
),
|
|
1029
|
+
streamId,
|
|
1030
|
+
type: "play.step.progress",
|
|
1031
|
+
payload: {
|
|
1032
|
+
runId: snapshot.runId,
|
|
1033
|
+
stepId: state.nodeId,
|
|
1034
|
+
completed: state.progress.completed,
|
|
1035
|
+
total: state.progress.total,
|
|
1036
|
+
failed: state.progress.failed,
|
|
1037
|
+
message: state.progress.message,
|
|
1038
|
+
artifactTableNamespace: state.progress.artifactTableNamespace ?? state.artifactTableNamespace ?? null,
|
|
1039
|
+
...resolveTimingWindow({
|
|
1040
|
+
startedAt: state.startedAt ?? state.progress.startedAt ?? null,
|
|
1041
|
+
completedAt: state.completedAt ?? state.progress.completedAt ?? null,
|
|
1042
|
+
updatedAt: state.progress.updatedAt ?? snapshot.updatedAt ?? null
|
|
1043
|
+
})
|
|
1044
|
+
}
|
|
1045
|
+
})
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (logDiff.lines.length > 0) {
|
|
1050
|
+
events.push(
|
|
1051
|
+
makeRunStreamEvent({
|
|
1052
|
+
cursor,
|
|
1053
|
+
streamId,
|
|
1054
|
+
type: "play.run.log",
|
|
1055
|
+
payload: {
|
|
1056
|
+
runId: snapshot.runId,
|
|
1057
|
+
lines: logDiff.lines,
|
|
1058
|
+
source: "worker",
|
|
1059
|
+
...logDiff.firstSeq !== null ? { firstSeq: logDiff.firstSeq } : {},
|
|
1060
|
+
totalLogCount: snapshot.totalLogCount
|
|
1061
|
+
}
|
|
1062
|
+
})
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
if (next.snapshotSignature !== previous.snapshotSignature) {
|
|
1066
|
+
const enrichedNodeStates = snapshot.nodeStates.map((state) => {
|
|
1067
|
+
const timing = resolveTimingWindow({
|
|
1068
|
+
startedAt: state.startedAt ?? state.progress?.startedAt ?? null,
|
|
1069
|
+
completedAt: state.completedAt ?? state.progress?.completedAt ?? null,
|
|
1070
|
+
updatedAt: state.updatedAt ?? state.progress?.updatedAt ?? snapshot.updatedAt ?? null
|
|
1071
|
+
});
|
|
1072
|
+
return {
|
|
1073
|
+
...state,
|
|
1074
|
+
...timing,
|
|
1075
|
+
progress: state.progress ? {
|
|
1076
|
+
...state.progress,
|
|
1077
|
+
...resolveTimingWindow({
|
|
1078
|
+
startedAt: state.progress.startedAt ?? state.startedAt ?? null,
|
|
1079
|
+
completedAt: state.progress.completedAt ?? state.completedAt ?? null,
|
|
1080
|
+
updatedAt: state.progress.updatedAt ?? state.updatedAt ?? snapshot.updatedAt ?? null
|
|
1081
|
+
})
|
|
1082
|
+
} : state.progress
|
|
1083
|
+
};
|
|
1084
|
+
});
|
|
1085
|
+
events.push(
|
|
1086
|
+
makeRunStreamEvent({
|
|
1087
|
+
cursor,
|
|
1088
|
+
streamId,
|
|
1089
|
+
type: "play.run.snapshot",
|
|
1090
|
+
payload: { ...snapshot, nodeStates: enrichedNodeStates }
|
|
1091
|
+
})
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (next.runSignature !== previous.runSignature) {
|
|
1095
|
+
events.push(
|
|
1096
|
+
makeRunStreamEvent({
|
|
1097
|
+
cursor,
|
|
1098
|
+
streamId,
|
|
1099
|
+
type: "play.run.status",
|
|
1100
|
+
payload: {
|
|
1101
|
+
runId: snapshot.runId,
|
|
1102
|
+
status: snapshot.status,
|
|
1103
|
+
updatedAt: snapshot.updatedAt
|
|
1104
|
+
}
|
|
1105
|
+
})
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
return { events, next };
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/runs/observe-transport.ts
|
|
1112
|
+
var RunObserveTransportUnavailableError = class extends Error {
|
|
1113
|
+
constructor(message, reason) {
|
|
1114
|
+
super(message);
|
|
1115
|
+
this.reason = reason;
|
|
1116
|
+
this.name = "RunObserveTransportUnavailableError";
|
|
1117
|
+
}
|
|
1118
|
+
reason;
|
|
1119
|
+
};
|
|
1120
|
+
var OBSERVE_BOOTSTRAP_TIMEOUT_MS = 1e4;
|
|
1121
|
+
var OBSERVE_RECONNECT_NOTICE_MS = 1e4;
|
|
1122
|
+
var OBSERVE_STALE_WARNING_MS = 12e4;
|
|
1123
|
+
var OBSERVE_WATCHDOG_TICK_MS = 5e3;
|
|
1124
|
+
var GRANT_REFRESH_MARGIN_MS = 5 * 6e4;
|
|
1125
|
+
var BACKFILL_PAGE_LIMIT = 1e3;
|
|
1126
|
+
var BACKFILL_MAX_PAGES = 30;
|
|
1127
|
+
var OBSERVER_SNAPSHOT_QUERY = "runObservers:getPlayRunSnapshotForObserver";
|
|
1128
|
+
var OBSERVER_LOG_PAGE_QUERY = "runObservers:getRunLogPageForObserver";
|
|
1129
|
+
function errorText(error) {
|
|
1130
|
+
return error instanceof Error ? error.message : String(error);
|
|
1131
|
+
}
|
|
1132
|
+
async function mintRunObserveGrant(http, runId) {
|
|
1133
|
+
let response;
|
|
1134
|
+
try {
|
|
1135
|
+
response = await http.post(
|
|
1136
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/observe-grant`,
|
|
1137
|
+
{}
|
|
1138
|
+
);
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
if (error instanceof DeeplineError) {
|
|
1141
|
+
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
1142
|
+
throw error;
|
|
1143
|
+
}
|
|
1144
|
+
throw new RunObserveTransportUnavailableError(
|
|
1145
|
+
`observe-grant endpoint unavailable (${error.statusCode ?? "network"}): ${error.message}`,
|
|
1146
|
+
"grant_endpoint_unavailable"
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
throw new RunObserveTransportUnavailableError(
|
|
1150
|
+
`observe-grant request failed: ${errorText(error)}`,
|
|
1151
|
+
"grant_request_failed"
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
const grant = response;
|
|
1155
|
+
if (!grant || typeof grant.convexUrl !== "string" || !grant.convexUrl.trim() || typeof grant.token !== "string" || !grant.token.trim() || typeof grant.expiresAt !== "number") {
|
|
1156
|
+
throw new RunObserveTransportUnavailableError(
|
|
1157
|
+
"observe-grant endpoint returned an invalid grant payload.",
|
|
1158
|
+
"grant_payload_invalid"
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
return grant;
|
|
1162
|
+
}
|
|
1163
|
+
async function backfillLogGap(input) {
|
|
1164
|
+
const lines = [];
|
|
1165
|
+
let cursor = input.lastLogSeq;
|
|
1166
|
+
for (let page = 0; page < BACKFILL_MAX_PAGES; page += 1) {
|
|
1167
|
+
if (cursor >= input.tailFirstSeq - 1) {
|
|
1168
|
+
break;
|
|
1169
|
+
}
|
|
1170
|
+
let logPage;
|
|
1171
|
+
try {
|
|
1172
|
+
logPage = await input.queryLogPage(
|
|
1173
|
+
cursor,
|
|
1174
|
+
Math.min(BACKFILL_PAGE_LIMIT, input.tailFirstSeq - 1 - cursor)
|
|
1175
|
+
);
|
|
1176
|
+
} catch {
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
const entries = (logPage?.entries ?? []).filter(
|
|
1180
|
+
(entry) => entry.seq > cursor && entry.seq < input.tailFirstSeq
|
|
1181
|
+
);
|
|
1182
|
+
if (entries.length === 0) {
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
for (const entry of entries) {
|
|
1186
|
+
if (entry.seq !== cursor + 1) {
|
|
1187
|
+
return null;
|
|
1188
|
+
}
|
|
1189
|
+
lines.push(entry.line);
|
|
1190
|
+
cursor = entry.seq;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
if (cursor < input.tailFirstSeq - 1) {
|
|
1194
|
+
return null;
|
|
1195
|
+
}
|
|
1196
|
+
return lines;
|
|
1197
|
+
}
|
|
1198
|
+
async function* observeRunEvents(options) {
|
|
1199
|
+
const { http, runId } = options;
|
|
1200
|
+
let grant = await mintRunObserveGrant(http, runId);
|
|
1201
|
+
let convexBrowser;
|
|
1202
|
+
let convexServer;
|
|
1203
|
+
try {
|
|
1204
|
+
convexBrowser = await import("convex/browser");
|
|
1205
|
+
convexServer = await import("convex/server");
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
throw new RunObserveTransportUnavailableError(
|
|
1208
|
+
`convex client module unavailable: ${errorText(error)}`,
|
|
1209
|
+
"convex_module_unavailable"
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
let webSocketConstructor;
|
|
1213
|
+
if (typeof WebSocket === "undefined") {
|
|
1214
|
+
try {
|
|
1215
|
+
const wsModuleName = "ws";
|
|
1216
|
+
const ws = await import(wsModuleName);
|
|
1217
|
+
webSocketConstructor = ws.default;
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
throw new RunObserveTransportUnavailableError(
|
|
1220
|
+
`no WebSocket implementation available: ${errorText(error)}`,
|
|
1221
|
+
"websocket_unavailable"
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
const snapshotQuery = convexServer.makeFunctionReference(
|
|
1226
|
+
OBSERVER_SNAPSHOT_QUERY
|
|
1227
|
+
);
|
|
1228
|
+
const logPageQuery = convexServer.makeFunctionReference(
|
|
1229
|
+
OBSERVER_LOG_PAGE_QUERY
|
|
1230
|
+
);
|
|
1231
|
+
const client = new convexBrowser.ConvexClient(grant.convexUrl, {
|
|
1232
|
+
...webSocketConstructor ? { webSocketConstructor } : {},
|
|
1233
|
+
unsavedChangesWarning: false
|
|
1234
|
+
});
|
|
1235
|
+
const queue = [];
|
|
1236
|
+
let wake = null;
|
|
1237
|
+
const push = (item) => {
|
|
1238
|
+
queue.push(item);
|
|
1239
|
+
wake?.();
|
|
1240
|
+
wake = null;
|
|
1241
|
+
};
|
|
1242
|
+
let lastForcedRefreshAt = 0;
|
|
1243
|
+
client.setAuth(async ({ forceRefreshToken }) => {
|
|
1244
|
+
const now = Date.now();
|
|
1245
|
+
if (!forceRefreshToken && grant.expiresAt - now > GRANT_REFRESH_MARGIN_MS) {
|
|
1246
|
+
return grant.token;
|
|
1247
|
+
}
|
|
1248
|
+
if (forceRefreshToken && now - lastForcedRefreshAt < 5e3) {
|
|
1249
|
+
push({
|
|
1250
|
+
kind: "error",
|
|
1251
|
+
error: new DeeplineError(
|
|
1252
|
+
`Run observe grant for ${runId} was rejected after a re-mint. The server and Convex deployment disagree on the grant issuer/JWKS.`,
|
|
1253
|
+
401,
|
|
1254
|
+
"RUN_OBSERVE_GRANT_REJECTED"
|
|
1255
|
+
)
|
|
1256
|
+
});
|
|
1257
|
+
return null;
|
|
1258
|
+
}
|
|
1259
|
+
if (forceRefreshToken) {
|
|
1260
|
+
lastForcedRefreshAt = now;
|
|
1261
|
+
}
|
|
1262
|
+
try {
|
|
1263
|
+
grant = await mintRunObserveGrant(http, runId);
|
|
1264
|
+
return grant.token;
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
push({ kind: "error", error });
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
const unsubscribe = client.onUpdate(
|
|
1271
|
+
snapshotQuery,
|
|
1272
|
+
{ workflowId: runId },
|
|
1273
|
+
(run) => push({ kind: "run", run: run ?? null }),
|
|
1274
|
+
(error) => push({ kind: "error", error })
|
|
1275
|
+
);
|
|
1276
|
+
let lastUpdateAt = Date.now();
|
|
1277
|
+
let lastStatusTerminal = false;
|
|
1278
|
+
let disconnectedSince = null;
|
|
1279
|
+
let warnedReconnecting = false;
|
|
1280
|
+
let warnedStale = false;
|
|
1281
|
+
const watchdog = setInterval(() => {
|
|
1282
|
+
const now = Date.now();
|
|
1283
|
+
try {
|
|
1284
|
+
const connectionState = client.connectionState();
|
|
1285
|
+
if (connectionState.isWebSocketConnected) {
|
|
1286
|
+
disconnectedSince = null;
|
|
1287
|
+
warnedReconnecting = false;
|
|
1288
|
+
} else {
|
|
1289
|
+
disconnectedSince ??= now;
|
|
1290
|
+
if (!warnedReconnecting && now - disconnectedSince >= OBSERVE_RECONNECT_NOTICE_MS) {
|
|
1291
|
+
warnedReconnecting = true;
|
|
1292
|
+
options.onNotice?.(
|
|
1293
|
+
`[observe] connection lost; reconnecting to live run ${runId}\u2026`
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
} catch {
|
|
1298
|
+
}
|
|
1299
|
+
if (!lastStatusTerminal && !warnedStale && now - lastUpdateAt >= OBSERVE_STALE_WARNING_MS) {
|
|
1300
|
+
warnedStale = true;
|
|
1301
|
+
options.onNotice?.(
|
|
1302
|
+
`[observe] no live updates for ${Math.round((now - lastUpdateAt) / 1e3)}s; run ${runId} may be stalled (status checks continue)`
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
}, OBSERVE_WATCHDOG_TICK_MS);
|
|
1306
|
+
watchdog.unref?.();
|
|
1307
|
+
const abortListener = () => push({
|
|
1308
|
+
kind: "error",
|
|
1309
|
+
error: new DeeplineError(
|
|
1310
|
+
"Run observation aborted.",
|
|
1311
|
+
void 0,
|
|
1312
|
+
"ABORTED"
|
|
1313
|
+
)
|
|
1314
|
+
});
|
|
1315
|
+
options.signal?.addEventListener("abort", abortListener, { once: true });
|
|
1316
|
+
let diffState = EMPTY_PLAY_RUN_STREAM_DIFF_STATE;
|
|
1317
|
+
const streamId = ["observe", runId].join(":");
|
|
1318
|
+
let sawFirstSnapshot = false;
|
|
1319
|
+
try {
|
|
1320
|
+
for (; ; ) {
|
|
1321
|
+
if (queue.length === 0) {
|
|
1322
|
+
const waitForItem = new Promise((resolve2) => {
|
|
1323
|
+
wake = resolve2;
|
|
1324
|
+
});
|
|
1325
|
+
if (!sawFirstSnapshot) {
|
|
1326
|
+
const timedOut = await Promise.race([
|
|
1327
|
+
waitForItem.then(() => false),
|
|
1328
|
+
new Promise(
|
|
1329
|
+
(resolve2) => setTimeout(() => resolve2(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
|
|
1330
|
+
)
|
|
1331
|
+
]);
|
|
1332
|
+
if (timedOut && queue.length === 0) {
|
|
1333
|
+
throw new RunObserveTransportUnavailableError(
|
|
1334
|
+
`no snapshot from Convex at ${grant.convexUrl} within ${OBSERVE_BOOTSTRAP_TIMEOUT_MS}ms`,
|
|
1335
|
+
"convex_unreachable"
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
} else {
|
|
1339
|
+
await waitForItem;
|
|
1340
|
+
}
|
|
1341
|
+
continue;
|
|
1342
|
+
}
|
|
1343
|
+
const item = queue.shift();
|
|
1344
|
+
if (item.kind === "error") {
|
|
1345
|
+
if (options.signal?.aborted) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
throw item.error;
|
|
1349
|
+
}
|
|
1350
|
+
sawFirstSnapshot = true;
|
|
1351
|
+
lastUpdateAt = Date.now();
|
|
1352
|
+
warnedStale = false;
|
|
1353
|
+
if (item.run === null) {
|
|
1354
|
+
throw new DeeplineError(
|
|
1355
|
+
`Run ${runId} was not found (or is not visible to this grant).`,
|
|
1356
|
+
404,
|
|
1357
|
+
"RUN_NOT_FOUND"
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
const snapshot = buildPlayRunStatusSnapshot({ run: item.run });
|
|
1361
|
+
lastStatusTerminal = isTerminalPlayRunLiveStatus(snapshot.status);
|
|
1362
|
+
const gap = resolvePlayRunLogGap(snapshot, diffState.lastLogSeq);
|
|
1363
|
+
if (gap && diffState.lastLogSeq > 0) {
|
|
1364
|
+
const backfilled = await backfillLogGap({
|
|
1365
|
+
queryLogPage: (afterSeq, limit) => client.query(logPageQuery, {
|
|
1366
|
+
workflowId: runId,
|
|
1367
|
+
afterSeq,
|
|
1368
|
+
limit
|
|
1369
|
+
}),
|
|
1370
|
+
lastLogSeq: diffState.lastLogSeq,
|
|
1371
|
+
tailFirstSeq: gap.tailFirstSeq
|
|
1372
|
+
});
|
|
1373
|
+
if (backfilled && backfilled.length > 0) {
|
|
1374
|
+
yield {
|
|
1375
|
+
cursor: String(snapshot.updatedAt ?? Date.now()),
|
|
1376
|
+
streamId,
|
|
1377
|
+
scope: "play",
|
|
1378
|
+
type: "play.run.log",
|
|
1379
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1380
|
+
payload: {
|
|
1381
|
+
runId: snapshot.runId,
|
|
1382
|
+
lines: backfilled,
|
|
1383
|
+
source: "worker",
|
|
1384
|
+
firstSeq: diffState.lastLogSeq + 1,
|
|
1385
|
+
totalLogCount: snapshot.totalLogCount
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
diffState = { ...diffState, lastLogSeq: gap.tailFirstSeq - 1 };
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
const { events, next } = diffPlayRunStreamEvents({
|
|
1392
|
+
streamId,
|
|
1393
|
+
snapshot,
|
|
1394
|
+
previous: diffState
|
|
1395
|
+
});
|
|
1396
|
+
diffState = next;
|
|
1397
|
+
const ordered = [
|
|
1398
|
+
...events.filter((event) => event.type === "play.run.snapshot"),
|
|
1399
|
+
...events.filter((event) => event.type !== "play.run.snapshot")
|
|
1400
|
+
];
|
|
1401
|
+
for (const event of ordered) {
|
|
1402
|
+
yield event;
|
|
1403
|
+
}
|
|
1404
|
+
if (lastStatusTerminal) {
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
} finally {
|
|
1409
|
+
clearInterval(watchdog);
|
|
1410
|
+
options.signal?.removeEventListener("abort", abortListener);
|
|
1411
|
+
try {
|
|
1412
|
+
unsubscribe();
|
|
1413
|
+
} catch {
|
|
1414
|
+
}
|
|
1415
|
+
await client.close().catch(() => void 0);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
607
1419
|
// src/client.ts
|
|
608
1420
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
609
1421
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
@@ -622,7 +1434,8 @@ function isTransientCompileManifestError(error) {
|
|
|
622
1434
|
message
|
|
623
1435
|
);
|
|
624
1436
|
}
|
|
625
|
-
|
|
1437
|
+
var RUN_LOGS_PAGE_LIMIT = 1e3;
|
|
1438
|
+
function isRecord2(value) {
|
|
626
1439
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
627
1440
|
}
|
|
628
1441
|
function isPrebuiltPlayDescription(play) {
|
|
@@ -692,10 +1505,31 @@ function normalizeLiveStatus(value) {
|
|
|
692
1505
|
}
|
|
693
1506
|
return null;
|
|
694
1507
|
}
|
|
1508
|
+
function appendPlayLiveLogLines(state, payload) {
|
|
1509
|
+
const lines = readStringArray(payload.lines);
|
|
1510
|
+
if (lines.length === 0) {
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
const firstSeq = typeof payload.firstSeq === "number" && Number.isFinite(payload.firstSeq) && payload.firstSeq >= 1 ? Math.trunc(payload.firstSeq) : null;
|
|
1514
|
+
if (firstSeq === null) {
|
|
1515
|
+
state.logs.push(...lines);
|
|
1516
|
+
const totalLogCount = typeof payload.totalLogCount === "number" && Number.isFinite(payload.totalLogCount) ? Math.trunc(payload.totalLogCount) : null;
|
|
1517
|
+
if (totalLogCount !== null) {
|
|
1518
|
+
state.lastLogSeq = Math.max(state.lastLogSeq, totalLogCount);
|
|
1519
|
+
}
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
const skip = Math.max(0, state.lastLogSeq + 1 - firstSeq);
|
|
1523
|
+
if (skip >= lines.length) {
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
state.logs.push(...lines.slice(skip));
|
|
1527
|
+
state.lastLogSeq = Math.max(state.lastLogSeq, firstSeq + lines.length - 1);
|
|
1528
|
+
}
|
|
695
1529
|
function updatePlayLiveStatusState(state, event) {
|
|
696
1530
|
const payload = getPlayLiveEventPayload(event);
|
|
697
1531
|
if (event.type === "play.run.log") {
|
|
698
|
-
state
|
|
1532
|
+
appendPlayLiveLogLines(state, payload);
|
|
699
1533
|
return null;
|
|
700
1534
|
}
|
|
701
1535
|
if (event.type !== "play.run.snapshot" && event.type !== "play.run.status" && event.type !== "play.run.final_status") {
|
|
@@ -703,12 +1537,14 @@ function updatePlayLiveStatusState(state, event) {
|
|
|
703
1537
|
}
|
|
704
1538
|
const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : isPlayRunPackage(payload) ? payload.run.id : state.runId;
|
|
705
1539
|
const status = normalizeLiveStatus(payload.status) ?? (isPlayRunPackage(payload) ? normalizeLiveStatus(payload.run.status) : null) ?? state.status;
|
|
706
|
-
const progressPayload =
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1540
|
+
const progressPayload = isRecord2(payload.progress) ? payload.progress : {};
|
|
1541
|
+
if (event.type === "play.run.final_status" && state.logs.length === 0 && state.lastLogSeq === 0) {
|
|
1542
|
+
const payloadLogs = readStringArray(payload.logs);
|
|
1543
|
+
const progressLogs = readStringArray(progressPayload.logs);
|
|
1544
|
+
const seedLogs = payloadLogs.length > 0 ? payloadLogs : progressLogs;
|
|
1545
|
+
if (seedLogs.length > 0) {
|
|
1546
|
+
state.logs = seedLogs;
|
|
1547
|
+
}
|
|
712
1548
|
}
|
|
713
1549
|
if ("result" in payload) {
|
|
714
1550
|
state.result = payload.result;
|
|
@@ -802,9 +1638,9 @@ var DeeplineClient = class {
|
|
|
802
1638
|
return fields.length > 0 ? { fields } : schema;
|
|
803
1639
|
}
|
|
804
1640
|
schemaMetadata(schema, key) {
|
|
805
|
-
if (!
|
|
1641
|
+
if (!isRecord2(schema)) return null;
|
|
806
1642
|
const value = schema[key];
|
|
807
|
-
return
|
|
1643
|
+
return isRecord2(value) ? value : null;
|
|
808
1644
|
}
|
|
809
1645
|
playRunCommand(play, options) {
|
|
810
1646
|
const target = play.reference || play.name;
|
|
@@ -851,7 +1687,7 @@ var DeeplineClient = class {
|
|
|
851
1687
|
aliases,
|
|
852
1688
|
inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
|
|
853
1689
|
outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
|
|
854
|
-
staticPipeline:
|
|
1690
|
+
staticPipeline: isRecord2(play.staticPipeline) ? play.staticPipeline : isRecord2(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord2(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
|
|
855
1691
|
...csvInput ? { csvInput } : {},
|
|
856
1692
|
...rowOutputSchema ? { rowOutputSchema } : {},
|
|
857
1693
|
runCommand,
|
|
@@ -1535,43 +2371,140 @@ var DeeplineClient = class {
|
|
|
1535
2371
|
);
|
|
1536
2372
|
return response.runs ?? [];
|
|
1537
2373
|
}
|
|
1538
|
-
/**
|
|
1539
|
-
|
|
2374
|
+
/**
|
|
2375
|
+
* Observe one run's live events through the Convex Run Snapshot
|
|
2376
|
+
* subscription transport (ADR-0008). Yields the same `play.*` event
|
|
2377
|
+
* envelopes as {@link streamPlayRunEvents} and ends after the terminal
|
|
2378
|
+
* snapshot. Throws {@link RunObserveTransportUnavailableError} when this
|
|
2379
|
+
* server cannot serve the transport (older server, unconfigured grants, or
|
|
2380
|
+
* unreachable Convex) — callers fall back to the SSE stream with a notice.
|
|
2381
|
+
*/
|
|
2382
|
+
observeRunEvents(runId, options) {
|
|
2383
|
+
return observeRunEvents({
|
|
2384
|
+
http: this.http,
|
|
2385
|
+
runId,
|
|
2386
|
+
signal: options?.signal,
|
|
2387
|
+
onNotice: options?.onNotice
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
/**
|
|
2391
|
+
* Tail one run through the subscription transport until terminal, then
|
|
2392
|
+
* return one durable REST status read (the final Run Response Package).
|
|
2393
|
+
*/
|
|
2394
|
+
async tailRunViaObserveTransport(runId, options) {
|
|
1540
2395
|
const state = {
|
|
1541
2396
|
runId,
|
|
1542
2397
|
status: "running",
|
|
1543
2398
|
logs: [],
|
|
2399
|
+
lastLogSeq: 0,
|
|
1544
2400
|
latest: null
|
|
1545
2401
|
};
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
signal: options?.signal
|
|
2402
|
+
for await (const event of this.observeRunEvents(runId, {
|
|
2403
|
+
signal: options?.signal,
|
|
2404
|
+
onNotice: options?.onNotice
|
|
1550
2405
|
})) {
|
|
1551
2406
|
const status = updatePlayLiveStatusState(state, event);
|
|
1552
|
-
if (!status) {
|
|
2407
|
+
if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
1553
2408
|
continue;
|
|
1554
2409
|
}
|
|
1555
|
-
|
|
1556
|
-
if (terminal) {
|
|
1557
|
-
break;
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
if (terminal && state.latest) {
|
|
1561
|
-
return await this.getRunStatus(state.latest.runId || runId).catch(
|
|
2410
|
+
return await this.getRunStatus(status.runId || runId).catch(
|
|
1562
2411
|
() => state.latest ?? playRunStatusFromState(state)
|
|
1563
2412
|
);
|
|
1564
2413
|
}
|
|
1565
|
-
if (
|
|
1566
|
-
|
|
2414
|
+
if (options?.signal?.aborted) {
|
|
2415
|
+
throw new DeeplineError("Run observation aborted.", void 0, "ABORTED");
|
|
2416
|
+
}
|
|
2417
|
+
const refreshed = await this.getRunStatus(runId);
|
|
2418
|
+
if (TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
|
|
2419
|
+
return refreshed;
|
|
1567
2420
|
}
|
|
1568
2421
|
throw new DeeplineError(
|
|
1569
|
-
`Run
|
|
2422
|
+
`Run observation for ${runId} ended before a terminal status.`,
|
|
1570
2423
|
void 0,
|
|
1571
|
-
"
|
|
1572
|
-
{ runId }
|
|
2424
|
+
"PLAY_LIVE_STREAM_ENDED"
|
|
1573
2425
|
);
|
|
1574
2426
|
}
|
|
2427
|
+
/**
|
|
2428
|
+
* Read the canonical run stream until a terminal run status is observed.
|
|
2429
|
+
*
|
|
2430
|
+
* Tries the Convex Run Snapshot subscription transport first (ADR-0008);
|
|
2431
|
+
* when the server cannot serve it (grant endpoint missing/unconfigured or
|
|
2432
|
+
* Convex unreachable) it falls back — with one `onNotice` message — to the
|
|
2433
|
+
* support-window SSE stream below.
|
|
2434
|
+
*
|
|
2435
|
+
* Server stream windows are finite: they end cleanly at the function
|
|
2436
|
+
* ceiling even while the run keeps executing. A window that ends (cleanly
|
|
2437
|
+
* or via transient network error) without a terminal event triggers one
|
|
2438
|
+
* durable-status re-check followed by a backed-off reconnect, so long runs
|
|
2439
|
+
* tail to completion. Abort via `options.signal` to stop waiting.
|
|
2440
|
+
*/
|
|
2441
|
+
async tailRun(runId, options) {
|
|
2442
|
+
try {
|
|
2443
|
+
return await this.tailRunViaObserveTransport(runId, options);
|
|
2444
|
+
} catch (error) {
|
|
2445
|
+
if (!(error instanceof RunObserveTransportUnavailableError)) {
|
|
2446
|
+
throw error;
|
|
2447
|
+
}
|
|
2448
|
+
options?.onNotice?.(
|
|
2449
|
+
`[observe] live subscription unavailable (${error.reason}); falling back to SSE tail (support window, ADR-0008)`
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
const state = {
|
|
2453
|
+
runId,
|
|
2454
|
+
status: "running",
|
|
2455
|
+
logs: [],
|
|
2456
|
+
lastLogSeq: 0,
|
|
2457
|
+
latest: null
|
|
2458
|
+
};
|
|
2459
|
+
let reconnectAttempt = 0;
|
|
2460
|
+
for (; ; ) {
|
|
2461
|
+
const connectedAt = Date.now();
|
|
2462
|
+
let sawEvent = false;
|
|
2463
|
+
let endedReason = "stream window ended before a terminal event";
|
|
2464
|
+
try {
|
|
2465
|
+
for await (const event of this.streamPlayRunEvents(runId, {
|
|
2466
|
+
mode: "cli",
|
|
2467
|
+
signal: options?.signal
|
|
2468
|
+
})) {
|
|
2469
|
+
sawEvent = true;
|
|
2470
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
2471
|
+
if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
2472
|
+
continue;
|
|
2473
|
+
}
|
|
2474
|
+
return await this.getRunStatus(status.runId || runId).catch(
|
|
2475
|
+
() => state.latest ?? playRunStatusFromState(state)
|
|
2476
|
+
);
|
|
2477
|
+
}
|
|
2478
|
+
} catch (error) {
|
|
2479
|
+
if (options?.signal?.aborted || !isTransientPlayStreamError(error)) {
|
|
2480
|
+
throw error;
|
|
2481
|
+
}
|
|
2482
|
+
endedReason = error instanceof Error ? error.message : String(error);
|
|
2483
|
+
}
|
|
2484
|
+
let refreshed = null;
|
|
2485
|
+
try {
|
|
2486
|
+
refreshed = await this.getRunStatus(runId);
|
|
2487
|
+
} catch (error) {
|
|
2488
|
+
if (!isTransientPlayStreamError(error)) {
|
|
2489
|
+
throw error;
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
if (refreshed && TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
|
|
2493
|
+
return refreshed;
|
|
2494
|
+
}
|
|
2495
|
+
if (sawEvent || Date.now() - connectedAt >= STREAM_HEALTHY_CONNECTION_MS) {
|
|
2496
|
+
reconnectAttempt = 0;
|
|
2497
|
+
}
|
|
2498
|
+
const delayMs = streamReconnectDelayMs(reconnectAttempt);
|
|
2499
|
+
reconnectAttempt += 1;
|
|
2500
|
+
options?.onReconnect?.({
|
|
2501
|
+
attempt: reconnectAttempt,
|
|
2502
|
+
delayMs,
|
|
2503
|
+
reason: endedReason
|
|
2504
|
+
});
|
|
2505
|
+
await sleep2(delayMs);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
1575
2508
|
/**
|
|
1576
2509
|
* Fetch persisted logs for a run using the public runs resource model.
|
|
1577
2510
|
*
|
|
@@ -1582,19 +2515,40 @@ var DeeplineClient = class {
|
|
|
1582
2515
|
* ```
|
|
1583
2516
|
*/
|
|
1584
2517
|
async getRunLogs(runId, options) {
|
|
1585
|
-
const
|
|
1586
|
-
const
|
|
1587
|
-
|
|
1588
|
-
|
|
2518
|
+
const limit = options?.all ? Number.MAX_SAFE_INTEGER : typeof options?.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : 200;
|
|
2519
|
+
const fetchPage = (afterSeq2, pageLimit) => this.http.get(
|
|
2520
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/logs?afterSeq=${afterSeq2}&limit=${pageLimit}`
|
|
2521
|
+
);
|
|
2522
|
+
const probe = await fetchPage(0, 1);
|
|
2523
|
+
const lastStoredSeq = probe.lastStoredSeq;
|
|
2524
|
+
let afterSeq = options?.all ? 0 : Math.max(0, lastStoredSeq - limit);
|
|
2525
|
+
const entries = [];
|
|
2526
|
+
while (entries.length < limit) {
|
|
2527
|
+
const page = await fetchPage(
|
|
2528
|
+
afterSeq,
|
|
2529
|
+
Math.min(RUN_LOGS_PAGE_LIMIT, limit - entries.length)
|
|
2530
|
+
);
|
|
2531
|
+
if (page.entries.length === 0) {
|
|
2532
|
+
break;
|
|
2533
|
+
}
|
|
2534
|
+
entries.push(...page.entries);
|
|
2535
|
+
afterSeq = page.entries[page.entries.length - 1].seq;
|
|
2536
|
+
if (!page.hasMore) {
|
|
2537
|
+
break;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
const firstSequence = entries.length > 0 ? entries[0].seq : null;
|
|
2541
|
+
const lastSequence = entries.length > 0 ? entries[entries.length - 1].seq : null;
|
|
1589
2542
|
return {
|
|
1590
|
-
runId:
|
|
1591
|
-
totalCount:
|
|
2543
|
+
runId: probe.runId,
|
|
2544
|
+
totalCount: probe.totalLogCount,
|
|
1592
2545
|
returnedCount: entries.length,
|
|
1593
|
-
firstSequence
|
|
1594
|
-
lastSequence
|
|
1595
|
-
truncated:
|
|
1596
|
-
hasMore:
|
|
1597
|
-
entries
|
|
2546
|
+
firstSequence,
|
|
2547
|
+
lastSequence,
|
|
2548
|
+
truncated: entries.length < probe.totalLogCount,
|
|
2549
|
+
hasMore: lastSequence !== null && lastSequence < lastStoredSeq,
|
|
2550
|
+
entries: entries.map((entry) => entry.line),
|
|
2551
|
+
...probe.logsTruncated ? { logsTruncated: true } : {}
|
|
1598
2552
|
};
|
|
1599
2553
|
}
|
|
1600
2554
|
/**
|
|
@@ -1885,6 +2839,7 @@ var DeeplineClient = class {
|
|
|
1885
2839
|
runId: workflowId,
|
|
1886
2840
|
status: "running",
|
|
1887
2841
|
logs: [],
|
|
2842
|
+
lastLogSeq: 0,
|
|
1888
2843
|
latest: null
|
|
1889
2844
|
};
|
|
1890
2845
|
if (options?.signal?.aborted) {
|
|
@@ -2255,7 +3210,7 @@ var TARGET_FALLBACK_KEYS = {
|
|
|
2255
3210
|
status: [/^email_status$/i, /^status$/i],
|
|
2256
3211
|
email_status: [/^email_status$/i, /^status$/i]
|
|
2257
3212
|
};
|
|
2258
|
-
function
|
|
3213
|
+
function isRecord3(value) {
|
|
2259
3214
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2260
3215
|
}
|
|
2261
3216
|
function toV2RawToolOutputPath(path) {
|
|
@@ -2315,7 +3270,7 @@ function valuesAtSegments(current, segments, path = []) {
|
|
|
2315
3270
|
if (!Array.isArray(current)) return [];
|
|
2316
3271
|
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
2317
3272
|
}
|
|
2318
|
-
if (!
|
|
3273
|
+
if (!isRecord3(current)) return [];
|
|
2319
3274
|
const directMatches = valuesAtSegments(current[segment], rest, [
|
|
2320
3275
|
...path,
|
|
2321
3276
|
segment
|
|
@@ -2345,7 +3300,7 @@ function getValuesAtPath(root, path) {
|
|
|
2345
3300
|
return valuesAtSegments(root, parsePath(path)).map((entry) => entry.value);
|
|
2346
3301
|
}
|
|
2347
3302
|
function toResultEnvelope(value) {
|
|
2348
|
-
if (
|
|
3303
|
+
if (isRecord3(value) && "data" in value) {
|
|
2349
3304
|
const envelope = { data: value.data };
|
|
2350
3305
|
if ("meta" in value) envelope.meta = value.meta;
|
|
2351
3306
|
return envelope;
|
|
@@ -2398,7 +3353,7 @@ function getAtPath(root, path) {
|
|
|
2398
3353
|
current = current[segment];
|
|
2399
3354
|
continue;
|
|
2400
3355
|
}
|
|
2401
|
-
if (!
|
|
3356
|
+
if (!isRecord3(current)) return void 0;
|
|
2402
3357
|
current = current[segment];
|
|
2403
3358
|
}
|
|
2404
3359
|
return current;
|
|
@@ -2415,7 +3370,7 @@ function normalizeString(value) {
|
|
|
2415
3370
|
}
|
|
2416
3371
|
function normalizeRows(value) {
|
|
2417
3372
|
if (!Array.isArray(value)) return null;
|
|
2418
|
-
return value.map((entry) =>
|
|
3373
|
+
return value.map((entry) => isRecord3(entry) ? entry : { value: entry });
|
|
2419
3374
|
}
|
|
2420
3375
|
function findFirstTargetByPath(result, paths) {
|
|
2421
3376
|
for (const path of paths ?? []) {
|
|
@@ -2474,7 +3429,7 @@ function findFirstTargetByKey(result, target, depth = 0, path = []) {
|
|
|
2474
3429
|
}
|
|
2475
3430
|
return null;
|
|
2476
3431
|
}
|
|
2477
|
-
if (!
|
|
3432
|
+
if (!isRecord3(result)) return null;
|
|
2478
3433
|
const patterns = TARGET_FALLBACK_KEYS[target] ?? [
|
|
2479
3434
|
new RegExp(`^${target}$`, "i")
|
|
2480
3435
|
];
|
|
@@ -2534,7 +3489,7 @@ function normalizeJobChangeStatus(value) {
|
|
|
2534
3489
|
function firstExperienceDate(value) {
|
|
2535
3490
|
if (!Array.isArray(value)) return null;
|
|
2536
3491
|
for (const entry of value) {
|
|
2537
|
-
if (!
|
|
3492
|
+
if (!isRecord3(entry)) continue;
|
|
2538
3493
|
const date = normalizeString(
|
|
2539
3494
|
entry.start_date ?? entry.started_at ?? entry.startDate
|
|
2540
3495
|
);
|
|
@@ -2543,10 +3498,10 @@ function firstExperienceDate(value) {
|
|
|
2543
3498
|
return null;
|
|
2544
3499
|
}
|
|
2545
3500
|
function normalizeJobChange(value) {
|
|
2546
|
-
const record =
|
|
2547
|
-
const nested =
|
|
2548
|
-
const output =
|
|
2549
|
-
const person =
|
|
3501
|
+
const record = isRecord3(value) ? value : {};
|
|
3502
|
+
const nested = isRecord3(record.job_change) ? record.job_change : record;
|
|
3503
|
+
const output = isRecord3(nested.output) ? nested.output : nested;
|
|
3504
|
+
const person = isRecord3(output.person) ? output.person : {};
|
|
2550
3505
|
const status = normalizeJobChangeStatus(
|
|
2551
3506
|
output.status ?? output.job_change_status ?? output.job_changed ?? output.changed
|
|
2552
3507
|
);
|
|
@@ -3114,11 +4069,11 @@ var Deepline = class {
|
|
|
3114
4069
|
return new DeeplineContext(options);
|
|
3115
4070
|
}
|
|
3116
4071
|
};
|
|
3117
|
-
function
|
|
4072
|
+
function isRecord4(value) {
|
|
3118
4073
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3119
4074
|
}
|
|
3120
4075
|
function stringArrayRecord(value) {
|
|
3121
|
-
if (!
|
|
4076
|
+
if (!isRecord4(value)) return {};
|
|
3122
4077
|
return Object.fromEntries(
|
|
3123
4078
|
Object.entries(value).map(([key, paths]) => [
|
|
3124
4079
|
key,
|
|
@@ -3130,10 +4085,10 @@ function stringArray(value) {
|
|
|
3130
4085
|
return Array.isArray(value) ? value.map(String) : [];
|
|
3131
4086
|
}
|
|
3132
4087
|
function extractorDescriptorRecord(value) {
|
|
3133
|
-
if (!
|
|
4088
|
+
if (!isRecord4(value)) return {};
|
|
3134
4089
|
return Object.fromEntries(
|
|
3135
4090
|
Object.entries(value).flatMap(([key, descriptor]) => {
|
|
3136
|
-
if (!
|
|
4091
|
+
if (!isRecord4(descriptor)) return [];
|
|
3137
4092
|
const paths = stringArray(descriptor.paths).map((path) => path.trim()).filter(Boolean);
|
|
3138
4093
|
if (paths.length === 0) return [];
|
|
3139
4094
|
const transforms = stringArray(descriptor.transforms).map((transform) => transform.trim()).filter(Boolean);
|
|
@@ -3154,14 +4109,14 @@ function extractorDescriptorRecord(value) {
|
|
|
3154
4109
|
function toolExecutionEnvelopeToResult(fallbackToolId, response) {
|
|
3155
4110
|
const raw = response.toolResponse?.raw ?? null;
|
|
3156
4111
|
const meta = response.toolResponse?.meta;
|
|
3157
|
-
const metadata =
|
|
3158
|
-
const toolMetadata =
|
|
4112
|
+
const metadata = isRecord4(response._metadata) ? response._metadata.tool : null;
|
|
4113
|
+
const toolMetadata = isRecord4(metadata) ? metadata : {};
|
|
3159
4114
|
return createToolExecuteResult({
|
|
3160
4115
|
status: typeof response.status === "string" ? response.status : "completed",
|
|
3161
4116
|
jobId: typeof response.job_id === "string" ? response.job_id : void 0,
|
|
3162
4117
|
result: {
|
|
3163
4118
|
data: raw,
|
|
3164
|
-
...
|
|
4119
|
+
...isRecord4(meta) ? { meta } : {}
|
|
3165
4120
|
},
|
|
3166
4121
|
metadata: {
|
|
3167
4122
|
toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
|
|
@@ -3175,7 +4130,7 @@ function toolExecutionEnvelopeToResult(fallbackToolId, response) {
|
|
|
3175
4130
|
cached: false,
|
|
3176
4131
|
source: "live"
|
|
3177
4132
|
},
|
|
3178
|
-
meta:
|
|
4133
|
+
meta: isRecord4(response.meta) ? response.meta : void 0
|
|
3179
4134
|
});
|
|
3180
4135
|
}
|
|
3181
4136
|
function defineInput(schema) {
|
|
@@ -3477,6 +4432,7 @@ function extractSummaryFields(payload) {
|
|
|
3477
4432
|
PLAY_BOOTSTRAP_TEMPLATES,
|
|
3478
4433
|
PROD_URL,
|
|
3479
4434
|
RateLimitError,
|
|
4435
|
+
RunObserveTransportUnavailableError,
|
|
3480
4436
|
SDK_API_CONTRACT,
|
|
3481
4437
|
SDK_VERSION,
|
|
3482
4438
|
defineInput,
|