@opengeni/worker-bundle 0.27.3 → 0.28.3-canary.0
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/activities/agent-turn/model-usage.d.ts +1 -1
- package/dist/activities/mcp-credentials.d.ts +3 -1
- package/dist/activities/sandbox-lease.d.ts +4 -4
- package/dist/activities/workspace-capture.d.ts +12 -1
- package/dist/{activities-control-WZRFEIJH.js → activities-control-JUBMDBDZ.js} +58 -73
- package/dist/activities-control-JUBMDBDZ.js.map +1 -0
- package/dist/{activities-turn-V7J34ZOF.js → activities-turn-I2ZKGZE6.js} +268 -187
- package/dist/activities-turn-I2ZKGZE6.js.map +1 -0
- package/dist/{chunk-BARTLVBK.js → chunk-A4XQWVZK.js} +25 -25
- package/dist/chunk-A4XQWVZK.js.map +1 -0
- package/dist/{chunk-C54VDT6I.js → chunk-ZNIKZQMN.js} +148 -111
- package/dist/chunk-ZNIKZQMN.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/observability-metrics.d.ts +12 -4
- package/dist/sandbox-archive-storage.d.ts +15 -3
- package/dist/sandbox-resume.d.ts +1 -1
- package/package.json +17 -17
- package/src/activities/agent-turn/agent-build.ts +30 -1
- package/src/activities/agent-turn/claim.ts +3 -3
- package/src/activities/agent-turn/finalization.ts +62 -41
- package/src/activities/agent-turn/model-usage.ts +10 -1
- package/src/activities/agent-turn/skill-read.ts +2 -21
- package/src/activities/agent-turn/stream-attempt.ts +3 -2
- package/src/activities/agent-turn/tool-environment.ts +52 -10
- package/src/activities/goals.ts +2 -0
- package/src/activities/mcp-credentials.ts +42 -2
- package/src/activities/sandbox-lease.ts +64 -71
- package/src/activities/scheduled-tasks.ts +8 -6
- package/src/activities/workspace-capture.ts +148 -126
- package/src/observability-metrics.ts +28 -24
- package/src/pr-review-credentials.ts +2 -0
- package/src/sandbox-archive-storage.ts +82 -18
- package/src/sandbox-resume.ts +79 -63
- package/dist/activities-control-WZRFEIJH.js.map +0 -1
- package/dist/activities-turn-V7J34ZOF.js.map +0 -1
- package/dist/chunk-BARTLVBK.js.map +0 -1
- package/dist/chunk-C54VDT6I.js.map +0 -1
|
@@ -86,7 +86,7 @@ import {
|
|
|
86
86
|
withFirstPartyTools,
|
|
87
87
|
wrapLazyTurnBoxWithRouting,
|
|
88
88
|
wrapTurnBoxWithRouting
|
|
89
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-ZNIKZQMN.js";
|
|
90
90
|
import {
|
|
91
91
|
StreamTimingMetrics,
|
|
92
92
|
makeMachineOpObserver,
|
|
@@ -112,7 +112,7 @@ import {
|
|
|
112
112
|
recordTurnWorkerPreparationTotal,
|
|
113
113
|
runtimeMetricsHooksForObservability,
|
|
114
114
|
turnLifecycleMetricsFor
|
|
115
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-A4XQWVZK.js";
|
|
116
116
|
|
|
117
117
|
// src/activities-turn.ts
|
|
118
118
|
import { createProductionAgentRuntime, summarizeForCompaction as summarizeForCompaction2 } from "@opengeni/runtime";
|
|
@@ -3550,6 +3550,7 @@ function createTurnContext(input) {
|
|
|
3550
3550
|
// src/activities/agent-turn/finalization.ts
|
|
3551
3551
|
import {
|
|
3552
3552
|
commitSessionAttemptQuiescence,
|
|
3553
|
+
listPendingSessionTurns,
|
|
3553
3554
|
recordCodexAccountUsageWithWakeTargets,
|
|
3554
3555
|
releaseCodexCredentialLease,
|
|
3555
3556
|
releaseXaiCredentialLease,
|
|
@@ -3713,6 +3714,50 @@ async function readCaptureRepository(svc, root) {
|
|
|
3713
3714
|
}
|
|
3714
3715
|
}
|
|
3715
3716
|
var loggedStorageNullOnce = false;
|
|
3717
|
+
async function captureWhileIdle(input) {
|
|
3718
|
+
if (input.signal?.aborted) return;
|
|
3719
|
+
const controller = new AbortController();
|
|
3720
|
+
const signal = input.signal ? AbortSignal.any([input.signal, controller.signal]) : controller.signal;
|
|
3721
|
+
let checking = false;
|
|
3722
|
+
let stopped = false;
|
|
3723
|
+
const check = async () => {
|
|
3724
|
+
if (checking || stopped || signal.aborted) return;
|
|
3725
|
+
checking = true;
|
|
3726
|
+
try {
|
|
3727
|
+
let timer2;
|
|
3728
|
+
let onAbort;
|
|
3729
|
+
try {
|
|
3730
|
+
const pending = await Promise.race([
|
|
3731
|
+
input.hasPendingWork(),
|
|
3732
|
+
new Promise((resolve) => {
|
|
3733
|
+
onAbort = () => resolve(true);
|
|
3734
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3735
|
+
timer2 = setTimeout(() => resolve(true), 1e3);
|
|
3736
|
+
})
|
|
3737
|
+
]);
|
|
3738
|
+
if (pending) controller.abort();
|
|
3739
|
+
} finally {
|
|
3740
|
+
clearTimeout(timer2);
|
|
3741
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
3742
|
+
}
|
|
3743
|
+
} catch {
|
|
3744
|
+
controller.abort();
|
|
3745
|
+
} finally {
|
|
3746
|
+
checking = false;
|
|
3747
|
+
}
|
|
3748
|
+
};
|
|
3749
|
+
await check();
|
|
3750
|
+
if (signal.aborted) return;
|
|
3751
|
+
const timer = setInterval(() => void check(), 250);
|
|
3752
|
+
timer.unref?.();
|
|
3753
|
+
try {
|
|
3754
|
+
await input.capture(signal);
|
|
3755
|
+
} finally {
|
|
3756
|
+
stopped = true;
|
|
3757
|
+
clearInterval(timer);
|
|
3758
|
+
controller.abort();
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3716
3761
|
async function captureWorkspaceRevision(input) {
|
|
3717
3762
|
const { observability } = input;
|
|
3718
3763
|
const stage = { value: "preflight" };
|
|
@@ -3755,13 +3800,23 @@ async function captureWorkspaceRevision(input) {
|
|
|
3755
3800
|
name: "opengeni_workspace_captures_inflight",
|
|
3756
3801
|
help: "Current workspace-capture operations still resident in this worker process."
|
|
3757
3802
|
});
|
|
3803
|
+
const ownership = { keys: /* @__PURE__ */ new Set(), retain: false };
|
|
3758
3804
|
const capture = runCapture(
|
|
3759
3805
|
input,
|
|
3760
3806
|
{ ...input, objectStorage: input.objectStorage },
|
|
3761
3807
|
startedAt,
|
|
3762
3808
|
controller.signal,
|
|
3763
|
-
stage
|
|
3764
|
-
|
|
3809
|
+
stage,
|
|
3810
|
+
ownership
|
|
3811
|
+
).finally(async () => {
|
|
3812
|
+
if (!ownership.retain && ownership.keys.size > 0) {
|
|
3813
|
+
await safeDelete(
|
|
3814
|
+
input.objectStorage,
|
|
3815
|
+
[...ownership.keys],
|
|
3816
|
+
observability,
|
|
3817
|
+
new AbortController().signal
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3765
3820
|
observability.incrementGauge({
|
|
3766
3821
|
name: "opengeni_workspace_captures_inflight",
|
|
3767
3822
|
help: "Current workspace-capture operations still resident in this worker process.",
|
|
@@ -3788,13 +3843,17 @@ async function captureWorkspaceRevision(input) {
|
|
|
3788
3843
|
});
|
|
3789
3844
|
return;
|
|
3790
3845
|
}
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3846
|
+
const reason = controller.signal.aborted ? "deadline_exceeded" : isBoxExitingError(error) ? "sandbox_exited" : "operation_failed";
|
|
3847
|
+
observability.warn(
|
|
3848
|
+
`workspace capture failed \u2014 stage=${stage.value} reason=${reason} durationMs=${Date.now() - startedAt}; review cache not updated`,
|
|
3849
|
+
{
|
|
3850
|
+
"opengeni.session_id": input.sessionId,
|
|
3851
|
+
"opengeni.turn_id": input.turnId ?? "",
|
|
3852
|
+
"error.message": error instanceof Error ? error.message : String(error),
|
|
3853
|
+
"workspace_capture.duration_ms": Date.now() - startedAt,
|
|
3854
|
+
"workspace_capture.stage": stage.value
|
|
3855
|
+
}
|
|
3856
|
+
);
|
|
3798
3857
|
observability.incrementCounter({
|
|
3799
3858
|
name: "opengeni_workspace_capture_total",
|
|
3800
3859
|
labels: { result: "failed" }
|
|
@@ -3805,7 +3864,8 @@ async function captureWorkspaceRevision(input) {
|
|
|
3805
3864
|
controller.abort();
|
|
3806
3865
|
}
|
|
3807
3866
|
}
|
|
3808
|
-
async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
3867
|
+
async function runCapture(input, ctx, startedAt, signal, stage, ownership) {
|
|
3868
|
+
const ownedKeys = ownership.keys;
|
|
3809
3869
|
const { observability } = input;
|
|
3810
3870
|
const storage = ctx.objectStorage;
|
|
3811
3871
|
const keepN = input.keepLatest ?? KEEP_LATEST_REVISIONS;
|
|
@@ -3892,6 +3952,13 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
3892
3952
|
}
|
|
3893
3953
|
const files = [];
|
|
3894
3954
|
const blobKeys = /* @__PURE__ */ new Set();
|
|
3955
|
+
const captureId = crypto.randomUUID();
|
|
3956
|
+
const retainedRefs = retainedCaptureBlobRefs(
|
|
3957
|
+
input.workspaceId,
|
|
3958
|
+
input.sessionId,
|
|
3959
|
+
prev?.blobKeys ?? []
|
|
3960
|
+
);
|
|
3961
|
+
const storedKeys = new Set(retainedRefs.values());
|
|
3895
3962
|
let totalBytes = 0;
|
|
3896
3963
|
let tooLargeCount = 0;
|
|
3897
3964
|
let binaryCount = 0;
|
|
@@ -3921,6 +3988,7 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
3921
3988
|
});
|
|
3922
3989
|
throwIfCaptureAborted(signal);
|
|
3923
3990
|
} catch (error) {
|
|
3991
|
+
if (signal.aborted) throw error;
|
|
3924
3992
|
const boxExiting = classifyCaptureEntryError(error);
|
|
3925
3993
|
if (boxExiting) throw boxExiting;
|
|
3926
3994
|
continue;
|
|
@@ -3942,7 +4010,7 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
3942
4010
|
}
|
|
3943
4011
|
const bytes = Buffer.from(read.content, "base64");
|
|
3944
4012
|
const hash = sha256(bytes);
|
|
3945
|
-
const contentRef = blobKey(input.workspaceId, input.sessionId, hash);
|
|
4013
|
+
const contentRef = retainedRefs.get(hash) ?? blobKey(input.workspaceId, input.sessionId, `${captureId}/${hash}`);
|
|
3946
4014
|
if (read.isBinary) binaryCount += 1;
|
|
3947
4015
|
if (!blobKeys.has(contentRef)) {
|
|
3948
4016
|
totalBytes += bytes.byteLength;
|
|
@@ -3959,6 +4027,17 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
3959
4027
|
}
|
|
3960
4028
|
}
|
|
3961
4029
|
blobKeys.add(contentRef);
|
|
4030
|
+
if (!storedKeys.has(contentRef)) {
|
|
4031
|
+
stage.value = "content_upload";
|
|
4032
|
+
ownedKeys.add(contentRef);
|
|
4033
|
+
await storage.putObject({
|
|
4034
|
+
key: contentRef,
|
|
4035
|
+
contentType: "application/octet-stream",
|
|
4036
|
+
body: bytes
|
|
4037
|
+
});
|
|
4038
|
+
throwIfCaptureAborted(signal);
|
|
4039
|
+
storedKeys.add(contentRef);
|
|
4040
|
+
}
|
|
3962
4041
|
files.push({
|
|
3963
4042
|
// baseHash (git HEAD blob sha) is intentionally null in M1: the wake-on-edit
|
|
3964
4043
|
// flush guard (M3/C2) compares live content against the after-image `hash`,
|
|
@@ -3975,7 +4054,7 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
3975
4054
|
deleted: false
|
|
3976
4055
|
});
|
|
3977
4056
|
}
|
|
3978
|
-
|
|
4057
|
+
const fingerprint = changeFingerprint(repos, files);
|
|
3979
4058
|
if (prev && prev.stats.fingerprint === fingerprint) {
|
|
3980
4059
|
observability.incrementCounter({
|
|
3981
4060
|
name: "opengeni_workspace_capture_total",
|
|
@@ -3986,102 +4065,9 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
3986
4065
|
stage.value = "tree_index";
|
|
3987
4066
|
const tree = await buildTreeIndex(svc, startedAt, signal);
|
|
3988
4067
|
throwIfCaptureAborted(signal);
|
|
3989
|
-
const turnKey = input.turnId
|
|
4068
|
+
const turnKey = `${input.turnId}/${captureId}`;
|
|
3990
4069
|
const treeKey = `workspace-captures/${input.workspaceId}/${input.sessionId}/trees/${turnKey}.json`;
|
|
3991
4070
|
const manifestKey = `workspace-captures/${input.workspaceId}/${input.sessionId}/manifests/${turnKey}.json`;
|
|
3992
|
-
const uploadedKeys = /* @__PURE__ */ new Set();
|
|
3993
|
-
blobKeys.clear();
|
|
3994
|
-
totalBytes = 0;
|
|
3995
|
-
let refreshedFiles = 0;
|
|
3996
|
-
const omittedFiles = /* @__PURE__ */ new Set();
|
|
3997
|
-
for (const file of files) {
|
|
3998
|
-
stage.value = "content_upload";
|
|
3999
|
-
throwIfCaptureAborted(signal);
|
|
4000
|
-
if (file.deleted || file.tooLarge || !file.contentRef || !file.hash) {
|
|
4001
|
-
continue;
|
|
4002
|
-
}
|
|
4003
|
-
let reread;
|
|
4004
|
-
try {
|
|
4005
|
-
reread = await svc.fsRead({
|
|
4006
|
-
path: file.path,
|
|
4007
|
-
encoding: "base64",
|
|
4008
|
-
maxBytes: PER_FILE_CONTENT_GUARD_BYTES
|
|
4009
|
-
});
|
|
4010
|
-
throwIfCaptureAborted(signal);
|
|
4011
|
-
} catch (error) {
|
|
4012
|
-
if (signal.aborted) throw error;
|
|
4013
|
-
const boxExiting = classifyCaptureEntryError(error);
|
|
4014
|
-
if (boxExiting) throw boxExiting;
|
|
4015
|
-
omittedFiles.add(file.path);
|
|
4016
|
-
refreshedFiles += 1;
|
|
4017
|
-
continue;
|
|
4018
|
-
}
|
|
4019
|
-
if (reread.truncated) {
|
|
4020
|
-
file.hash = null;
|
|
4021
|
-
file.contentRef = null;
|
|
4022
|
-
file.sizeBytes = reread.sizeBytes;
|
|
4023
|
-
file.isBinary = reread.isBinary;
|
|
4024
|
-
file.tooLarge = true;
|
|
4025
|
-
refreshedFiles += 1;
|
|
4026
|
-
continue;
|
|
4027
|
-
}
|
|
4028
|
-
const bytes = Buffer.from(reread.content, "base64");
|
|
4029
|
-
const hash = sha256(bytes);
|
|
4030
|
-
const contentRef = blobKey(input.workspaceId, input.sessionId, hash);
|
|
4031
|
-
if (hash !== file.hash || bytes.byteLength !== file.sizeBytes || reread.isBinary !== file.isBinary) {
|
|
4032
|
-
file.hash = hash;
|
|
4033
|
-
file.contentRef = contentRef;
|
|
4034
|
-
file.sizeBytes = bytes.byteLength;
|
|
4035
|
-
file.isBinary = reread.isBinary;
|
|
4036
|
-
refreshedFiles += 1;
|
|
4037
|
-
}
|
|
4038
|
-
if (!blobKeys.has(contentRef)) {
|
|
4039
|
-
totalBytes += bytes.byteLength;
|
|
4040
|
-
if (totalBytes > WHOLE_CAPTURE_GUARD_BYTES) {
|
|
4041
|
-
observability.warn("workspace capture skipped \u2014 whole-capture guard tripped", {
|
|
4042
|
-
"opengeni.session_id": input.sessionId,
|
|
4043
|
-
"workspace_capture.total_bytes": totalBytes
|
|
4044
|
-
});
|
|
4045
|
-
observability.incrementCounter({
|
|
4046
|
-
name: "opengeni_workspace_capture_total",
|
|
4047
|
-
labels: { result: "guard_tripped" }
|
|
4048
|
-
});
|
|
4049
|
-
return;
|
|
4050
|
-
}
|
|
4051
|
-
}
|
|
4052
|
-
blobKeys.add(contentRef);
|
|
4053
|
-
if (!uploadedKeys.has(contentRef)) {
|
|
4054
|
-
await storage.putObject({
|
|
4055
|
-
key: contentRef,
|
|
4056
|
-
contentType: "application/octet-stream",
|
|
4057
|
-
body: bytes
|
|
4058
|
-
});
|
|
4059
|
-
throwIfCaptureAborted(signal);
|
|
4060
|
-
uploadedKeys.add(contentRef);
|
|
4061
|
-
}
|
|
4062
|
-
}
|
|
4063
|
-
if (omittedFiles.size > 0) {
|
|
4064
|
-
for (let index = files.length - 1; index >= 0; index -= 1) {
|
|
4065
|
-
const file = files[index];
|
|
4066
|
-
if (file && omittedFiles.has(file.path)) files.splice(index, 1);
|
|
4067
|
-
}
|
|
4068
|
-
}
|
|
4069
|
-
if (refreshedFiles > 0) {
|
|
4070
|
-
observability.incrementCounter({
|
|
4071
|
-
name: "opengeni_workspace_capture_files_refreshed_total",
|
|
4072
|
-
amount: refreshedFiles
|
|
4073
|
-
});
|
|
4074
|
-
}
|
|
4075
|
-
tooLargeCount = files.filter((file) => file.tooLarge).length;
|
|
4076
|
-
binaryCount = files.filter((file) => !file.deleted && file.isBinary).length;
|
|
4077
|
-
fingerprint = changeFingerprint(repos, files);
|
|
4078
|
-
if (prev && prev.stats.fingerprint === fingerprint) {
|
|
4079
|
-
observability.incrementCounter({
|
|
4080
|
-
name: "opengeni_workspace_capture_total",
|
|
4081
|
-
labels: { result: "skipped_empty" }
|
|
4082
|
-
});
|
|
4083
|
-
return;
|
|
4084
|
-
}
|
|
4085
4071
|
const capturedAt = /* @__PURE__ */ new Date();
|
|
4086
4072
|
const stats = {
|
|
4087
4073
|
repoCount: repos.length,
|
|
@@ -4118,11 +4104,13 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
4118
4104
|
})
|
|
4119
4105
|
);
|
|
4120
4106
|
stage.value = "tree_upload";
|
|
4107
|
+
ownedKeys.add(treeKey);
|
|
4121
4108
|
await storage.putObject({ key: treeKey, contentType: "application/json", body: treeBytes });
|
|
4122
4109
|
throwIfCaptureAborted(signal);
|
|
4123
4110
|
stats.durationMs = Date.now() - startedAt;
|
|
4124
4111
|
const manifestBytes = utf8(JSON.stringify(manifest));
|
|
4125
4112
|
stage.value = "manifest_upload";
|
|
4113
|
+
ownedKeys.add(manifestKey);
|
|
4126
4114
|
await storage.putObject({
|
|
4127
4115
|
key: manifestKey,
|
|
4128
4116
|
contentType: "application/json",
|
|
@@ -4131,6 +4119,7 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
4131
4119
|
throwIfCaptureAborted(signal);
|
|
4132
4120
|
const sizeBytes = totalBytes + treeBytes.byteLength + manifestBytes.byteLength;
|
|
4133
4121
|
stage.value = "database_commit";
|
|
4122
|
+
ownership.retain = true;
|
|
4134
4123
|
const inserted = await insertWorkspaceCapture(input.db, {
|
|
4135
4124
|
accountId: input.accountId,
|
|
4136
4125
|
workspaceId: input.workspaceId,
|
|
@@ -4147,6 +4136,7 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
4147
4136
|
stats,
|
|
4148
4137
|
capturedAt
|
|
4149
4138
|
});
|
|
4139
|
+
ownership.retain = inserted !== null;
|
|
4150
4140
|
if (process.env.OPENGENI_TEST_SCENARIO === "sandbox") {
|
|
4151
4141
|
console.log(
|
|
4152
4142
|
`[sandbox-e2e] capture commit inserted=${Boolean(inserted)} revision=${revision} epoch=${input.leaseEpoch} group=${input.sandboxGroupId}`
|
|
@@ -4164,6 +4154,7 @@ async function runCapture(input, ctx, startedAt, signal, stage) {
|
|
|
4164
4154
|
if (input.publish) {
|
|
4165
4155
|
await input.publish(inserted.events).catch(() => void 0);
|
|
4166
4156
|
}
|
|
4157
|
+
stage.value = "garbage_collection";
|
|
4167
4158
|
let gcDeleted = 0;
|
|
4168
4159
|
try {
|
|
4169
4160
|
throwIfCaptureAborted(signal);
|
|
@@ -4323,6 +4314,16 @@ function utf8(s) {
|
|
|
4323
4314
|
function blobKey(workspaceId, sessionId, sha256Hex) {
|
|
4324
4315
|
return `workspace-captures/${workspaceId}/${sessionId}/blobs/${sha256Hex}`;
|
|
4325
4316
|
}
|
|
4317
|
+
function retainedCaptureBlobRefs(workspaceId, sessionId, latestKeys) {
|
|
4318
|
+
const prefix = blobKey(workspaceId, sessionId, "");
|
|
4319
|
+
const refs = /* @__PURE__ */ new Map();
|
|
4320
|
+
for (const key of latestKeys) {
|
|
4321
|
+
if (!key.startsWith(prefix)) continue;
|
|
4322
|
+
const match = /^(?:[0-9a-f-]{36}\/)?([0-9a-f]{64})$/.exec(key.slice(prefix.length));
|
|
4323
|
+
if (match?.[1]) refs.set(match[1], key);
|
|
4324
|
+
}
|
|
4325
|
+
return refs;
|
|
4326
|
+
}
|
|
4326
4327
|
async function safeDelete(storage, keys, observability, signal) {
|
|
4327
4328
|
for (const key of keys) {
|
|
4328
4329
|
throwIfCaptureAborted(signal);
|
|
@@ -4692,39 +4693,49 @@ async function finalizeTurnAttempt(deps) {
|
|
|
4692
4693
|
cancellationRequested: finalizerSignal?.aborted === true,
|
|
4693
4694
|
deadlineRotationRequested: sandboxState.deadlineRotationRequested
|
|
4694
4695
|
});
|
|
4695
|
-
if (runTurnEndPersistence && attempt.turnId && sandboxState.resolvedSandbox && sandboxState.setupBoxSession && sandboxState.sandboxGroupId) {
|
|
4696
|
+
if (settings.workspaceCaptureEnabled && runTurnEndPersistence && attempt.turnId && sandboxState.resolvedSandbox && sandboxState.setupBoxSession && sandboxState.sandboxGroupId) {
|
|
4696
4697
|
sandboxState.turnEndCaptureInProgress = true;
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4698
|
+
const captureSandbox = sandboxState.resolvedSandbox;
|
|
4699
|
+
const captureSession = sandboxState.setupBoxSession;
|
|
4700
|
+
const captureGroupId = sandboxState.sandboxGroupId;
|
|
4701
|
+
const captureTurnId = attempt.turnId;
|
|
4702
|
+
await captureWhileIdle({
|
|
4703
|
+
...finalizerSignal ? { signal: finalizerSignal } : {},
|
|
4704
|
+
hasPendingWork: async () => (await listPendingSessionTurns(db, input.workspaceId, input.sessionId)).some(
|
|
4705
|
+
(turn) => turn.id !== captureTurnId
|
|
4706
|
+
),
|
|
4707
|
+
capture: async (signal) => {
|
|
4708
|
+
if (sandboxState.snapshotInFlight) {
|
|
4709
|
+
await waitForWarmSnapshot(
|
|
4710
|
+
sandboxState.snapshotInFlight,
|
|
4711
|
+
settings.sandboxSnapshotTimeoutMs,
|
|
4712
|
+
signal
|
|
4713
|
+
);
|
|
4714
|
+
}
|
|
4715
|
+
if (signal.aborted) return;
|
|
4716
|
+
await captureWorkspaceRevision({
|
|
4717
|
+
db,
|
|
4718
|
+
objectStorage,
|
|
4719
|
+
settings,
|
|
4720
|
+
publish: async (events) => publishDurableSessionEvents(bus, input.workspaceId, input.sessionId, events),
|
|
4721
|
+
session: captureSession,
|
|
4722
|
+
openReadSession: async () => openFreshWorkspaceCaptureSession({
|
|
4723
|
+
backendId: captureSandbox.established.backendId,
|
|
4724
|
+
client: captureSandbox.established.client,
|
|
4725
|
+
session: captureSession,
|
|
4726
|
+
expectedInstanceId: captureSandbox.established.instanceId
|
|
4727
|
+
}),
|
|
4728
|
+
leaseEpoch: captureSandbox.leaseEpoch,
|
|
4729
|
+
sandboxGroupId: captureGroupId,
|
|
4730
|
+
accountId: input.accountId,
|
|
4731
|
+
workspaceId: input.workspaceId,
|
|
4732
|
+
sessionId: input.sessionId,
|
|
4733
|
+
turnId: captureTurnId,
|
|
4734
|
+
attemptId: input.attemptId,
|
|
4735
|
+
observability,
|
|
4736
|
+
signal
|
|
4737
|
+
});
|
|
4738
|
+
}
|
|
4728
4739
|
});
|
|
4729
4740
|
}
|
|
4730
4741
|
eventing.toolPreparationClosing = true;
|
|
@@ -4879,12 +4890,12 @@ async function finalizeTurnAttempt(deps) {
|
|
|
4879
4890
|
status: finalizationError ? "cleanup_failed" : control.activityStatus,
|
|
4880
4891
|
durationSeconds
|
|
4881
4892
|
});
|
|
4882
|
-
if (attempt.turnId
|
|
4883
|
-
turnLifecycleMetricsFor(observability).finish(
|
|
4884
|
-
|
|
4885
|
-
control.turnMetricOutcome,
|
|
4893
|
+
if (attempt.turnId) {
|
|
4894
|
+
turnLifecycleMetricsFor(observability).finish({
|
|
4895
|
+
attemptId: input.attemptId,
|
|
4896
|
+
outcome: control.turnMetricOutcome,
|
|
4886
4897
|
durationSeconds
|
|
4887
|
-
);
|
|
4898
|
+
});
|
|
4888
4899
|
}
|
|
4889
4900
|
activitySpan.end({
|
|
4890
4901
|
attributes: {
|
|
@@ -4995,8 +5006,13 @@ function createCompactionModelUsageEventState(claimedSourceKeys = /* @__PURE__ *
|
|
|
4995
5006
|
return { usageCount: 0, claimedSourceKeys };
|
|
4996
5007
|
}
|
|
4997
5008
|
var createSessionTitleModelUsageEventState = createCompactionModelUsageEventState;
|
|
4998
|
-
function modelResponseContextSignal(state) {
|
|
4999
|
-
|
|
5009
|
+
function modelResponseContextSignal(state, responseCountBeforeStream = 0) {
|
|
5010
|
+
const signal = state.contextSignal;
|
|
5011
|
+
if (!signal || signal.revision <= responseCountBeforeStream) return null;
|
|
5012
|
+
return {
|
|
5013
|
+
revision: signal.revision - responseCountBeforeStream,
|
|
5014
|
+
totalTokens: signal.totalTokens
|
|
5015
|
+
};
|
|
5000
5016
|
}
|
|
5001
5017
|
function assertModelResponseLatencyMode(input) {
|
|
5002
5018
|
if (input.requested === "standard") {
|
|
@@ -8250,7 +8266,7 @@ async function runTurnStreamAttempt(deps) {
|
|
|
8250
8266
|
await toolResultSpill.materializeDeferred();
|
|
8251
8267
|
}
|
|
8252
8268
|
} : {},
|
|
8253
|
-
contextCompactionSignal: () => modelResponseContextSignal(modelResponseState),
|
|
8269
|
+
contextCompactionSignal: () => modelResponseContextSignal(modelResponseState, responseCountBeforeStream),
|
|
8254
8270
|
contextCompactionRequested: () => isSessionCompactionRequested(db, input.workspaceId, input.sessionId),
|
|
8255
8271
|
onModelPreparationPhase: (measurement) => {
|
|
8256
8272
|
recordTurnStartupPhase(observability, {
|
|
@@ -8427,7 +8443,7 @@ async function runTurnStreamAttempt(deps) {
|
|
|
8427
8443
|
currentToolBatchCallIds = /* @__PURE__ */ new Set();
|
|
8428
8444
|
currentToolBatchCompletedCallIds = /* @__PURE__ */ new Set();
|
|
8429
8445
|
await historySink.reconcileConversationTruth();
|
|
8430
|
-
turnLifecycleMetricsFor(observability).progress(
|
|
8446
|
+
turnLifecycleMetricsFor(observability).progress({ attemptId: input.attemptId });
|
|
8431
8447
|
modelCheckpointMemoryCollector.schedule(observability);
|
|
8432
8448
|
try {
|
|
8433
8449
|
await ensureRunAllowed(
|
|
@@ -9535,7 +9551,7 @@ async function claimTurnAttempt(deps) {
|
|
|
9535
9551
|
});
|
|
9536
9552
|
return attached.action === "claimed" && attached.turn.id === turn.id;
|
|
9537
9553
|
};
|
|
9538
|
-
turnLifecycleMetricsFor(observability).start(
|
|
9554
|
+
turnLifecycleMetricsFor(observability).start({ attemptId: input.attemptId });
|
|
9539
9555
|
await waitForTurnOperation(
|
|
9540
9556
|
ensureRunAllowed(
|
|
9541
9557
|
capabilitySettings,
|
|
@@ -9613,7 +9629,7 @@ async function claimTurnAttempt(deps) {
|
|
|
9613
9629
|
}
|
|
9614
9630
|
recordCanonicalStartupMilestones(appended.canonicalStartupMilestones);
|
|
9615
9631
|
if (inputs.length > 0) {
|
|
9616
|
-
turnLifecycleMetricsFor(observability).progress(
|
|
9632
|
+
turnLifecycleMetricsFor(observability).progress({ attemptId: input.attemptId });
|
|
9617
9633
|
}
|
|
9618
9634
|
activityContext?.heartbeat({
|
|
9619
9635
|
...heartbeatDetails,
|
|
@@ -9664,7 +9680,7 @@ async function claimTurnAttempt(deps) {
|
|
|
9664
9680
|
return false;
|
|
9665
9681
|
}
|
|
9666
9682
|
recordCanonicalStartupMilestones(result.canonicalStartupMilestones);
|
|
9667
|
-
turnLifecycleMetricsFor(observability).progress(
|
|
9683
|
+
turnLifecycleMetricsFor(observability).progress({ attemptId: input.attemptId });
|
|
9668
9684
|
await publishDurableSessionEvents4(bus, input.workspaceId, input.sessionId, result.events);
|
|
9669
9685
|
if (inputSettlement.turnStatus === "requires_action") {
|
|
9670
9686
|
await deliverChildRequiresActionToParent(
|
|
@@ -14287,6 +14303,8 @@ async function prepareRunCredentials(deps) {
|
|
|
14287
14303
|
import { getWorkspaceConnectionModelRestrictions } from "@opengeni/db";
|
|
14288
14304
|
import {
|
|
14289
14305
|
beginConnectorActionExecution,
|
|
14306
|
+
getExternalLinkTurnAuthorization,
|
|
14307
|
+
getSessionTurnForAttempt as getSessionTurnForAttempt2,
|
|
14290
14308
|
getWorkspaceVideoGenerationPolicy,
|
|
14291
14309
|
listSkillDescriptors as listSkillDescriptors2,
|
|
14292
14310
|
completeConnectorActionExecution,
|
|
@@ -14922,6 +14940,8 @@ function driveQuery(value) {
|
|
|
14922
14940
|
import {
|
|
14923
14941
|
buildConnectionTokenResolver,
|
|
14924
14942
|
buildHostConnectionTokenResolver,
|
|
14943
|
+
getSessionTurnForAttempt,
|
|
14944
|
+
authorizeDirectHostMcpUse,
|
|
14925
14945
|
resolveAcceptedConnectionUse,
|
|
14926
14946
|
sessionTenancyProductActivated
|
|
14927
14947
|
} from "@opengeni/db";
|
|
@@ -14929,7 +14949,10 @@ import { recordTenancyCompatibilityLaneUse } from "@opengeni/observability";
|
|
|
14929
14949
|
var OPENGENI_CONNECTION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
14930
14950
|
function connectionTokenResolverForTurn(input) {
|
|
14931
14951
|
const hostResolver = input.connectionCredentials?.mcpCredentials;
|
|
14932
|
-
const
|
|
14952
|
+
const readHostTurn = input.getHostTurnForAttempt ?? getSessionTurnForAttempt;
|
|
14953
|
+
const hostDb = input.db;
|
|
14954
|
+
const nativeResolver = buildConnectionTokenResolver(input.db, input.settings);
|
|
14955
|
+
const configuredResolver = hostResolver ? buildHostConnectionTokenResolver(hostResolver, {
|
|
14933
14956
|
accountId: input.accountId,
|
|
14934
14957
|
workspaceId: input.workspaceId,
|
|
14935
14958
|
sessionId: input.sessionId,
|
|
@@ -14939,8 +14962,25 @@ function connectionTokenResolverForTurn(input) {
|
|
|
14939
14962
|
executionGeneration: input.turn.executionGeneration,
|
|
14940
14963
|
initiator: input.turn.initiator,
|
|
14941
14964
|
initiatorContext: input.turn.initiatorContext,
|
|
14942
|
-
surface: "model"
|
|
14943
|
-
|
|
14965
|
+
surface: "model",
|
|
14966
|
+
// Only immutable captured direct-turn authority is currently supported.
|
|
14967
|
+
// Direct, scheduled and exact causal/child snapshots are validated;
|
|
14968
|
+
// no authority follows merely from a binding or creator identity.
|
|
14969
|
+
authorizeDurableBinding: (request) => authorizeDirectHostMcpUse(hostDb, request),
|
|
14970
|
+
authorizeExecution: async (request) => {
|
|
14971
|
+
if (request.connectionRef.authoritySource !== "host" && (!request.connectionRef.connectionId || OPENGENI_CONNECTION_ID_PATTERN.test(request.connectionRef.connectionId)))
|
|
14972
|
+
return true;
|
|
14973
|
+
if (!request.attemptId) return false;
|
|
14974
|
+
const current = await readHostTurn(
|
|
14975
|
+
hostDb,
|
|
14976
|
+
request.workspaceId,
|
|
14977
|
+
request.sessionId,
|
|
14978
|
+
request.attemptId
|
|
14979
|
+
);
|
|
14980
|
+
return current !== null && current.id === request.turnId && current.executionGeneration === request.executionGeneration;
|
|
14981
|
+
}
|
|
14982
|
+
}) : nativeResolver;
|
|
14983
|
+
const baseResolver = (request) => input.connectionCredentials?.mcpAuthoritySource === "host" && request.connectionRef.authoritySource !== "host" ? nativeResolver(request) : configuredResolver(request);
|
|
14944
14984
|
return async (request) => {
|
|
14945
14985
|
if (request.connectionRef.authoritySource === "host") {
|
|
14946
14986
|
if (hostResolver) return await baseResolver(request);
|
|
@@ -14956,7 +14996,7 @@ function connectionTokenResolverForTurn(input) {
|
|
|
14956
14996
|
...request.connectionRef.selectedResources ? { selectedResources: request.connectionRef.selectedResources } : {}
|
|
14957
14997
|
};
|
|
14958
14998
|
}
|
|
14959
|
-
if (hostResolver && request.connectionRef.connectionId && !OPENGENI_CONNECTION_ID_PATTERN.test(request.connectionRef.connectionId)) {
|
|
14999
|
+
if (hostResolver && input.connectionCredentials?.mcpAuthoritySource !== "host" && request.connectionRef.connectionId && !OPENGENI_CONNECTION_ID_PATTERN.test(request.connectionRef.connectionId)) {
|
|
14960
15000
|
try {
|
|
14961
15001
|
return await baseResolver(request);
|
|
14962
15002
|
} catch {
|
|
@@ -16063,10 +16103,14 @@ import {
|
|
|
16063
16103
|
resolveCatalogSettings as resolveCatalogSettings2,
|
|
16064
16104
|
resolveWorkspaceModelSelection,
|
|
16065
16105
|
withFrozenPersonalConnectionDelegations,
|
|
16066
|
-
resolveSessionToolPolicy
|
|
16106
|
+
resolveSessionToolPolicy,
|
|
16107
|
+
hasPermission as hasPermission2
|
|
16067
16108
|
} from "@opengeni/core";
|
|
16068
16109
|
import { SandboxChannelAService as SandboxChannelAService3 } from "@opengeni/runtime/sandbox";
|
|
16069
16110
|
import { sandboxRunAs as sandboxRunAs4 } from "@opengeni/runtime";
|
|
16111
|
+
import {
|
|
16112
|
+
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2
|
|
16113
|
+
} from "@opengeni/contracts";
|
|
16070
16114
|
|
|
16071
16115
|
// src/activities/agent-turn/turn-sandbox-access.ts
|
|
16072
16116
|
async function resolveTurnSandboxAccess(sandboxState, sdkOwnedSandboxSession, unavailableMessage) {
|
|
@@ -16189,10 +16233,9 @@ import {
|
|
|
16189
16233
|
|
|
16190
16234
|
// src/activities/agent-turn/skill-read.ts
|
|
16191
16235
|
import {
|
|
16192
|
-
|
|
16236
|
+
listSkillPaths,
|
|
16193
16237
|
PORTABLE_SKILL_MAX_FILES,
|
|
16194
16238
|
readSkillFiles,
|
|
16195
|
-
SKILL_READ_MAX_OUTPUT_BYTES,
|
|
16196
16239
|
SKILL_READ_MAX_PATHS
|
|
16197
16240
|
} from "@opengeni/runtime/skill-library";
|
|
16198
16241
|
var SKILL_READ_TOOL_NAME = "skill_read";
|
|
@@ -16239,7 +16282,7 @@ function createSkillReadAttemptToolDefinition(input) {
|
|
|
16239
16282
|
const loaded = await input.load(args.skill);
|
|
16240
16283
|
const metadata = "files" in loaded ? loaded : null;
|
|
16241
16284
|
const files = metadata ? metadata.files : loaded;
|
|
16242
|
-
const selected = args.listFiles === true ? listSkillPaths(files) : readSkillFiles(files, args.paths);
|
|
16285
|
+
const selected = args.listFiles === true ? listSkillPaths(files, PORTABLE_SKILL_MAX_FILES) : readSkillFiles(files, args.paths);
|
|
16243
16286
|
const output = {
|
|
16244
16287
|
...metadata ? {
|
|
16245
16288
|
skillId: metadata.skillId,
|
|
@@ -16257,22 +16300,6 @@ function createSkillReadAttemptToolDefinition(input) {
|
|
|
16257
16300
|
}
|
|
16258
16301
|
};
|
|
16259
16302
|
}
|
|
16260
|
-
function listSkillPaths(files) {
|
|
16261
|
-
if (files.length > PORTABLE_SKILL_MAX_FILES) {
|
|
16262
|
-
throw new Error(`Skill inventory exceeds ${PORTABLE_SKILL_MAX_FILES} files.`);
|
|
16263
|
-
}
|
|
16264
|
-
const seen = /* @__PURE__ */ new Set();
|
|
16265
|
-
for (const { path } of files) {
|
|
16266
|
-
assertSkillRelativePath(path);
|
|
16267
|
-
if (seen.has(path)) throw new Error(`Duplicate stored Skill path: ${path}`);
|
|
16268
|
-
seen.add(path);
|
|
16269
|
-
}
|
|
16270
|
-
const result = { paths: [...seen].sort() };
|
|
16271
|
-
if (Buffer.byteLength(JSON.stringify(result), "utf8") > SKILL_READ_MAX_OUTPUT_BYTES) {
|
|
16272
|
-
throw new Error("Skill inventory exceeds the read output limit.");
|
|
16273
|
-
}
|
|
16274
|
-
return result;
|
|
16275
|
-
}
|
|
16276
16303
|
|
|
16277
16304
|
// src/activities/agent-turn/skill-search.ts
|
|
16278
16305
|
import { PublicSkillSearchError } from "@opengeni/core";
|
|
@@ -16494,7 +16521,7 @@ function createSkillInstallAttemptToolDefinition(input) {
|
|
|
16494
16521
|
// src/activities/agent-turn/skill-transfer.ts
|
|
16495
16522
|
import { posix } from "path";
|
|
16496
16523
|
import {
|
|
16497
|
-
assertSkillRelativePath
|
|
16524
|
+
assertSkillRelativePath,
|
|
16498
16525
|
buildPortableSkillArtifact as buildPortableSkillArtifact2,
|
|
16499
16526
|
PORTABLE_SKILL_MAX_FILES as PORTABLE_SKILL_MAX_FILES3,
|
|
16500
16527
|
PORTABLE_SKILL_MAX_FILE_BYTES,
|
|
@@ -16518,7 +16545,7 @@ function guardSkillFilesystem(fs, authority) {
|
|
|
16518
16545
|
};
|
|
16519
16546
|
}
|
|
16520
16547
|
async function checkoutSkillDirectory(fs, directory, files) {
|
|
16521
|
-
|
|
16548
|
+
assertSkillRelativePath(directory);
|
|
16522
16549
|
const artifact = buildPortableSkillArtifact2(files);
|
|
16523
16550
|
const parent = posix.dirname(directory);
|
|
16524
16551
|
if (parent !== ".") await fs.fsMkdir({ path: parent, recursive: true });
|
|
@@ -16538,7 +16565,7 @@ async function checkoutSkillDirectory(fs, directory, files) {
|
|
|
16538
16565
|
return { directory, fileCount: artifact.files.length };
|
|
16539
16566
|
}
|
|
16540
16567
|
async function readSkillDirectory(fs, directory) {
|
|
16541
|
-
|
|
16568
|
+
assertSkillRelativePath(directory);
|
|
16542
16569
|
const pending = [directory];
|
|
16543
16570
|
const seen = new Set(pending);
|
|
16544
16571
|
const files = [];
|
|
@@ -16559,7 +16586,7 @@ async function readSkillDirectory(fs, directory) {
|
|
|
16559
16586
|
throw new Error(`Skill directory listing is incomplete: ${current}`);
|
|
16560
16587
|
}
|
|
16561
16588
|
for (const entry of listing.root.children) {
|
|
16562
|
-
|
|
16589
|
+
assertSkillRelativePath(entry.path);
|
|
16563
16590
|
if (posix.dirname(entry.path) !== current || posix.basename(entry.path) !== entry.name) {
|
|
16564
16591
|
throw new Error("Skill directory listing returned a path outside the requested directory.");
|
|
16565
16592
|
}
|
|
@@ -17218,6 +17245,19 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
17218
17245
|
}
|
|
17219
17246
|
};
|
|
17220
17247
|
})() : void 0;
|
|
17248
|
+
const linkedAuthority = await getExternalLinkTurnAuthorization(
|
|
17249
|
+
db,
|
|
17250
|
+
{
|
|
17251
|
+
accountId: input.accountId,
|
|
17252
|
+
workspaceId: input.workspaceId
|
|
17253
|
+
},
|
|
17254
|
+
turn.id
|
|
17255
|
+
);
|
|
17256
|
+
if (linkedAuthority && !linkedAuthority.authorized)
|
|
17257
|
+
throw new Error("Native identity link was revoked");
|
|
17258
|
+
const effectiveFirstPartyPermissions = linkedAuthority ? (session.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2).filter(
|
|
17259
|
+
(permission) => hasPermission2(linkedAuthority.permissions, permission)
|
|
17260
|
+
) : session.firstPartyMcpPermissions;
|
|
17221
17261
|
const selectedFirstPartyMcpTools = allowedFirstPartyMcpToolsForSession(
|
|
17222
17262
|
runSettings,
|
|
17223
17263
|
session.firstPartyMcpTools
|
|
@@ -17229,11 +17269,17 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
17229
17269
|
title: session.title,
|
|
17230
17270
|
titleSource: session.titleSource,
|
|
17231
17271
|
firstPartyMcpTools: selectedFirstPartyMcpTools,
|
|
17232
|
-
firstPartyMcpPermissions:
|
|
17272
|
+
firstPartyMcpPermissions: effectiveFirstPartyPermissions
|
|
17233
17273
|
}),
|
|
17234
17274
|
parallelGenerationAvailable: typeof runtime.generateSessionTitle === "function"
|
|
17235
17275
|
});
|
|
17236
|
-
const googleDrivePublicationAllowed = selectedFirstPartyMcpTools.includes("editable_artifact_export") && selectedFirstPartyMcpTools.includes("editable_artifact_export_status") && (
|
|
17276
|
+
const googleDrivePublicationAllowed = selectedFirstPartyMcpTools.includes("editable_artifact_export") && selectedFirstPartyMcpTools.includes("editable_artifact_export_status") && hasPermission2(
|
|
17277
|
+
[...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2],
|
|
17278
|
+
"artifacts:read"
|
|
17279
|
+
) && hasPermission2(
|
|
17280
|
+
[...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2],
|
|
17281
|
+
"artifacts:publish"
|
|
17282
|
+
);
|
|
17237
17283
|
const googleDriveConnectorBindings = googleDrivePublicationTool && googleDrivePublicationTarget && googleDrivePublicationAllowed ? [
|
|
17238
17284
|
{
|
|
17239
17285
|
modelName: googleDrivePublicationTool.modelName,
|
|
@@ -17448,7 +17494,7 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
17448
17494
|
attemptId: input.attemptId,
|
|
17449
17495
|
executionGeneration: attempt.executionGeneration
|
|
17450
17496
|
},
|
|
17451
|
-
...
|
|
17497
|
+
...effectiveFirstPartyPermissions ? { permissions: effectiveFirstPartyPermissions } : {},
|
|
17452
17498
|
selectedTools: selectedFirstPartyMcpTools,
|
|
17453
17499
|
subjectId: "worker:first-party-mcp",
|
|
17454
17500
|
subjectLabel: "OpenGeni worker",
|
|
@@ -17529,6 +17575,18 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
17529
17575
|
...credentialSubjectId ? { credentialSubjectId } : {},
|
|
17530
17576
|
...codexAppsAuth ? { codexAppsAuth } : {},
|
|
17531
17577
|
resolveCredential,
|
|
17578
|
+
...linkedAuthority ? {
|
|
17579
|
+
authorizeAttemptExecution: async () => {
|
|
17580
|
+
const current = await getSessionTurnForAttempt2(
|
|
17581
|
+
db,
|
|
17582
|
+
input.workspaceId,
|
|
17583
|
+
input.sessionId,
|
|
17584
|
+
input.attemptId
|
|
17585
|
+
);
|
|
17586
|
+
if (!current || current.id !== turn.id || current.executionGeneration !== attempt.executionGeneration)
|
|
17587
|
+
throw new Error("The linked agent attempt is no longer authorized");
|
|
17588
|
+
}
|
|
17589
|
+
} : {},
|
|
17532
17590
|
onAuthNeeded: publishToolAuthNeeded,
|
|
17533
17591
|
materializeConnectorAttachments,
|
|
17534
17592
|
refreshOwnedCommand: async (commandId) => {
|
|
@@ -17555,7 +17613,7 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
17555
17613
|
},
|
|
17556
17614
|
// Manager-style sessions carry a creation-validated permission set
|
|
17557
17615
|
// for their first-party MCP token; null keeps the fixed default.
|
|
17558
|
-
...
|
|
17616
|
+
...effectiveFirstPartyPermissions ? { firstPartyPermissions: effectiveFirstPartyPermissions } : {},
|
|
17559
17617
|
firstPartyTools: titleToolPlan.remoteFirstPartyMcpTools,
|
|
17560
17618
|
nestedAgentDepth: session.nestedAgentDepth,
|
|
17561
17619
|
effectiveMaxNestedAgentDepth: session.effectiveMaxNestedAgentDepth,
|
|
@@ -17823,7 +17881,9 @@ import {
|
|
|
17823
17881
|
getXaiSessionAccountPin as getXaiSessionAccountPin2,
|
|
17824
17882
|
setXaiSessionAccountPin as setXaiSessionAccountPin2,
|
|
17825
17883
|
getWorkspaceVideoGenerationPolicy as getWorkspaceVideoGenerationPolicy2,
|
|
17826
|
-
loadWorkspaceVercelAiGatewayCredentialLease
|
|
17884
|
+
loadWorkspaceVercelAiGatewayCredentialLease,
|
|
17885
|
+
getExternalLinkTurnAuthorization as getExternalLinkTurnAuthorization2,
|
|
17886
|
+
getSessionTurnForAttempt as getSessionTurnForAttempt3
|
|
17827
17887
|
} from "@opengeni/db";
|
|
17828
17888
|
import {
|
|
17829
17889
|
formatSkillCatalog
|
|
@@ -19372,11 +19432,33 @@ async function buildTurnAgent(deps) {
|
|
|
19372
19432
|
outcome: "completed",
|
|
19373
19433
|
durationSeconds: (performance.now() - postToolPreparationStartedAt) / 1e3
|
|
19374
19434
|
});
|
|
19435
|
+
const linkedToolAuthority = await getExternalLinkTurnAuthorization2(
|
|
19436
|
+
db,
|
|
19437
|
+
{
|
|
19438
|
+
accountId: input.accountId,
|
|
19439
|
+
workspaceId: input.workspaceId
|
|
19440
|
+
},
|
|
19441
|
+
turn.id
|
|
19442
|
+
);
|
|
19443
|
+
if (linkedToolAuthority && !linkedToolAuthority.authorized)
|
|
19444
|
+
throw new Error("Native identity link was revoked");
|
|
19375
19445
|
const agent = (() => {
|
|
19376
19446
|
const agentConstructionStartedAt = performance.now();
|
|
19377
19447
|
let agentConstructionOutcome = "completed";
|
|
19378
19448
|
try {
|
|
19379
19449
|
return runtime.buildAgent(eventing.modelRunSettings, runtimeResources, {
|
|
19450
|
+
...linkedToolAuthority ? {
|
|
19451
|
+
authorizeAttemptExecution: async () => {
|
|
19452
|
+
const current = await getSessionTurnForAttempt3(
|
|
19453
|
+
db,
|
|
19454
|
+
input.workspaceId,
|
|
19455
|
+
input.sessionId,
|
|
19456
|
+
input.attemptId
|
|
19457
|
+
);
|
|
19458
|
+
if (!current || current.id !== turn.id || current.executionGeneration !== turn.executionGeneration)
|
|
19459
|
+
throw new Error("The linked agent attempt is no longer authorized");
|
|
19460
|
+
}
|
|
19461
|
+
} : {},
|
|
19380
19462
|
...preparedTools.inputWaitYield ? { inputWaitYield: preparedTools.inputWaitYield } : {},
|
|
19381
19463
|
reasoningEffort: turn.reasoningEffort,
|
|
19382
19464
|
latencyMode: turnExecutionPolicy.latencyMode,
|
|
@@ -19463,7 +19545,6 @@ async function buildTurnAgent(deps) {
|
|
|
19463
19545
|
),
|
|
19464
19546
|
onRetainableSessionImageOutput: media.retainSessionImageAtToolBoundary,
|
|
19465
19547
|
skillCatalog: deps.skillCatalog,
|
|
19466
|
-
serverSkillReading: true,
|
|
19467
19548
|
...!structuredWorkspacePolicyActive && workspaceAgentInstructions ? { instructionsTemplate: workspaceAgentInstructions } : {},
|
|
19468
19549
|
...workspaceGovernance ? { workspaceGovernance } : {},
|
|
19469
19550
|
...workspaceMemory ? { workspaceMemory } : {},
|
|
@@ -21970,4 +22051,4 @@ export {
|
|
|
21970
22051
|
createTurnActivities,
|
|
21971
22052
|
createTurnActivitiesFromServices
|
|
21972
22053
|
};
|
|
21973
|
-
//# sourceMappingURL=activities-turn-
|
|
22054
|
+
//# sourceMappingURL=activities-turn-I2ZKGZE6.js.map
|