@opengeni/worker-bundle 1.0.0-canary.0 → 1.0.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-run-admission.d.ts +3 -1
- package/dist/activities/agent-turn/admission.d.ts +24 -3
- package/dist/activities/agent-turn/agent-build.d.ts +4 -0
- package/dist/activities/agent-turn/claude-usage-observer.d.ts +58 -0
- package/dist/activities/agent-turn/code-search.d.ts +60 -0
- package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
- package/dist/activities/agent-turn/codex-plan-entitlement.d.ts +105 -0
- package/dist/activities/agent-turn/codex.d.ts +3 -2
- package/dist/activities/agent-turn/compaction-prep.d.ts +21 -5
- package/dist/activities/agent-turn/credential-leases.d.ts +19 -33
- package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
- package/dist/activities/agent-turn/errors.d.ts +82 -11
- package/dist/activities/agent-turn/failure-settlement.d.ts +6 -3
- package/dist/activities/agent-turn/final-reply.d.ts +18 -0
- package/dist/activities/agent-turn/finalization-monitor.d.ts +17 -0
- package/dist/activities/agent-turn/finalization.d.ts +4 -2
- package/dist/activities/agent-turn/github-repository-bindings.d.ts +2 -0
- package/dist/activities/agent-turn/governance-model.d.ts +9 -2
- package/dist/activities/agent-turn/history-sink.d.ts +2 -0
- package/dist/activities/agent-turn/history.d.ts +2 -0
- package/dist/activities/agent-turn/input-wait-reply.d.ts +41 -0
- package/dist/activities/agent-turn/media-artifacts.d.ts +5 -3
- package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
- package/dist/activities/agent-turn/model-usage.d.ts +6 -0
- package/dist/activities/agent-turn/model-wire-dispatch.d.ts +15 -0
- package/dist/activities/agent-turn/optional-repositories.d.ts +59 -0
- package/dist/activities/agent-turn/provider-dispatch-barrier.d.ts +12 -1
- package/dist/activities/agent-turn/quiescence.d.ts +7 -7
- package/dist/activities/agent-turn/recovery-warning.d.ts +9 -0
- package/dist/activities/agent-turn/refresh-credentials.d.ts +6 -0
- package/dist/activities/agent-turn/run-credentials.d.ts +8 -3
- package/dist/activities/agent-turn/sandbox-establish.d.ts +2 -1
- package/dist/activities/agent-turn/sandbox-provision.d.ts +3 -1
- package/dist/activities/agent-turn/sandbox-route.d.ts +3 -20
- package/dist/activities/agent-turn/sandbox-runtime.d.ts +2 -2
- package/dist/activities/agent-turn/session-title.d.ts +34 -2
- package/dist/activities/agent-turn/skill-checkout.d.ts +25 -6
- package/dist/activities/agent-turn/skill-read.d.ts +70 -2
- package/dist/activities/agent-turn/skill-remove.d.ts +14 -0
- package/dist/activities/agent-turn/skill-search.d.ts +3 -1
- package/dist/activities/agent-turn/skill-tools.d.ts +15 -2
- package/dist/activities/agent-turn/skill-transfer.d.ts +18 -6
- package/dist/activities/agent-turn/stream-attempt.d.ts +7 -3
- package/dist/activities/agent-turn/subscription-lease.d.ts +38 -0
- package/dist/activities/agent-turn/tool-environment.d.ts +56 -6
- package/dist/activities/agent-turn/tool-policy.d.ts +43 -0
- package/dist/activities/agent-turn/turn-context.d.ts +29 -0
- package/dist/activities/agent-turn/turn-sandbox-access.d.ts +3 -0
- package/dist/activities/agent-turn/xai-capacity.d.ts +2 -1
- package/dist/activities/automations.d.ts +3 -1
- package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
- package/dist/activities/codemode-dispatcher.d.ts +9 -2
- package/dist/activities/codex-capacity.d.ts +18 -2
- package/dist/activities/codex-rotation.d.ts +7 -1
- package/dist/activities/context-compaction.d.ts +16 -2
- package/dist/activities/gmail-files.d.ts +32 -0
- package/dist/activities/goals.d.ts +8 -0
- package/dist/activities/knowledge-indexing.d.ts +19 -0
- package/dist/activities/mcp-account-routes.d.ts +3 -0
- package/dist/activities/mcp-credentials.d.ts +12 -13
- package/dist/activities/mcp-operation-authority.d.ts +0 -5
- package/dist/activities/model-call-fact-reconciler.d.ts +34 -0
- package/dist/activities/open-suffix-resume.d.ts +13 -0
- package/dist/activities/parent-wake.d.ts +6 -12
- package/dist/activities/retained-screenshots.d.ts +7 -2
- package/dist/activities/rig-verification.d.ts +2 -3
- package/dist/activities/run-credential-renewal.d.ts +1 -0
- package/dist/activities/run-credentials.d.ts +15 -3
- package/dist/activities/sandbox-images.d.ts +1 -1
- package/dist/activities/sandbox-lease.d.ts +47 -9
- package/dist/activities/scheduled-tasks.d.ts +4 -35
- package/dist/activities/session-state.d.ts +70 -3
- package/dist/activities/types.d.ts +55 -6
- package/dist/activities/workspace-capture.d.ts +2 -0
- package/dist/activities/workspace-credential-provider.d.ts +46 -0
- package/dist/{activities-control-HMFGSKC5.js → activities-control-BNPTRTOE.js} +1896 -418
- package/dist/activities-control-BNPTRTOE.js.map +1 -0
- package/dist/activities-control.d.ts +182 -4
- package/dist/{activities-turn-AP67JADS.js → activities-turn-5LGZOSVU.js} +4476 -1327
- package/dist/activities-turn-5LGZOSVU.js.map +1 -0
- package/dist/activities.d.ts +182 -4
- package/dist/artifact-materializer-entry.js +5 -2
- package/dist/artifact-materializer-entry.js.map +1 -1
- package/dist/artifact-outbox-entry.js +5 -2
- package/dist/artifact-outbox-entry.js.map +1 -1
- package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
- package/dist/{chunk-A4XQWVZK.js → chunk-3ZTRWDMN.js} +307 -4
- package/dist/chunk-3ZTRWDMN.js.map +1 -0
- package/dist/{chunk-RAMNYSAW.js → chunk-4ER3YXOT.js} +22 -4
- package/dist/chunk-4ER3YXOT.js.map +1 -0
- package/dist/{chunk-CYITU5UH.js → chunk-LJX7Z2KP.js} +1445 -343
- package/dist/chunk-LJX7Z2KP.js.map +1 -0
- package/dist/editable-artifact-materializer-service.d.ts +2 -2
- package/dist/editable-artifact-outbox-service.d.ts +2 -2
- package/dist/host-export-pump.d.ts +3 -1
- package/dist/host-export.d.ts +1 -1
- package/dist/host-export.js +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +95 -3
- package/dist/index.js +137 -43
- package/dist/index.js.map +1 -1
- package/dist/observability-metrics.d.ts +118 -8
- package/dist/retained-process-diagnostics.d.ts +4 -0
- package/dist/retained-process-retry.d.ts +7 -0
- package/dist/sandbox-resume.d.ts +55 -13
- package/dist/sandbox-routing.d.ts +5 -3
- package/dist/sandbox-snapshot-diagnostics.d.ts +20 -0
- package/dist/session-event-fanout.d.ts +6 -0
- package/dist/warm-capture-holder.d.ts +3 -0
- package/dist/worker-service-lifecycle.d.ts +12 -0
- package/dist/workflow-bundle.js +273 -41
- package/dist/workflows/activities.d.ts +1 -1
- package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
- package/dist/workflows/scheduled-tasks.d.ts +4 -0
- package/dist/workflows/session.d.ts +36 -0
- package/dist/workflows.d.ts +1 -0
- package/package.json +21 -19
- package/src/activities/agent-run-admission.ts +17 -1
- package/src/activities/agent-turn/admission.ts +66 -3
- package/src/activities/agent-turn/agent-build.ts +84 -10
- package/src/activities/agent-turn/claim.ts +186 -43
- package/src/activities/agent-turn/claude-usage-observer.ts +221 -0
- package/src/activities/agent-turn/code-search.ts +275 -0
- package/src/activities/agent-turn/codex-capacity.ts +172 -8
- package/src/activities/agent-turn/codex-plan-entitlement.ts +254 -0
- package/src/activities/agent-turn/codex.ts +13 -5
- package/src/activities/agent-turn/compaction-prep.ts +170 -102
- package/src/activities/agent-turn/credential-leases.ts +122 -216
- package/src/activities/agent-turn/credential-restriction.ts +14 -0
- package/src/activities/agent-turn/errors.ts +647 -48
- package/src/activities/agent-turn/failure-settlement.ts +682 -130
- package/src/activities/agent-turn/final-reply.ts +46 -0
- package/src/activities/agent-turn/finalization-monitor.ts +120 -0
- package/src/activities/agent-turn/finalization.ts +146 -43
- package/src/activities/agent-turn/github-repository-bindings.ts +3 -1
- package/src/activities/agent-turn/governance-model.ts +69 -28
- package/src/activities/agent-turn/history-sink.ts +16 -2
- package/src/activities/agent-turn/history.ts +38 -11
- package/src/activities/agent-turn/input-wait-reply.ts +103 -0
- package/src/activities/agent-turn/knowledge-source-tools.ts +2 -0
- package/src/activities/agent-turn/media-artifacts.ts +2 -1
- package/src/activities/agent-turn/model-call-admission.ts +94 -0
- package/src/activities/agent-turn/model-usage.ts +64 -3
- package/src/activities/agent-turn/model-wire-dispatch.ts +27 -0
- package/src/activities/agent-turn/optional-repositories.ts +224 -0
- package/src/activities/agent-turn/provider-dispatch-barrier.ts +22 -0
- package/src/activities/agent-turn/quiescence.ts +10 -7
- package/src/activities/agent-turn/recovery-warning.ts +16 -0
- package/src/activities/agent-turn/refresh-credentials.ts +44 -0
- package/src/activities/agent-turn/run-credentials.ts +116 -55
- package/src/activities/agent-turn/run.ts +320 -93
- package/src/activities/agent-turn/sandbox-establish.ts +84 -8
- package/src/activities/agent-turn/sandbox-provision.ts +3 -1
- package/src/activities/agent-turn/sandbox-route.ts +4 -21
- package/src/activities/agent-turn/sandbox-runtime.ts +343 -18
- package/src/activities/agent-turn/session-title.ts +81 -5
- package/src/activities/agent-turn/skill-checkout.ts +111 -24
- package/src/activities/agent-turn/skill-install.ts +1 -1
- package/src/activities/agent-turn/skill-read.ts +374 -28
- package/src/activities/agent-turn/skill-remove.ts +46 -0
- package/src/activities/agent-turn/skill-save.ts +1 -1
- package/src/activities/agent-turn/skill-search.ts +10 -1
- package/src/activities/agent-turn/skill-selection.ts +4 -0
- package/src/activities/agent-turn/skill-tools.ts +112 -18
- package/src/activities/agent-turn/skill-transfer.ts +68 -23
- package/src/activities/agent-turn/stream-attempt.ts +313 -77
- package/src/activities/agent-turn/subscription-lease.ts +115 -0
- package/src/activities/agent-turn/tool-environment.ts +316 -167
- package/src/activities/agent-turn/tool-policy.ts +80 -1
- package/src/activities/agent-turn/turn-context.ts +35 -0
- package/src/activities/agent-turn/turn-sandbox-access.ts +7 -1
- package/src/activities/agent-turn/xai-capacity.ts +94 -51
- package/src/activities/automations.ts +76 -4
- package/src/activities/browser-deadline-checkpoint.ts +279 -0
- package/src/activities/capabilities.ts +108 -11
- package/src/activities/codemode-dispatcher.ts +36 -8
- package/src/activities/codex-capacity.ts +60 -25
- package/src/activities/codex-rotation.ts +39 -17
- package/src/activities/context-compaction.ts +75 -18
- package/src/activities/gmail-files.ts +88 -0
- package/src/activities/goals.ts +116 -121
- package/src/activities/google-drive-publication.ts +1 -3
- package/src/activities/image-generation-operation.ts +1 -1
- package/src/activities/knowledge-indexing.ts +269 -15
- package/src/activities/knowledge-source-sync.ts +10 -0
- package/src/activities/mcp-account-routes.ts +17 -0
- package/src/activities/mcp-credentials.ts +83 -194
- package/src/activities/mcp-operation-authority.ts +16 -41
- package/src/activities/model-call-fact-reconciler.ts +112 -0
- package/src/activities/open-suffix-resume.ts +15 -2
- package/src/activities/parent-wake.ts +46 -21
- package/src/activities/retained-screenshots.ts +82 -11
- package/src/activities/rig-verification.ts +38 -37
- package/src/activities/run-credential-renewal.ts +13 -1
- package/src/activities/run-credentials.ts +59 -17
- package/src/activities/run-input.ts +25 -16
- package/src/activities/sandbox-images.ts +0 -1
- package/src/activities/sandbox-lease.ts +798 -82
- package/src/activities/scheduled-tasks.ts +550 -178
- package/src/activities/session-state.ts +245 -6
- package/src/activities/site-auth-maintenance.ts +3 -0
- package/src/activities/types.ts +72 -5
- package/src/activities/workflow-wake.ts +2 -17
- package/src/activities/workspace-capture.ts +13 -2
- package/src/activities/workspace-credential-provider.ts +283 -0
- package/src/activities-control.ts +4 -0
- package/src/activities-turn.ts +5 -0
- package/src/activities.ts +13 -0
- package/src/activity-services.ts +16 -4
- package/src/browser-deadline-checkpoint-contract.ts +5 -0
- package/src/editable-artifact-hint-broker.ts +3 -0
- package/src/editable-artifact-materializer-service.ts +7 -3
- package/src/editable-artifact-outbox-service.ts +4 -4
- package/src/github-rest-mcp.ts +1 -2
- package/src/host-export-pump.ts +26 -4
- package/src/host-export.ts +3 -0
- package/src/http.ts +4 -2
- package/src/index.ts +99 -37
- package/src/observability-metrics.ts +510 -5
- package/src/personal-github-git-credentials.ts +2 -1
- package/src/pr-review-credentials.ts +1 -3
- package/src/retained-process-diagnostics.ts +50 -0
- package/src/retained-process-retry.ts +36 -0
- package/src/sandbox-resume.ts +388 -101
- package/src/sandbox-routing.ts +150 -25
- package/src/sandbox-snapshot-diagnostics.ts +112 -0
- package/src/session-event-fanout.ts +23 -0
- package/src/warm-capture-holder.ts +15 -0
- package/src/worker-service-lifecycle.ts +53 -0
- package/src/workflows/activities.ts +16 -1
- package/src/workflows/browser-deadline-checkpoint.ts +50 -0
- package/src/workflows/file-upload-reaper.ts +2 -0
- package/src/workflows/scheduled-tasks.ts +26 -13
- package/src/workflows/session.ts +242 -22
- package/src/workflows.ts +4 -0
- package/dist/activities/agent-turn/knowledge-sources.d.ts +0 -20
- package/dist/activities/packs.d.ts +0 -55
- package/dist/activities-control-HMFGSKC5.js.map +0 -1
- package/dist/activities-turn-AP67JADS.js.map +0 -1
- package/dist/chunk-A4XQWVZK.js.map +0 -1
- package/dist/chunk-CYITU5UH.js.map +0 -1
- package/dist/chunk-RAMNYSAW.js.map +0 -1
- package/src/activities/agent-turn/knowledge-sources.ts +0 -86
- package/src/activities/packs.ts +0 -166
|
@@ -4,18 +4,22 @@ import {
|
|
|
4
4
|
WORKSPACE_OPENROUTER_MODEL_ID_PREFIX,
|
|
5
5
|
} from "@opengeni/config";
|
|
6
6
|
import {
|
|
7
|
+
applySessionAgentConfigWriteThrough,
|
|
7
8
|
assertWorkspaceModelPolicyAllows,
|
|
8
9
|
canonicalConfiguredModel,
|
|
10
|
+
resolveSessionAgentConfigForCreate,
|
|
9
11
|
createAndStartSessionWithOutcome,
|
|
10
12
|
recordWorkspaceUsage,
|
|
11
13
|
resolveCatalogSettings,
|
|
12
14
|
resolveWorkspaceCatalogSettings,
|
|
15
|
+
isDeveloperSetupDelegatedPermissionAllowed,
|
|
13
16
|
} from "@opengeni/core";
|
|
14
17
|
import {
|
|
15
18
|
AutomationAuthorityRevokedError,
|
|
16
19
|
assertAutomationRunAuthorityInTransaction,
|
|
17
20
|
claimAutomationRun,
|
|
18
21
|
settleAutomationRun,
|
|
22
|
+
requireWorkspace,
|
|
19
23
|
} from "@opengeni/db";
|
|
20
24
|
import { SessionSkills } from "@opengeni/contracts";
|
|
21
25
|
import { agentRunAdmissionDenial } from "./agent-run-admission";
|
|
@@ -30,6 +34,8 @@ export type AutomationActivityOptions = {
|
|
|
30
34
|
settle?: typeof settleAutomationRun;
|
|
31
35
|
assertAuthority?: typeof assertAutomationRunAuthorityInTransaction;
|
|
32
36
|
createSession?: typeof createAndStartSessionWithOutcome;
|
|
37
|
+
/** Workspace read for agent-configuration defaults (tests inject it). */
|
|
38
|
+
readWorkspace?: typeof requireWorkspace;
|
|
33
39
|
admit?: typeof agentRunAdmissionDenial;
|
|
34
40
|
assertModelPolicy?: typeof assertWorkspaceModelPolicyAllows;
|
|
35
41
|
recordUsage?: typeof recordWorkspaceUsage;
|
|
@@ -43,6 +49,7 @@ export function createAutomationActivities(
|
|
|
43
49
|
const settle = options.settle ?? settleAutomationRun;
|
|
44
50
|
const assertAuthority = options.assertAuthority ?? assertAutomationRunAuthorityInTransaction;
|
|
45
51
|
const createSession = options.createSession ?? createAndStartSessionWithOutcome;
|
|
52
|
+
const readWorkspace = options.readWorkspace ?? requireWorkspace;
|
|
46
53
|
const admit = options.admit ?? agentRunAdmissionDenial;
|
|
47
54
|
const assertModelPolicy = options.assertModelPolicy ?? assertWorkspaceModelPolicyAllows;
|
|
48
55
|
const recordUsage = options.recordUsage ?? recordWorkspaceUsage;
|
|
@@ -100,6 +107,20 @@ export function createAutomationActivities(
|
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
const template = accepted.sessionTemplate;
|
|
110
|
+
if (
|
|
111
|
+
template.credentialRestriction === "developer_setup" &&
|
|
112
|
+
template.firstPartyMcpPermissions.some(
|
|
113
|
+
(permission) => !isDeveloperSetupDelegatedPermissionAllowed(permission),
|
|
114
|
+
)
|
|
115
|
+
) {
|
|
116
|
+
await settle(service.db, {
|
|
117
|
+
workspaceId: input.workspaceId,
|
|
118
|
+
runId: run.id,
|
|
119
|
+
status: "failed",
|
|
120
|
+
errorCode: "credential_restriction_violation",
|
|
121
|
+
});
|
|
122
|
+
return { action: "failed", reason: "credential_restriction_violation" };
|
|
123
|
+
}
|
|
103
124
|
const requestedModel = template.model ?? deploymentCatalogSettings.openaiModel;
|
|
104
125
|
const catalogSettings =
|
|
105
126
|
requestedModel.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) ||
|
|
@@ -158,7 +179,49 @@ export function createAutomationActivities(
|
|
|
158
179
|
reason: "interactive_compute_not_allowed",
|
|
159
180
|
};
|
|
160
181
|
}
|
|
161
|
-
|
|
182
|
+
// Agent configuration for the generated session (null = legacy). The
|
|
183
|
+
// template's explicit tools are its baseline; capabilities only narrow.
|
|
184
|
+
let agentWriteThrough: {
|
|
185
|
+
config: import("@opengeni/contracts").ResolvedAgentConfig | null;
|
|
186
|
+
instructions: string | undefined;
|
|
187
|
+
firstPartyMcpTools: typeof template.firstPartyMcpTools;
|
|
188
|
+
tools: typeof template.tools;
|
|
189
|
+
};
|
|
190
|
+
try {
|
|
191
|
+
const workspaceSettings = (await readWorkspace(service.db, input.workspaceId)).settings;
|
|
192
|
+
const resolution = resolveSessionAgentConfigForCreate({
|
|
193
|
+
settings: catalogSettings,
|
|
194
|
+
creator: "automation",
|
|
195
|
+
request: template.agent,
|
|
196
|
+
instructions: template.instructions ?? undefined,
|
|
197
|
+
workspaceSettings,
|
|
198
|
+
parent: null,
|
|
199
|
+
goal: false,
|
|
200
|
+
});
|
|
201
|
+
const written = applySessionAgentConfigWriteThrough({
|
|
202
|
+
config: resolution.config,
|
|
203
|
+
firstPartyMcpTools: template.firstPartyMcpTools,
|
|
204
|
+
tools: template.tools,
|
|
205
|
+
toolPolicy: { mode: "explicit", inheritedFromSessionId: null },
|
|
206
|
+
productServerIds: template.tools.map((tool) => tool.id),
|
|
207
|
+
});
|
|
208
|
+
agentWriteThrough = {
|
|
209
|
+
config: resolution.config,
|
|
210
|
+
instructions: resolution.instructions,
|
|
211
|
+
firstPartyMcpTools: written.firstPartyMcpTools,
|
|
212
|
+
tools: written.tools,
|
|
213
|
+
};
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (!isUnprocessableEntity(error)) throw error;
|
|
216
|
+
await settle(service.db, {
|
|
217
|
+
workspaceId: input.workspaceId,
|
|
218
|
+
runId: run.id,
|
|
219
|
+
status: "failed",
|
|
220
|
+
errorCode: "dispatch_failed",
|
|
221
|
+
});
|
|
222
|
+
return { action: "failed", reason: "dispatch_failed" };
|
|
223
|
+
}
|
|
224
|
+
const resolvedTurnExecutionPolicy = resolveTurnExecutionPolicyV1(catalogSettings, {
|
|
162
225
|
modelId: model,
|
|
163
226
|
requestedModelId: template.model,
|
|
164
227
|
modelSource: template.model ? "explicit" : "deployment",
|
|
@@ -167,6 +230,12 @@ export function createAutomationActivities(
|
|
|
167
230
|
latencyMode: "standard",
|
|
168
231
|
latencyModeSource: "deployment",
|
|
169
232
|
});
|
|
233
|
+
const turnExecutionPolicy = template.credentialRestriction
|
|
234
|
+
? {
|
|
235
|
+
...resolvedTurnExecutionPolicy,
|
|
236
|
+
credentialRestriction: template.credentialRestriction,
|
|
237
|
+
}
|
|
238
|
+
: resolvedTurnExecutionPolicy;
|
|
170
239
|
const created = await createSession({
|
|
171
240
|
db: service.db,
|
|
172
241
|
bus: service.bus,
|
|
@@ -189,10 +258,12 @@ export function createAutomationActivities(
|
|
|
189
258
|
accountId: input.accountId,
|
|
190
259
|
workspaceId: input.workspaceId,
|
|
191
260
|
initialMessage: accepted.initialMessage,
|
|
261
|
+
surface: "automation",
|
|
262
|
+
metrics: service.observability,
|
|
192
263
|
resources: template.resources,
|
|
193
264
|
skills: SessionSkills.parse(template.skills),
|
|
194
265
|
bundledSkillIds: template.bundledSkillIds,
|
|
195
|
-
tools:
|
|
266
|
+
tools: agentWriteThrough.tools,
|
|
196
267
|
toolPolicy: { mode: "explicit", inheritedFromSessionId: null },
|
|
197
268
|
model,
|
|
198
269
|
reasoningEffort,
|
|
@@ -211,10 +282,11 @@ export function createAutomationActivities(
|
|
|
211
282
|
label: accepted.serviceLabel,
|
|
212
283
|
},
|
|
213
284
|
createdByContext: accepted.provenance,
|
|
214
|
-
instructions: template.instructions,
|
|
285
|
+
instructions: agentWriteThrough.instructions ?? template.instructions,
|
|
215
286
|
policyRole: template.policyRole,
|
|
216
287
|
firstPartyMcpPermissions: template.firstPartyMcpPermissions,
|
|
217
|
-
firstPartyMcpTools:
|
|
288
|
+
firstPartyMcpTools: agentWriteThrough.firstPartyMcpTools,
|
|
289
|
+
...(agentWriteThrough.config ? { agentConfig: agentWriteThrough.config } : {}),
|
|
218
290
|
retainWorkspaceCustomModel:
|
|
219
291
|
model.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) ||
|
|
220
292
|
model.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX),
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { Context } from "@temporalio/activity";
|
|
2
|
+
import {
|
|
3
|
+
environmentsEncryptionKeyBytes,
|
|
4
|
+
resolveFirstPartyDelegationSecret,
|
|
5
|
+
type Settings,
|
|
6
|
+
} from "@opengeni/config";
|
|
7
|
+
import { BROWSER_STATE_ARTIFACT_CONTENT_TYPE } from "@opengeni/contracts";
|
|
8
|
+
import {
|
|
9
|
+
browserDeadlineCheckpoint,
|
|
10
|
+
clearSuspendedBrowserSessionController,
|
|
11
|
+
commitBrowserSessionSuspension,
|
|
12
|
+
dispatchBrowserSessionOperation,
|
|
13
|
+
failBrowserSessionSuspension,
|
|
14
|
+
listBrowserDeadlineCheckpoints,
|
|
15
|
+
readLease,
|
|
16
|
+
releaseLeaseHolder,
|
|
17
|
+
withRlsContext,
|
|
18
|
+
type BrowserDeadlineCheckpointTarget,
|
|
19
|
+
} from "@opengeni/db";
|
|
20
|
+
import { deriveBrowserControllerAdminToken } from "@opengeni/interaction/browser-controller-authority";
|
|
21
|
+
import {
|
|
22
|
+
browserStateArtifactAad,
|
|
23
|
+
browserStateManifestDigest,
|
|
24
|
+
browserStateObjectKey,
|
|
25
|
+
deriveBrowserStateDataKey,
|
|
26
|
+
wrapBrowserStateDataKey,
|
|
27
|
+
} from "@opengeni/interaction/browser-state-authority";
|
|
28
|
+
import {
|
|
29
|
+
BrowserControlClient,
|
|
30
|
+
BrowserControlRequestError,
|
|
31
|
+
createSandboxClientForBackend,
|
|
32
|
+
deserializeSandboxSessionStateEnvelope,
|
|
33
|
+
resumeExactSandboxSession,
|
|
34
|
+
type BrowserControlPlacementSession,
|
|
35
|
+
} from "@opengeni/runtime";
|
|
36
|
+
import type { ControlActivityServices } from "./types";
|
|
37
|
+
|
|
38
|
+
const UPLOAD_CLEANUP_GRACE_MS = 24 * 60 * 60_000;
|
|
39
|
+
|
|
40
|
+
function heartbeat(): void {
|
|
41
|
+
try {
|
|
42
|
+
Context.current().heartbeat();
|
|
43
|
+
} catch {
|
|
44
|
+
// Direct embedded calls have no Temporal context. In-flight controller
|
|
45
|
+
// operations still settle under their exact durable database claim.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function withActivityHeartbeat<T>(run: () => Promise<T>): Promise<T> {
|
|
50
|
+
heartbeat();
|
|
51
|
+
const timer = setInterval(heartbeat, 5_000);
|
|
52
|
+
try {
|
|
53
|
+
return await run();
|
|
54
|
+
} finally {
|
|
55
|
+
clearInterval(timer);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type CheckpointController = Pick<BrowserControlClient, "captureState" | "endSession">;
|
|
60
|
+
type CheckpointPlacement = {
|
|
61
|
+
target: BrowserDeadlineCheckpointTarget;
|
|
62
|
+
lease: NonNullable<Awaited<ReturnType<typeof readLease>>>;
|
|
63
|
+
settings: Settings;
|
|
64
|
+
controllerRoot: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
async function resumeCheckpointController({
|
|
68
|
+
target,
|
|
69
|
+
lease,
|
|
70
|
+
settings,
|
|
71
|
+
controllerRoot,
|
|
72
|
+
}: CheckpointPlacement): Promise<CheckpointController> {
|
|
73
|
+
// This edge cannot create a box or route through a user's current machine.
|
|
74
|
+
const provider = createSandboxClientForBackend("modal", settings) as Parameters<
|
|
75
|
+
typeof deserializeSandboxSessionStateEnvelope
|
|
76
|
+
>[0];
|
|
77
|
+
const envelope = lease.resumeState as { sessionState?: unknown };
|
|
78
|
+
const state = await deserializeSandboxSessionStateEnvelope(
|
|
79
|
+
provider,
|
|
80
|
+
envelope.sessionState ?? lease.resumeState,
|
|
81
|
+
target.instanceId,
|
|
82
|
+
);
|
|
83
|
+
const resumed = await resumeExactSandboxSession(provider, "modal", state, target.instanceId);
|
|
84
|
+
return new BrowserControlClient(resumed.session as BrowserControlPlacementSession, {
|
|
85
|
+
adminToken: deriveBrowserControllerAdminToken({
|
|
86
|
+
rootSecret: controllerRoot,
|
|
87
|
+
accountId: target.accountId,
|
|
88
|
+
workspaceId: target.workspaceId,
|
|
89
|
+
placement: { kind: "sandbox_group", sandboxGroupId: target.sandboxGroupId },
|
|
90
|
+
placementInstanceId: target.instanceId,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function createBrowserDeadlineCheckpointActivities(
|
|
96
|
+
services: () => Promise<ControlActivityServices>,
|
|
97
|
+
connectController: (
|
|
98
|
+
placement: CheckpointPlacement,
|
|
99
|
+
) => Promise<CheckpointController> = resumeCheckpointController,
|
|
100
|
+
) {
|
|
101
|
+
return {
|
|
102
|
+
async listDueBrowserCheckpoints() {
|
|
103
|
+
return await withActivityHeartbeat(async () => {
|
|
104
|
+
const { db, settings, objectStorage } = await services();
|
|
105
|
+
if (
|
|
106
|
+
!settings.sandboxOwnershipEnabled ||
|
|
107
|
+
!objectStorage ||
|
|
108
|
+
!resolveFirstPartyDelegationSecret(settings)
|
|
109
|
+
)
|
|
110
|
+
return [];
|
|
111
|
+
const root = environmentsEncryptionKeyBytes(settings);
|
|
112
|
+
if (!root) return [];
|
|
113
|
+
root.fill(0);
|
|
114
|
+
return await listBrowserDeadlineCheckpoints(db);
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
async checkpointBrowserBeforeDeadline(target: BrowserDeadlineCheckpointTarget) {
|
|
118
|
+
return await withActivityHeartbeat(async () => {
|
|
119
|
+
const { db, settings, objectStorage } = await services();
|
|
120
|
+
const rootKey = environmentsEncryptionKeyBytes(settings);
|
|
121
|
+
const controllerRoot = resolveFirstPartyDelegationSecret(settings);
|
|
122
|
+
if (!rootKey || !objectStorage || !controllerRoot) {
|
|
123
|
+
rootKey?.fill(0);
|
|
124
|
+
throw new Error("browser deadline checkpoint storage or encryption is unavailable");
|
|
125
|
+
}
|
|
126
|
+
let dataKey: Buffer | null = null;
|
|
127
|
+
let aad: Buffer | null = null;
|
|
128
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
129
|
+
try {
|
|
130
|
+
const claim = await browserDeadlineCheckpoint(db, target, { prepare: true, touch: true });
|
|
131
|
+
if (!claim) return { status: "skipped" as const };
|
|
132
|
+
let pulseRunning = false;
|
|
133
|
+
let authorityLost = false;
|
|
134
|
+
const pulse = async () => {
|
|
135
|
+
if (pulseRunning) return;
|
|
136
|
+
pulseRunning = true;
|
|
137
|
+
try {
|
|
138
|
+
if (!(await browserDeadlineCheckpoint(db, target, { touch: true })))
|
|
139
|
+
authorityLost = true;
|
|
140
|
+
} finally {
|
|
141
|
+
pulseRunning = false;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
timer = setInterval(() => {
|
|
145
|
+
void pulse().catch(() => undefined);
|
|
146
|
+
}, 5_000);
|
|
147
|
+
const lease = await readLease(db, target.workspaceId, target.sandboxGroupId);
|
|
148
|
+
if (
|
|
149
|
+
!lease ||
|
|
150
|
+
lease.instanceId !== target.instanceId ||
|
|
151
|
+
lease.leaseEpoch !== target.leaseEpoch ||
|
|
152
|
+
!lease.resumeState
|
|
153
|
+
) {
|
|
154
|
+
throw new Error("browser deadline checkpoint placement changed");
|
|
155
|
+
}
|
|
156
|
+
const placement = {
|
|
157
|
+
kind: "sandbox_group" as const,
|
|
158
|
+
sandboxGroupId: target.sandboxGroupId,
|
|
159
|
+
};
|
|
160
|
+
const client = await connectController({ target, lease, settings, controllerRoot });
|
|
161
|
+
if (authorityLost || !(await browserDeadlineCheckpoint(db, target, { touch: true }))) {
|
|
162
|
+
throw new Error("browser deadline checkpoint authority changed");
|
|
163
|
+
}
|
|
164
|
+
if (claim.state !== "completed") {
|
|
165
|
+
const scope = { ...target, operationId: claim.operationId };
|
|
166
|
+
const objectKey = browserStateObjectKey(target.workspaceId, claim.operationId);
|
|
167
|
+
dataKey = deriveBrowserStateDataKey(rootKey, { ...scope, objectKey });
|
|
168
|
+
aad = browserStateArtifactAad({ ...scope, objectKey });
|
|
169
|
+
await dispatchBrowserSessionOperation(db, {
|
|
170
|
+
...scope,
|
|
171
|
+
deadlineTarget: target,
|
|
172
|
+
stateUpload: {
|
|
173
|
+
objectKey,
|
|
174
|
+
cleanupAfter: new Date(Date.now() + UPLOAD_CLEANUP_GRACE_MS),
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
const signed = await objectStorage.createPutUrl({
|
|
178
|
+
key: objectKey,
|
|
179
|
+
contentType: BROWSER_STATE_ARTIFACT_CONTENT_TYPE,
|
|
180
|
+
audience: "sandbox",
|
|
181
|
+
});
|
|
182
|
+
const receipt = await client
|
|
183
|
+
.captureState({
|
|
184
|
+
...scope,
|
|
185
|
+
objectKey,
|
|
186
|
+
afterCapture: "stop",
|
|
187
|
+
dataKey,
|
|
188
|
+
aad,
|
|
189
|
+
upload: {
|
|
190
|
+
url: signed.url,
|
|
191
|
+
requiredHeaders: signed.requiredHeaders,
|
|
192
|
+
expiresAt: signed.expiresAt.toISOString(),
|
|
193
|
+
},
|
|
194
|
+
})
|
|
195
|
+
.catch(async (error: unknown) => {
|
|
196
|
+
if (
|
|
197
|
+
error instanceof BrowserControlRequestError &&
|
|
198
|
+
(error.error.code === "outcome_unknown" || !error.error.retryable)
|
|
199
|
+
) {
|
|
200
|
+
await failBrowserSessionSuspension(db, { ...scope, error: error.error });
|
|
201
|
+
}
|
|
202
|
+
throw error;
|
|
203
|
+
});
|
|
204
|
+
if (authorityLost) throw new Error("browser deadline checkpoint authority changed");
|
|
205
|
+
const portable = receipt.manifest.profileCrypto !== "platform_bound";
|
|
206
|
+
await commitBrowserSessionSuspension(db, {
|
|
207
|
+
...scope,
|
|
208
|
+
deadlineTarget: target,
|
|
209
|
+
artifact: {
|
|
210
|
+
kind: "chromium_profile",
|
|
211
|
+
format: receipt.format,
|
|
212
|
+
objectKey,
|
|
213
|
+
artifactDigest: receipt.artifactDigest,
|
|
214
|
+
contentDigest: receipt.contentDigest,
|
|
215
|
+
manifestDigest: browserStateManifestDigest(receipt.manifest),
|
|
216
|
+
sizeBytes: receipt.sizeBytes,
|
|
217
|
+
encryptedDataKey: wrapBrowserStateDataKey(rootKey, dataKey, {
|
|
218
|
+
...scope,
|
|
219
|
+
objectKey,
|
|
220
|
+
artifactDigest: receipt.artifactDigest,
|
|
221
|
+
contentDigest: receipt.contentDigest,
|
|
222
|
+
}),
|
|
223
|
+
materialization: {
|
|
224
|
+
portability: portable ? "portable" : "placement_bound",
|
|
225
|
+
reason: portable
|
|
226
|
+
? null
|
|
227
|
+
: "Profile encryption depends on the source operating-system credential store.",
|
|
228
|
+
platform: receipt.manifest.platform,
|
|
229
|
+
architecture: receipt.manifest.architecture,
|
|
230
|
+
engine: receipt.manifest.engine,
|
|
231
|
+
engineVersion: receipt.manifest.engineVersion,
|
|
232
|
+
driverId: receipt.manifest.driverId,
|
|
233
|
+
driverSchemaVersion: receipt.manifest.driverSchemaVersion,
|
|
234
|
+
profileCrypto: receipt.manifest.profileCrypto,
|
|
235
|
+
providerId: null,
|
|
236
|
+
placement: portable ? null : placement,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
// Only remove the local profile after the encrypted artifact and its
|
|
242
|
+
// authority committed. A crash resumes this cleanup, never capture.
|
|
243
|
+
await client.endSession(target, { removeState: true }).catch((error: unknown) => {
|
|
244
|
+
if (!(error instanceof BrowserControlRequestError && error.status === 404)) throw error;
|
|
245
|
+
});
|
|
246
|
+
await withRlsContext(
|
|
247
|
+
db,
|
|
248
|
+
target,
|
|
249
|
+
async (tx) => {
|
|
250
|
+
if ((await browserDeadlineCheckpoint(tx, target))?.state !== "completed") {
|
|
251
|
+
throw new Error("browser deadline checkpoint cleanup authority changed");
|
|
252
|
+
}
|
|
253
|
+
await clearSuspendedBrowserSessionController(tx, {
|
|
254
|
+
...target,
|
|
255
|
+
expectedControllerGeneration: target.controllerGeneration,
|
|
256
|
+
});
|
|
257
|
+
// One transaction prevents a human resume from acquiring a new
|
|
258
|
+
// same-browser holder between clearing and releasing the old one.
|
|
259
|
+
await releaseLeaseHolder(tx, {
|
|
260
|
+
...target,
|
|
261
|
+
kind: "interaction",
|
|
262
|
+
holderId: `browser-session:${target.browserSessionId}`,
|
|
263
|
+
idleGraceMs: settings.sandboxIdleGraceMs,
|
|
264
|
+
});
|
|
265
|
+
},
|
|
266
|
+
undefined,
|
|
267
|
+
"none",
|
|
268
|
+
);
|
|
269
|
+
return { status: "suspended" as const };
|
|
270
|
+
} finally {
|
|
271
|
+
if (timer) clearInterval(timer);
|
|
272
|
+
dataKey?.fill(0);
|
|
273
|
+
aad?.fill(0);
|
|
274
|
+
rootKey.fill(0);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CLAUDE_CONNECTION_KINDS,
|
|
3
|
+
claudeProviderId,
|
|
4
|
+
withClaudeConnectionCatalog,
|
|
5
|
+
withClaudeConnectionCredential,
|
|
6
|
+
} from "@opengeni/config";
|
|
1
7
|
import {
|
|
2
8
|
environmentsEncryptionKeyBytes,
|
|
3
9
|
type Settings,
|
|
@@ -22,6 +28,7 @@ import {
|
|
|
22
28
|
getWorkspaceOpenRouterCustomModelForExecution,
|
|
23
29
|
listSessionMcpServerMetadata,
|
|
24
30
|
listSessionMcpServersForRun,
|
|
31
|
+
getSessionAttemptMcpApprovalPolicies,
|
|
25
32
|
listWorkspaceGatewayCustomModels,
|
|
26
33
|
listWorkspaceOpenRouterCustomModels,
|
|
27
34
|
workspaceCodexSubscriptionActive,
|
|
@@ -30,6 +37,9 @@ import {
|
|
|
30
37
|
listOrganizationModelProviderCustomModelsForWorkspace,
|
|
31
38
|
getOrganizationModelProviderCustomModelForExecution,
|
|
32
39
|
loadOrganizationModelProviderApiKey,
|
|
40
|
+
listWorkspaceProviderCustomModels,
|
|
41
|
+
getWorkspaceProviderCustomModelForExecution,
|
|
42
|
+
loadWorkspaceProviderApiKey,
|
|
33
43
|
type Database,
|
|
34
44
|
type SessionMcpServerForRun,
|
|
35
45
|
} from "@opengeni/db";
|
|
@@ -47,10 +57,40 @@ export async function settingsWithSessionMcpServersForRun(
|
|
|
47
57
|
},
|
|
48
58
|
): Promise<Settings> {
|
|
49
59
|
const encryptionKey = environmentsEncryptionKeyBytes(settings);
|
|
60
|
+
let policies: Awaited<ReturnType<typeof getSessionAttemptMcpApprovalPolicies>>;
|
|
61
|
+
let resolvedServers: SessionMcpServerForRun[] | undefined;
|
|
62
|
+
if (encryptionKey && typeof (db as Database & { rollback?: unknown }).rollback !== "function") {
|
|
63
|
+
// Both readers independently fence this exact active attempt. The server
|
|
64
|
+
// read must remain fresh for credential renewal; it does not consume the
|
|
65
|
+
// policy read's result. Root-pool RLS transactions may overlap, whereas
|
|
66
|
+
// nested scopes on a transaction handle must retain serial savepoints.
|
|
67
|
+
const [policyResult, serverResult] = await Promise.allSettled([
|
|
68
|
+
(async () =>
|
|
69
|
+
await getSessionAttemptMcpApprovalPolicies(db, workspaceId, sessionId, attemptId))(),
|
|
70
|
+
(async () =>
|
|
71
|
+
await listSessionMcpServersForRun(db, workspaceId, sessionId, attemptId, encryptionKey))(),
|
|
72
|
+
]);
|
|
73
|
+
// Observe both reads before returning or propagating an error. Preserve the
|
|
74
|
+
// previous policy-first diagnostic priority, including synchronous ports.
|
|
75
|
+
if (policyResult.status === "rejected") throw policyResult.reason;
|
|
76
|
+
if (serverResult.status === "rejected") throw serverResult.reason;
|
|
77
|
+
policies = policyResult.value;
|
|
78
|
+
resolvedServers = serverResult.value;
|
|
79
|
+
} else {
|
|
80
|
+
policies = await getSessionAttemptMcpApprovalPolicies(db, workspaceId, sessionId, attemptId);
|
|
81
|
+
}
|
|
82
|
+
const policySettings = {
|
|
83
|
+
...settings,
|
|
84
|
+
mcpServers: settings.mcpServers.map((server) =>
|
|
85
|
+
Object.hasOwn(policies, server.id)
|
|
86
|
+
? { ...server, requireApproval: policies[server.id] }
|
|
87
|
+
: server,
|
|
88
|
+
),
|
|
89
|
+
};
|
|
50
90
|
if (!encryptionKey) {
|
|
51
91
|
const metadata = await listSessionMcpServerMetadata(db, workspaceId, sessionId);
|
|
52
92
|
if (metadata.length === 0) {
|
|
53
|
-
return
|
|
93
|
+
return policySettings;
|
|
54
94
|
}
|
|
55
95
|
if (metadata.some((server) => server.headerNames.length > 0)) {
|
|
56
96
|
throw new Error(
|
|
@@ -58,18 +98,20 @@ export async function settingsWithSessionMcpServersForRun(
|
|
|
58
98
|
);
|
|
59
99
|
}
|
|
60
100
|
}
|
|
61
|
-
const servers =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
101
|
+
const servers =
|
|
102
|
+
resolvedServers ??
|
|
103
|
+
(await listSessionMcpServersForRun(
|
|
104
|
+
db,
|
|
105
|
+
workspaceId,
|
|
106
|
+
sessionId,
|
|
107
|
+
attemptId,
|
|
108
|
+
encryptionKey ?? null,
|
|
109
|
+
));
|
|
68
110
|
// Keep credential provenance coupled to the exact decrypted rows that are
|
|
69
111
|
// overlaid into settings. A session projection read earlier in the turn can
|
|
70
112
|
// be stale after a concurrent mcpCredentialUpdates renewal.
|
|
71
113
|
options?.onResolvedServers?.(servers);
|
|
72
|
-
return settingsWithSessionMcpServers(
|
|
114
|
+
return settingsWithSessionMcpServers(policySettings, servers);
|
|
73
115
|
}
|
|
74
116
|
|
|
75
117
|
export function settingsWithSessionMcpServers(
|
|
@@ -233,7 +275,10 @@ export async function settingsWithOrganizationProviderCredentials(
|
|
|
233
275
|
settings: Settings,
|
|
234
276
|
retainedProductModelId?: string | null,
|
|
235
277
|
): Promise<Settings> {
|
|
236
|
-
const buildModels = async (
|
|
278
|
+
const buildModels = async (
|
|
279
|
+
providerKind: "vercel_gateway" | "openrouter" | "anthropic" | "claude_subscription",
|
|
280
|
+
prefix: string,
|
|
281
|
+
) => {
|
|
237
282
|
const active = await listOrganizationModelProviderCustomModelsForWorkspace(db, {
|
|
238
283
|
accountId,
|
|
239
284
|
workspaceId,
|
|
@@ -269,7 +314,59 @@ export async function settingsWithOrganizationProviderCredentials(
|
|
|
269
314
|
workspaceId,
|
|
270
315
|
providerKind: "openrouter",
|
|
271
316
|
});
|
|
272
|
-
|
|
317
|
+
let result = openRouterKey
|
|
273
318
|
? withOrganizationOpenRouterCredential(gatewaySettings, openRouterKey, openRouterModels)
|
|
274
319
|
: withOrganizationOpenRouterCatalogProvider(gatewaySettings, openRouterModels);
|
|
320
|
+
for (const kind of CLAUDE_CONNECTION_KINDS) {
|
|
321
|
+
if (kind === "claude_subscription" && !settings.claudeSubscriptionEnabled) continue;
|
|
322
|
+
const models = await buildModels(kind, claudeProviderId(kind) + "/");
|
|
323
|
+
result = withClaudeConnectionCatalog(result, { [kind]: { models } });
|
|
324
|
+
const credential =
|
|
325
|
+
kind === "claude_subscription"
|
|
326
|
+
? null
|
|
327
|
+
: await loadOrganizationModelProviderApiKey(db, settings, {
|
|
328
|
+
accountId,
|
|
329
|
+
workspaceId,
|
|
330
|
+
providerKind: kind,
|
|
331
|
+
});
|
|
332
|
+
if (credential)
|
|
333
|
+
result = withClaudeConnectionCredential(result, kind, credential, "organization", undefined);
|
|
334
|
+
const workspaceModels = await listWorkspaceProviderCustomModels(db, {
|
|
335
|
+
accountId,
|
|
336
|
+
workspaceId,
|
|
337
|
+
providerKind: kind,
|
|
338
|
+
});
|
|
339
|
+
const workspacePrefix = claudeProviderId(kind, "workspace") + "/";
|
|
340
|
+
const workspaceModelId = retainedProductModelId?.startsWith(workspacePrefix)
|
|
341
|
+
? retainedProductModelId
|
|
342
|
+
: null;
|
|
343
|
+
if (workspaceModelId) {
|
|
344
|
+
const retained = await getWorkspaceProviderCustomModelForExecution(db, {
|
|
345
|
+
accountId,
|
|
346
|
+
workspaceId,
|
|
347
|
+
providerKind: kind,
|
|
348
|
+
upstreamModelId: workspaceModelId.slice(workspacePrefix.length),
|
|
349
|
+
});
|
|
350
|
+
if (retained && !workspaceModels.some((model) => model.id === retained.id))
|
|
351
|
+
workspaceModels.push(retained);
|
|
352
|
+
}
|
|
353
|
+
result = withClaudeConnectionCatalog(
|
|
354
|
+
result,
|
|
355
|
+
{ [kind]: { models: workspaceModels } },
|
|
356
|
+
"workspace",
|
|
357
|
+
);
|
|
358
|
+
const workspaceCredential =
|
|
359
|
+
kind === "claude_subscription"
|
|
360
|
+
? null
|
|
361
|
+
: await loadWorkspaceProviderApiKey(db, settings, workspaceId, kind, workspaceModelId);
|
|
362
|
+
if (workspaceCredential)
|
|
363
|
+
result = withClaudeConnectionCredential(
|
|
364
|
+
result,
|
|
365
|
+
kind,
|
|
366
|
+
workspaceCredential,
|
|
367
|
+
"workspace",
|
|
368
|
+
undefined,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
return result;
|
|
275
372
|
}
|