@opengeni/worker-bundle 4.4.1 → 4.5.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/owned-sandbox-setup.d.ts +38 -0
- package/dist/activities/agent-turn/stream-attempt.d.ts +3 -0
- package/dist/{activities-turn-G33RWTX2.js → activities-turn-B73PNSEA.js} +504 -432
- package/dist/activities-turn-B73PNSEA.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +27 -27
- package/src/activities/agent-turn/owned-sandbox-setup.ts +207 -0
- package/src/activities/agent-turn/run.ts +237 -193
- package/src/activities/agent-turn/stream-attempt.ts +11 -95
- package/dist/activities-turn-G33RWTX2.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1477,7 +1477,7 @@ async function createDefaultWorkerActivities(role, dependencies = {}) {
|
|
|
1477
1477
|
if (dependencies.objectStorage == null) {
|
|
1478
1478
|
prepareObjectStorageProvider(dependencies.settings ?? getSettings());
|
|
1479
1479
|
}
|
|
1480
|
-
return role === "control" ? (await import("./activities-control-BXAGB3AU.js")).createControlActivities(dependencies) : (await import("./activities-turn-
|
|
1480
|
+
return role === "control" ? (await import("./activities-control-BXAGB3AU.js")).createControlActivities(dependencies) : (await import("./activities-turn-B73PNSEA.js")).createTurnActivities(dependencies);
|
|
1481
1481
|
}
|
|
1482
1482
|
function resolveOpenGeniWorkflowDefinition(moduleUrl = import.meta.url) {
|
|
1483
1483
|
const modulePath = fileURLToPath(moduleUrl).replaceAll("\\", "/");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/worker-bundle",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Opengeni worker entry and reusable embedded lifecycle, shipped with a release-coherent pre-bundled Temporal workflow artifact.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -56,32 +56,32 @@
|
|
|
56
56
|
"@1password/sdk": "0.5.0",
|
|
57
57
|
"@keeper-security/secrets-manager-core": "17.6.0",
|
|
58
58
|
"@llamaindex/liteparse": "2.14.2",
|
|
59
|
-
"@opengeni/agent-proto": "4.
|
|
60
|
-
"@opengeni/capabilities": "4.
|
|
61
|
-
"@opengeni/codemode": "4.
|
|
62
|
-
"@opengeni/codex": "4.
|
|
63
|
-
"@opengeni/config": "4.
|
|
64
|
-
"@opengeni/contracts": "4.
|
|
65
|
-
"@opengeni/core": "4.
|
|
66
|
-
"@opengeni/db": "4.
|
|
67
|
-
"@opengeni/decisions": "4.
|
|
68
|
-
"@opengeni/documents": "4.
|
|
69
|
-
"@opengeni/events": "4.
|
|
70
|
-
"@opengeni/github": "4.
|
|
71
|
-
"@opengeni/interaction": "4.
|
|
72
|
-
"@opengeni/jev": "4.
|
|
73
|
-
"@opengeni/network": "4.
|
|
74
|
-
"@opengeni/observability": "4.
|
|
75
|
-
"@opengeni/runtime": "4.
|
|
76
|
-
"@opengeni/sdk": "4.
|
|
77
|
-
"@opengeni/storage": "4.
|
|
78
|
-
"@opengeni/subscriptions": "4.
|
|
79
|
-
"@opengeni/tool-gateway": "4.
|
|
80
|
-
"@opengeni/vaults": "4.
|
|
81
|
-
"@opengeni/vaults-keeper": "4.
|
|
82
|
-
"@opengeni/vaults-onepassword": "4.
|
|
83
|
-
"@opengeni/vaults-protonpass": "4.
|
|
84
|
-
"@opengeni/xai-subscription": "4.
|
|
59
|
+
"@opengeni/agent-proto": "4.5.0",
|
|
60
|
+
"@opengeni/capabilities": "4.5.0",
|
|
61
|
+
"@opengeni/codemode": "4.5.0",
|
|
62
|
+
"@opengeni/codex": "4.5.0",
|
|
63
|
+
"@opengeni/config": "4.5.0",
|
|
64
|
+
"@opengeni/contracts": "4.5.0",
|
|
65
|
+
"@opengeni/core": "4.5.0",
|
|
66
|
+
"@opengeni/db": "4.5.0",
|
|
67
|
+
"@opengeni/decisions": "4.5.0",
|
|
68
|
+
"@opengeni/documents": "4.5.0",
|
|
69
|
+
"@opengeni/events": "4.5.0",
|
|
70
|
+
"@opengeni/github": "4.5.0",
|
|
71
|
+
"@opengeni/interaction": "4.5.0",
|
|
72
|
+
"@opengeni/jev": "4.5.0",
|
|
73
|
+
"@opengeni/network": "4.5.0",
|
|
74
|
+
"@opengeni/observability": "4.5.0",
|
|
75
|
+
"@opengeni/runtime": "4.5.0",
|
|
76
|
+
"@opengeni/sdk": "4.5.0",
|
|
77
|
+
"@opengeni/storage": "4.5.0",
|
|
78
|
+
"@opengeni/subscriptions": "4.5.0",
|
|
79
|
+
"@opengeni/tool-gateway": "4.5.0",
|
|
80
|
+
"@opengeni/vaults": "4.5.0",
|
|
81
|
+
"@opengeni/vaults-keeper": "4.5.0",
|
|
82
|
+
"@opengeni/vaults-onepassword": "4.5.0",
|
|
83
|
+
"@opengeni/vaults-protonpass": "4.5.0",
|
|
84
|
+
"@opengeni/xai-subscription": "4.5.0",
|
|
85
85
|
"@temporalio/activity": "^1.17.0",
|
|
86
86
|
"@temporalio/client": "^1.17.0",
|
|
87
87
|
"@temporalio/worker": "^1.17.0",
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runOwnedSandboxSetup,
|
|
3
|
+
withRunCredentialsSession,
|
|
4
|
+
type GitCredentialTokenWriterSession,
|
|
5
|
+
type PreparedAgentInput,
|
|
6
|
+
type RunCredentialCommandSession,
|
|
7
|
+
} from "@opengeni/runtime";
|
|
8
|
+
import {
|
|
9
|
+
recordSandboxSharedPreparation,
|
|
10
|
+
recordTurnStartupPhase,
|
|
11
|
+
} from "../../observability-metrics";
|
|
12
|
+
import { createSharedRigSetupCoordinator } from "./sandbox-shared-preparation";
|
|
13
|
+
import type { TurnStreamAttemptDeps } from "./stream-attempt";
|
|
14
|
+
import { ownedTurnSandboxForAgent } from "./turn-sandbox-access";
|
|
15
|
+
|
|
16
|
+
export type EagerOwnedSandboxSetupDeps = Pick<
|
|
17
|
+
TurnStreamAttemptDeps,
|
|
18
|
+
| "input"
|
|
19
|
+
| "db"
|
|
20
|
+
| "observability"
|
|
21
|
+
| "runtimeCancellationSignal"
|
|
22
|
+
| "sandboxState"
|
|
23
|
+
| "eventing"
|
|
24
|
+
| "leases"
|
|
25
|
+
| "runWorkspaceMutationForSandbox"
|
|
26
|
+
| "attachGitCredentialRenewal"
|
|
27
|
+
| "attachRunCredentialRenewal"
|
|
28
|
+
| "activeSandboxBackend"
|
|
29
|
+
| "groupBoxBackend"
|
|
30
|
+
| "turnExecutionPolicy"
|
|
31
|
+
| "agent"
|
|
32
|
+
| "runSettings"
|
|
33
|
+
| "initialRunCredentialMaterial"
|
|
34
|
+
| "initialGitCredentials"
|
|
35
|
+
| "sandboxEnvironment"
|
|
36
|
+
| "fileResourceDownloads"
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
export type EagerOwnedSandboxSetupOptions = {
|
|
40
|
+
/** The worker delivers this turn's file resources itself. */
|
|
41
|
+
fileDownloadsMaterialized: boolean;
|
|
42
|
+
/** Receives the runtime's file-failure note when the runtime delivers files. */
|
|
43
|
+
preparedInput?: PreparedAgentInput;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Whether this turn's platform setup runs eagerly against an owned box the
|
|
48
|
+
* worker already holds. Lazy boxes run the same setup in their first-operation
|
|
49
|
+
* provisioner, and connected machines receive no platform setup.
|
|
50
|
+
*/
|
|
51
|
+
export function hasEagerOwnedSandboxSetup(
|
|
52
|
+
sandboxState: EagerOwnedSandboxSetupDeps["sandboxState"],
|
|
53
|
+
): boolean {
|
|
54
|
+
return Boolean(
|
|
55
|
+
sandboxState.resolvedSandbox &&
|
|
56
|
+
!sandboxState.lazyOwnedSandbox &&
|
|
57
|
+
ownedTurnSandboxForAgent(sandboxState),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Run the turn's platform setup (rig setup, credential hooks, repository
|
|
63
|
+
* clones) against the eager owned box. The setup settles its workspace
|
|
64
|
+
* admission before returning, so no admission stays open into the model stream.
|
|
65
|
+
*/
|
|
66
|
+
export async function runEagerOwnedSandboxSetup(
|
|
67
|
+
deps: EagerOwnedSandboxSetupDeps,
|
|
68
|
+
options: EagerOwnedSandboxSetupOptions,
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const { input, sandboxState, eventing, leases, observability } = deps;
|
|
71
|
+
const eagerResolvedSandbox = sandboxState.resolvedSandbox;
|
|
72
|
+
const ownedEstablished = ownedTurnSandboxForAgent(sandboxState);
|
|
73
|
+
if (!eagerResolvedSandbox || sandboxState.lazyOwnedSandbox || !ownedEstablished) return;
|
|
74
|
+
const ownedSandboxSetupStartedAt = performance.now();
|
|
75
|
+
let ownedSandboxSetupOutcome: "completed" | "failed" = "completed";
|
|
76
|
+
try {
|
|
77
|
+
const eagerSetupSession = sandboxState.setupBoxSession ?? ownedEstablished.session;
|
|
78
|
+
// The worker owns platform setup for owned boxes, so the runtime skips its
|
|
79
|
+
// credential session callback. Materialize host-managed run credentials
|
|
80
|
+
// before any setup command (including provider login hooks), then decorate
|
|
81
|
+
// setup commands so they source the active generation.
|
|
82
|
+
await deps.attachRunCredentialRenewal(
|
|
83
|
+
eagerSetupSession as RunCredentialCommandSession,
|
|
84
|
+
deps.initialRunCredentialMaterial,
|
|
85
|
+
eagerResolvedSandbox,
|
|
86
|
+
);
|
|
87
|
+
const eagerCredentialSetupSession = deps.initialRunCredentialMaterial
|
|
88
|
+
? withRunCredentialsSession(eagerSetupSession as object, input.sessionId)
|
|
89
|
+
: eagerSetupSession;
|
|
90
|
+
await deps.runWorkspaceMutationForSandbox(
|
|
91
|
+
eagerResolvedSandbox,
|
|
92
|
+
"eagerOwnedSandboxSetup",
|
|
93
|
+
async () =>
|
|
94
|
+
await runOwnedSandboxSetup(
|
|
95
|
+
deps.agent,
|
|
96
|
+
ownedEstablished.session as never,
|
|
97
|
+
eagerCredentialSetupSession as never,
|
|
98
|
+
{
|
|
99
|
+
settings: deps.runSettings,
|
|
100
|
+
environment: deps.sandboxEnvironment,
|
|
101
|
+
...(options.preparedInput ? { preparedInput: options.preparedInput } : {}),
|
|
102
|
+
...(options.fileDownloadsMaterialized ? { fileDownloadsMaterialized: true } : {}),
|
|
103
|
+
onRuntimeEvent: async (event) => {
|
|
104
|
+
await leases.renewServing("runtime_event");
|
|
105
|
+
if (leases.servingLost()) {
|
|
106
|
+
throw new Error("Provider credential lease expired during sandbox setup");
|
|
107
|
+
}
|
|
108
|
+
await eventing.publish([{ type: event.type, payload: event.payload }], true);
|
|
109
|
+
},
|
|
110
|
+
...(eventing.toolCancellationFenceRef.current
|
|
111
|
+
? {
|
|
112
|
+
commandRunner: eventing.toolCancellationFenceRef.current.runSandboxCommand.bind(
|
|
113
|
+
eventing.toolCancellationFenceRef.current,
|
|
114
|
+
),
|
|
115
|
+
}
|
|
116
|
+
: {}),
|
|
117
|
+
...(sandboxState.sandboxGroupId && sandboxState.sandboxHolderId
|
|
118
|
+
? {
|
|
119
|
+
coordinateSharedRigSetup: createSharedRigSetupCoordinator({
|
|
120
|
+
db: deps.db,
|
|
121
|
+
accountId: input.accountId,
|
|
122
|
+
workspaceId: input.workspaceId,
|
|
123
|
+
sandboxGroupId: sandboxState.sandboxGroupId,
|
|
124
|
+
attemptId: input.attemptId,
|
|
125
|
+
holderId: sandboxState.sandboxHolderId,
|
|
126
|
+
sandbox: eagerResolvedSandbox,
|
|
127
|
+
...(deps.runtimeCancellationSignal
|
|
128
|
+
? { signal: deps.runtimeCancellationSignal }
|
|
129
|
+
: {}),
|
|
130
|
+
observe: (measurement) =>
|
|
131
|
+
recordSandboxSharedPreparation(observability, measurement),
|
|
132
|
+
}),
|
|
133
|
+
}
|
|
134
|
+
: {}),
|
|
135
|
+
},
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
await deps.attachGitCredentialRenewal(
|
|
139
|
+
eagerSetupSession as GitCredentialTokenWriterSession,
|
|
140
|
+
deps.initialGitCredentials,
|
|
141
|
+
);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
ownedSandboxSetupOutcome = "failed";
|
|
144
|
+
throw error;
|
|
145
|
+
} finally {
|
|
146
|
+
recordTurnStartupPhase(observability, {
|
|
147
|
+
phase: "owned_sandbox_setup",
|
|
148
|
+
provider: deps.turnExecutionPolicy.providerId,
|
|
149
|
+
backend: deps.activeSandboxBackend ?? deps.groupBoxBackend,
|
|
150
|
+
outcome: ownedSandboxSetupOutcome,
|
|
151
|
+
durationSeconds: (performance.now() - ownedSandboxSetupStartedAt) / 1_000,
|
|
152
|
+
count: deps.fileResourceDownloads.length,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The eager platform setup for each model stream of one turn attempt.
|
|
159
|
+
*
|
|
160
|
+
* The first stream's setup may already be running: it needs nothing from the
|
|
161
|
+
* model input, so the worker starts it with file delivery and input
|
|
162
|
+
* preparation instead of after them. Each later stream of the attempt runs the
|
|
163
|
+
* idempotent setup again, as before.
|
|
164
|
+
*/
|
|
165
|
+
export type EagerOwnedSandboxSetup = {
|
|
166
|
+
/** Run, or join the already started, setup for the next model stream. */
|
|
167
|
+
beforeModelStream(options: EagerOwnedSandboxSetupOptions): Promise<void>;
|
|
168
|
+
/** Resolves once a started setup has finished, whatever its outcome. */
|
|
169
|
+
settled(): Promise<void>;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export function createEagerOwnedSandboxSetup(
|
|
173
|
+
deps: EagerOwnedSandboxSetupDeps,
|
|
174
|
+
start?: { fileDownloadsMaterialized: boolean },
|
|
175
|
+
runSetup: typeof runEagerOwnedSandboxSetup = runEagerOwnedSandboxSetup,
|
|
176
|
+
): EagerOwnedSandboxSetup {
|
|
177
|
+
const startedFor = start ? sandboxIdentity(deps.sandboxState) : null;
|
|
178
|
+
let started: Promise<void> | null = start
|
|
179
|
+
? runSetup(deps, {
|
|
180
|
+
fileDownloadsMaterialized: start.fileDownloadsMaterialized,
|
|
181
|
+
})
|
|
182
|
+
: null;
|
|
183
|
+
// Observing the outcome here keeps an early failure from being unhandled;
|
|
184
|
+
// the first model stream still awaits the original promise and rethrows it.
|
|
185
|
+
const settled = started ? started.then(noop, noop) : Promise.resolve();
|
|
186
|
+
return {
|
|
187
|
+
beforeModelStream: async (options) => {
|
|
188
|
+
if (started) {
|
|
189
|
+
const prestarted = started;
|
|
190
|
+
started = null;
|
|
191
|
+
await prestarted;
|
|
192
|
+
// A box rebound while the setup ran (rotation, recovery) gets its
|
|
193
|
+
// own setup; the prestarted one only covered the earlier box.
|
|
194
|
+
if (sandboxIdentity(deps.sandboxState) === startedFor) return;
|
|
195
|
+
}
|
|
196
|
+
await runSetup(deps, options);
|
|
197
|
+
},
|
|
198
|
+
settled: () => settled,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function sandboxIdentity(sandboxState: EagerOwnedSandboxSetupDeps["sandboxState"]): string | null {
|
|
203
|
+
const resolved = sandboxState.resolvedSandbox;
|
|
204
|
+
return resolved ? `${resolved.leaseEpoch}:${resolved.established.instanceId}` : null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function noop(): void {}
|