@opengeni/worker-bundle 2.2.1 → 2.3.0-canary.36935312914001
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/credential-restriction.d.ts +3 -0
- package/dist/activities/agent-turn/run-credentials.d.ts +2 -0
- package/dist/activities/scheduled-tasks.d.ts +4 -35
- package/dist/activities/types.d.ts +3 -0
- package/dist/activities/workspace-capture.d.ts +2 -0
- package/dist/{activities-control-55ECL47G.js → activities-control-RDA4E2DM.js} +102 -20
- package/dist/activities-control-RDA4E2DM.js.map +1 -0
- package/dist/{activities-turn-T7Y3BWYO.js → activities-turn-A7LDKRLD.js} +20 -7
- package/dist/activities-turn-A7LDKRLD.js.map +1 -0
- package/dist/{chunk-OWNLATJL.js → chunk-HXPW4HPN.js} +60 -24
- package/dist/chunk-HXPW4HPN.js.map +1 -0
- package/dist/{chunk-IJZU752L.js → chunk-YG27NEMX.js} +34 -1
- package/dist/chunk-YG27NEMX.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/observability-metrics.d.ts +16 -1
- package/dist/workflow-bundle.js +18 -12
- package/dist/workflows/scheduled-tasks.d.ts +4 -0
- package/package.json +21 -21
- package/src/activities/agent-turn/claim.ts +13 -1
- package/src/activities/agent-turn/credential-restriction.ts +14 -0
- package/src/activities/agent-turn/errors.ts +39 -13
- package/src/activities/agent-turn/run-credentials.ts +5 -0
- package/src/activities/agent-turn/run.ts +1 -0
- package/src/activities/agent-turn/tool-environment.ts +4 -0
- package/src/activities/automations.ts +23 -1
- package/src/activities/goals.ts +33 -8
- package/src/activities/sandbox-lease.ts +22 -0
- package/src/activities/scheduled-tasks.ts +89 -25
- package/src/activities/site-auth-maintenance.ts +1 -0
- package/src/activities/types.ts +3 -0
- package/src/activities/workspace-capture.ts +13 -2
- package/src/observability-metrics.ts +55 -1
- package/src/workflows/scheduled-tasks.ts +26 -13
- package/dist/activities-control-55ECL47G.js.map +0 -1
- package/dist/activities-turn-T7Y3BWYO.js.map +0 -1
- package/dist/chunk-IJZU752L.js.map +0 -1
- package/dist/chunk-OWNLATJL.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TurnInitiator } from "@opengeni/contracts";
|
|
2
|
+
import type { DispatchScheduledTaskRunInput } from "../activities/types.js";
|
|
2
3
|
type ScheduledTaskFireWorkflowBase = {
|
|
3
4
|
accountId: string;
|
|
4
5
|
workspaceId: string;
|
|
@@ -8,10 +9,13 @@ export type ScheduledTaskFireWorkflowInput = ScheduledTaskFireWorkflowBase & ({
|
|
|
8
9
|
triggerType: "scheduled";
|
|
9
10
|
agentRunUsageIdempotencyKey?: never;
|
|
10
11
|
initiator?: never;
|
|
12
|
+
credentialRestriction?: never;
|
|
11
13
|
} | {
|
|
12
14
|
triggerType: "manual" | "initial" | "provider_event" | "retry" | "repair";
|
|
13
15
|
agentRunUsageIdempotencyKey: string;
|
|
14
16
|
initiator: TurnInitiator;
|
|
17
|
+
credentialRestriction?: "developer_setup";
|
|
15
18
|
});
|
|
19
|
+
export declare function scheduledTaskDispatchInput(input: ScheduledTaskFireWorkflowInput, producerKey: string): DispatchScheduledTaskRunInput;
|
|
16
20
|
export declare function scheduledTaskFireWorkflow(input: ScheduledTaskFireWorkflowInput): Promise<void>;
|
|
17
21
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/worker-bundle",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0-canary.36935312914001",
|
|
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": {
|
|
@@ -54,26 +54,26 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@llamaindex/liteparse": "2.14.2",
|
|
57
|
-
"@opengeni/agent-proto": "^0.6.1",
|
|
58
|
-
"@opengeni/capabilities": "^0.3.5",
|
|
59
|
-
"@opengeni/codemode": "^0.6.
|
|
60
|
-
"@opengeni/codex": "^0.2.
|
|
61
|
-
"@opengeni/config": "^3.2.
|
|
62
|
-
"@opengeni/contracts": "^5.
|
|
63
|
-
"@opengeni/core": "^5.0.
|
|
64
|
-
"@opengeni/db": "^6.
|
|
65
|
-
"@opengeni/documents": "^0.8.
|
|
66
|
-
"@opengeni/events": "^0.4.
|
|
67
|
-
"@opengeni/github": "^0.8.
|
|
68
|
-
"@opengeni/interaction": "^0.4.
|
|
69
|
-
"@opengeni/jev": "^0.2.1",
|
|
70
|
-
"@opengeni/network": "^0.3.1",
|
|
71
|
-
"@opengeni/observability": "^0.8.
|
|
72
|
-
"@opengeni/runtime": "^4.
|
|
73
|
-
"@opengeni/sdk": "^7.
|
|
74
|
-
"@opengeni/storage": "^0.2.
|
|
75
|
-
"@opengeni/tool-gateway": "^0.1.
|
|
76
|
-
"@opengeni/xai-subscription": "^0.1.5",
|
|
57
|
+
"@opengeni/agent-proto": "^0.6.1-canary.36935312914001",
|
|
58
|
+
"@opengeni/capabilities": "^0.3.5-canary.36935312914001",
|
|
59
|
+
"@opengeni/codemode": "^0.6.7-canary.36935312914001",
|
|
60
|
+
"@opengeni/codex": "^0.2.31-canary.36935312914001",
|
|
61
|
+
"@opengeni/config": "^3.2.1-canary.36935312914001",
|
|
62
|
+
"@opengeni/contracts": "^5.6.0-canary.36935312914001",
|
|
63
|
+
"@opengeni/core": "^5.1.0-canary.36935312914001",
|
|
64
|
+
"@opengeni/db": "^6.4.0-canary.36935312914001",
|
|
65
|
+
"@opengeni/documents": "^0.8.39-canary.36935312914001",
|
|
66
|
+
"@opengeni/events": "^0.4.37-canary.36935312914001",
|
|
67
|
+
"@opengeni/github": "^0.8.2-canary.36935312914001",
|
|
68
|
+
"@opengeni/interaction": "^0.4.45-canary.36935312914001",
|
|
69
|
+
"@opengeni/jev": "^0.2.1-canary.36935312914001",
|
|
70
|
+
"@opengeni/network": "^0.3.1-canary.36935312914001",
|
|
71
|
+
"@opengeni/observability": "^0.8.37-canary.36935312914001",
|
|
72
|
+
"@opengeni/runtime": "^4.5.0-canary.36935312914001",
|
|
73
|
+
"@opengeni/sdk": "^7.6.0-canary.36935312914001",
|
|
74
|
+
"@opengeni/storage": "^0.2.138-canary.36935312914001",
|
|
75
|
+
"@opengeni/tool-gateway": "^0.1.18-canary.36935312914001",
|
|
76
|
+
"@opengeni/xai-subscription": "^0.1.5-canary.36935312914001",
|
|
77
77
|
"@temporalio/activity": "^1.17.0",
|
|
78
78
|
"@temporalio/client": "^1.17.0",
|
|
79
79
|
"@temporalio/worker": "^1.17.0",
|
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
import { createTurnCredentialLeases } from "./credential-leases";
|
|
57
57
|
import { createTurnMediaArtifacts } from "./media-artifacts";
|
|
58
58
|
import { readTurnExecutionPolicyV1 } from "@opengeni/contracts";
|
|
59
|
+
import { turnCredentialRestriction } from "./credential-restriction";
|
|
59
60
|
|
|
60
61
|
import {
|
|
61
62
|
credentialSubjectIdForTurnInitiator,
|
|
@@ -290,10 +291,21 @@ export async function claimTurnAttempt(deps: ClaimTurnDeps): Promise<ClaimTurnOu
|
|
|
290
291
|
const codexAppsCredentialId = capabilitySettings.codexConnectedAppsEnabled
|
|
291
292
|
? await resolveCodexAppsCredentialIdForRun(db, input.workspaceId)
|
|
292
293
|
: null;
|
|
293
|
-
const
|
|
294
|
+
const candidatePolicy =
|
|
294
295
|
claimedPolicy.kind === "valid"
|
|
295
296
|
? claimedPolicy.policy
|
|
296
297
|
: resolveTurnExecutionPolicyV1(capabilitySettings, legacyTurnExecutionPolicyInput(turn));
|
|
298
|
+
// This context is frozen by the accepted-turn writer from the exact source
|
|
299
|
+
// turn. Its reserved restriction field cannot come from public service JSON.
|
|
300
|
+
const credentialRestriction =
|
|
301
|
+
claimedPolicy.kind === "absent"
|
|
302
|
+
? turn.initiatorContext?.credentialRestriction === "developer_setup"
|
|
303
|
+
? "developer_setup"
|
|
304
|
+
: turnCredentialRestriction(candidatePolicy, session.metadata)
|
|
305
|
+
: undefined;
|
|
306
|
+
const policyForAbsent = credentialRestriction
|
|
307
|
+
? { ...candidatePolicy, credentialRestriction }
|
|
308
|
+
: candidatePolicy;
|
|
297
309
|
const installedPolicy = await installOrReadTurnExecutionPolicyForAttempt(db, {
|
|
298
310
|
accountId: input.accountId,
|
|
299
311
|
workspaceId: input.workspaceId,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readTurnExecutionPolicyV1, type TurnExecutionPolicyV1 } from "@opengeni/contracts";
|
|
2
|
+
|
|
3
|
+
/** Only accepted policies establish the ceiling; ordinary metadata is not authority. */
|
|
4
|
+
export function turnCredentialRestriction(
|
|
5
|
+
acceptedPolicy: TurnExecutionPolicyV1,
|
|
6
|
+
initialSessionMetadata: unknown,
|
|
7
|
+
): "developer_setup" | undefined {
|
|
8
|
+
const initialPolicy = readTurnExecutionPolicyV1(initialSessionMetadata);
|
|
9
|
+
return acceptedPolicy.credentialRestriction === "developer_setup" ||
|
|
10
|
+
(initialPolicy.kind === "valid" &&
|
|
11
|
+
initialPolicy.policy.credentialRestriction === "developer_setup")
|
|
12
|
+
? "developer_setup"
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
ActiveSessionHistoryLimitExceededError,
|
|
4
4
|
ApprovalRunStateLimitExceededError,
|
|
5
5
|
nestedPostgresSqlState,
|
|
6
|
+
databaseFailureCode,
|
|
7
|
+
isRetryablePersistenceSqlState,
|
|
6
8
|
safeDatabaseErrorFacts,
|
|
7
9
|
isRetryableDatabaseTransportFailure,
|
|
8
10
|
isSessionEventPersistenceError,
|
|
@@ -352,6 +354,13 @@ function retryableDatabaseFailureCode(
|
|
|
352
354
|
error: unknown,
|
|
353
355
|
): PostClaimDatabaseRecoveryDetail["code"] | null {
|
|
354
356
|
const persistenceFailure = isSessionEventPersistenceError(error) ? error : null;
|
|
357
|
+
if (!persistenceFailure) {
|
|
358
|
+
const driver = findPostgresDriverError(error);
|
|
359
|
+
const driverSqlState = typeof driver?.code === "string" ? driver.code : null;
|
|
360
|
+
if (isRetryablePersistenceSqlState(driverSqlState)) {
|
|
361
|
+
return databaseFailureCode(driverSqlState);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
355
364
|
const sqlState = persistenceFailure?.details.sqlState ?? null;
|
|
356
365
|
if (sqlState === null && isRetryableDatabaseTransportFailure(error)) {
|
|
357
366
|
return "db_failure";
|
|
@@ -1010,6 +1019,16 @@ function findPostgresDriverError(error: unknown): Record<string, unknown> | null
|
|
|
1010
1019
|
return null;
|
|
1011
1020
|
}
|
|
1012
1021
|
|
|
1022
|
+
function isRawDatabaseQueryError(error: unknown): boolean {
|
|
1023
|
+
return (
|
|
1024
|
+
error instanceof Error &&
|
|
1025
|
+
"query" in error &&
|
|
1026
|
+
typeof error.query === "string" &&
|
|
1027
|
+
"params" in error &&
|
|
1028
|
+
Array.isArray(error.params)
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1013
1032
|
export function agentRunFailurePayload(
|
|
1014
1033
|
error: unknown,
|
|
1015
1034
|
options: { isCodexTurn?: boolean } = {},
|
|
@@ -1060,7 +1079,11 @@ function baseAgentRunFailurePayload(
|
|
|
1060
1079
|
return { error: error.message, code: "retained_attachment_transport_limit", retryable: false };
|
|
1061
1080
|
}
|
|
1062
1081
|
if (error instanceof MandatoryHistoryPersistenceError) {
|
|
1063
|
-
const
|
|
1082
|
+
const databaseFailure =
|
|
1083
|
+
isSessionEventPersistenceError(error.cause) ||
|
|
1084
|
+
findPostgresDriverError(error.cause) !== null ||
|
|
1085
|
+
isRawDatabaseQueryError(error.cause);
|
|
1086
|
+
const underlying = databaseFailure
|
|
1064
1087
|
? agentRunFailurePayload(error.cause, options)
|
|
1065
1088
|
: {
|
|
1066
1089
|
error: error.cause instanceof Error ? error.cause.message : String(error.cause),
|
|
@@ -1070,6 +1093,21 @@ function baseAgentRunFailurePayload(
|
|
|
1070
1093
|
historyPersistenceStage: error.stage,
|
|
1071
1094
|
};
|
|
1072
1095
|
}
|
|
1096
|
+
// Raw ORM wrappers can contain the full SQL and its parameters. Classify a
|
|
1097
|
+
// real driver before provider message heuristics; the original cause stays
|
|
1098
|
+
// available to internal diagnostics. This payload grants no replay authority.
|
|
1099
|
+
const postgresDriverError = findPostgresDriverError(error);
|
|
1100
|
+
const rawOrmFailure = isRawDatabaseQueryError(error);
|
|
1101
|
+
if ((postgresDriverError || rawOrmFailure) && !isSessionEventPersistenceError(error)) {
|
|
1102
|
+
const database = safeDatabaseErrorFacts(postgresDriverError ?? error);
|
|
1103
|
+
const sqlState = postgresDriverError ? nestedPostgresSqlState(postgresDriverError) : null;
|
|
1104
|
+
return {
|
|
1105
|
+
error: "OpenGeni encountered a database error.",
|
|
1106
|
+
code: databaseFailureCode(sqlState),
|
|
1107
|
+
sqlState,
|
|
1108
|
+
...(Object.keys(database).length > 0 ? { database } : {}),
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1073
1111
|
const safetyRefusalDiagnostic = providerSafetyRefusalDiagnostic(error);
|
|
1074
1112
|
if (safetyRefusalDiagnostic !== undefined) {
|
|
1075
1113
|
return {
|
|
@@ -1362,18 +1400,6 @@ function baseAgentRunFailurePayload(
|
|
|
1362
1400
|
}
|
|
1363
1401
|
return { error: message, code: "provider_unavailable", retryable: true };
|
|
1364
1402
|
}
|
|
1365
|
-
const postgresDriverError = findPostgresDriverError(error);
|
|
1366
|
-
if (postgresDriverError) {
|
|
1367
|
-
const database = safeDatabaseErrorFacts(postgresDriverError);
|
|
1368
|
-
const sqlState = nestedPostgresSqlState(postgresDriverError);
|
|
1369
|
-
if (sqlState !== null || Object.keys(database).length > 0) {
|
|
1370
|
-
return {
|
|
1371
|
-
error: message,
|
|
1372
|
-
sqlState,
|
|
1373
|
-
...(Object.keys(database).length > 0 ? { database } : {}),
|
|
1374
|
-
};
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
1403
|
return { error: message };
|
|
1378
1404
|
}
|
|
1379
1405
|
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
sandboxSettingsForRoute,
|
|
66
66
|
} from "./sandbox-route";
|
|
67
67
|
import type { ClaimTurnOk } from "./claim";
|
|
68
|
+
import { turnCredentialRestriction } from "./credential-restriction";
|
|
68
69
|
import type { GovernanceModelOk } from "./governance-model";
|
|
69
70
|
import type { SandboxTurnRuntime } from "./sandbox-runtime";
|
|
70
71
|
import type {
|
|
@@ -91,6 +92,7 @@ export type PrepareRunCredentialsDeps = {
|
|
|
91
92
|
sandboxRuntime: SandboxTurnRuntime;
|
|
92
93
|
turn: ClaimTurnOk["turn"];
|
|
93
94
|
session: ClaimTurnOk["session"];
|
|
95
|
+
turnExecutionPolicy: ClaimTurnOk["turnExecutionPolicy"];
|
|
94
96
|
fileAuthoritySubjectId: ClaimTurnOk["fileAuthoritySubjectId"];
|
|
95
97
|
runSettings: GovernanceModelOk["runSettings"];
|
|
96
98
|
workspaceVariableSet: Awaited<ReturnType<typeof loadWorkspaceEnvironmentForRunWithCredentials>>;
|
|
@@ -129,6 +131,7 @@ export async function prepareRunCredentials(deps: PrepareRunCredentialsDeps) {
|
|
|
129
131
|
sandboxState,
|
|
130
132
|
turn,
|
|
131
133
|
session,
|
|
134
|
+
turnExecutionPolicy,
|
|
132
135
|
fileAuthoritySubjectId,
|
|
133
136
|
runSettings,
|
|
134
137
|
workspaceVariableSet,
|
|
@@ -346,11 +349,13 @@ export async function prepareRunCredentials(deps: PrepareRunCredentialsDeps) {
|
|
|
346
349
|
turn,
|
|
347
350
|
})
|
|
348
351
|
: undefined;
|
|
352
|
+
const credentialRestriction = turnCredentialRestriction(turnExecutionPolicy, session.metadata);
|
|
349
353
|
const codemodeAuthority = {
|
|
350
354
|
sessionId: input.sessionId,
|
|
351
355
|
turnId: turn.id,
|
|
352
356
|
attemptId: input.attemptId,
|
|
353
357
|
executionGeneration: turn.executionGeneration,
|
|
358
|
+
...(credentialRestriction ? { credentialRestriction } : {}),
|
|
354
359
|
};
|
|
355
360
|
const sandboxArtifactRuntime = sandboxArtifactRuntimeAdmission(
|
|
356
361
|
settings,
|
|
@@ -127,6 +127,7 @@ import { codeSearchToolDefinitions, codeSearchWorkspaceFromChannel } from "./cod
|
|
|
127
127
|
import { createWorkspaceSkillTools } from "./skill-tools";
|
|
128
128
|
import { loadConfiguredBundledSkills } from "./skill-selection";
|
|
129
129
|
import { guardSkillFilesystem } from "./skill-transfer";
|
|
130
|
+
import { turnCredentialRestriction } from "./credential-restriction";
|
|
130
131
|
|
|
131
132
|
export type PrepareTurnToolPolicyDeps = {
|
|
132
133
|
input: RunAgentTurnInput;
|
|
@@ -422,6 +423,7 @@ export async function prepareTurnToolRuntime(deps: PrepareTurnToolRuntimeDeps) {
|
|
|
422
423
|
});
|
|
423
424
|
const runSettings = accountRoutes.settings;
|
|
424
425
|
const turnTools = accountRoutes.tools;
|
|
426
|
+
const credentialRestriction = turnCredentialRestriction(turnExecutionPolicy, session.metadata);
|
|
425
427
|
const toolContextPreparationStartedAt = performance.now();
|
|
426
428
|
throwIfWorkerShuttingDown();
|
|
427
429
|
throwIfTurnCancelled();
|
|
@@ -1009,6 +1011,7 @@ export async function prepareTurnToolRuntime(deps: PrepareTurnToolRuntimeDeps) {
|
|
|
1009
1011
|
: []),
|
|
1010
1012
|
...createFirstPartyInteractionAttemptToolDefinitions({
|
|
1011
1013
|
settings: runSettings,
|
|
1014
|
+
...(credentialRestriction ? { credentialRestriction } : {}),
|
|
1012
1015
|
scope: {
|
|
1013
1016
|
accountId: input.accountId,
|
|
1014
1017
|
workspaceId: input.workspaceId,
|
|
@@ -1104,6 +1107,7 @@ export async function prepareTurnToolRuntime(deps: PrepareTurnToolRuntimeDeps) {
|
|
|
1104
1107
|
try {
|
|
1105
1108
|
eventing.preparedTools = await waitForTurnOperation(
|
|
1106
1109
|
runtime.prepareTools(githubRestMcp.settings, githubRestMcp.tools, {
|
|
1110
|
+
...(credentialRestriction ? { credentialRestriction } : {}),
|
|
1107
1111
|
mcpAccountLabels: accountRoutes.accountLabels,
|
|
1108
1112
|
accountId: input.accountId,
|
|
1109
1113
|
workspaceId: input.workspaceId,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
recordWorkspaceUsage,
|
|
14
14
|
resolveCatalogSettings,
|
|
15
15
|
resolveWorkspaceCatalogSettings,
|
|
16
|
+
isDeveloperSetupDelegatedPermissionAllowed,
|
|
16
17
|
} from "@opengeni/core";
|
|
17
18
|
import {
|
|
18
19
|
AutomationAuthorityRevokedError,
|
|
@@ -107,6 +108,20 @@ export function createAutomationActivities(
|
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
const template = accepted.sessionTemplate;
|
|
111
|
+
if (
|
|
112
|
+
template.credentialRestriction === "developer_setup" &&
|
|
113
|
+
template.firstPartyMcpPermissions.some(
|
|
114
|
+
(permission) => !isDeveloperSetupDelegatedPermissionAllowed(permission),
|
|
115
|
+
)
|
|
116
|
+
) {
|
|
117
|
+
await settle(service.db, {
|
|
118
|
+
workspaceId: input.workspaceId,
|
|
119
|
+
runId: run.id,
|
|
120
|
+
status: "failed",
|
|
121
|
+
errorCode: "credential_restriction_violation",
|
|
122
|
+
});
|
|
123
|
+
return { action: "failed", reason: "credential_restriction_violation" };
|
|
124
|
+
}
|
|
110
125
|
const requestedModel = template.model ?? deploymentCatalogSettings.openaiModel;
|
|
111
126
|
const catalogSettings =
|
|
112
127
|
requestedModel.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) ||
|
|
@@ -209,7 +224,7 @@ export function createAutomationActivities(
|
|
|
209
224
|
});
|
|
210
225
|
return { action: "failed", reason: "dispatch_failed" };
|
|
211
226
|
}
|
|
212
|
-
const
|
|
227
|
+
const resolvedTurnExecutionPolicy = resolveTurnExecutionPolicyV1(catalogSettings, {
|
|
213
228
|
modelId: model,
|
|
214
229
|
requestedModelId: template.model,
|
|
215
230
|
modelSource: template.model ? "explicit" : "deployment",
|
|
@@ -218,6 +233,12 @@ export function createAutomationActivities(
|
|
|
218
233
|
latencyMode: "standard",
|
|
219
234
|
latencyModeSource: "deployment",
|
|
220
235
|
});
|
|
236
|
+
const turnExecutionPolicy = template.credentialRestriction
|
|
237
|
+
? {
|
|
238
|
+
...resolvedTurnExecutionPolicy,
|
|
239
|
+
credentialRestriction: template.credentialRestriction,
|
|
240
|
+
}
|
|
241
|
+
: resolvedTurnExecutionPolicy;
|
|
221
242
|
const created = await createSession({
|
|
222
243
|
db: service.db,
|
|
223
244
|
bus: service.bus,
|
|
@@ -241,6 +262,7 @@ export function createAutomationActivities(
|
|
|
241
262
|
workspaceId: input.workspaceId,
|
|
242
263
|
initialMessage: accepted.initialMessage,
|
|
243
264
|
surface: "automation",
|
|
265
|
+
metrics: service.observability,
|
|
244
266
|
resources: template.resources,
|
|
245
267
|
skills: SessionSkills.parse(template.skills),
|
|
246
268
|
bundledSkillIds: template.bundledSkillIds,
|
package/src/activities/goals.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
evaluateWorkspaceModelPolicy,
|
|
16
16
|
mergeToolRefs,
|
|
17
|
+
readTurnExecutionPolicyV1,
|
|
17
18
|
type SessionGoal,
|
|
18
19
|
type ToolRef,
|
|
19
20
|
} from "@opengeni/contracts";
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
enqueueSessionWorkflowWakeIfRunnable,
|
|
23
24
|
getWorkspaceModelPolicy,
|
|
24
25
|
getSessionGoal,
|
|
26
|
+
getSessionTurn,
|
|
25
27
|
materializeGoalContinuation,
|
|
26
28
|
requireSession,
|
|
27
29
|
} from "@opengeni/db";
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
resolveWorkspaceCatalogSettings,
|
|
37
39
|
} from "@opengeni/core";
|
|
38
40
|
import { agentRunAdmissionDenial } from "./agent-run-admission";
|
|
41
|
+
import { turnCredentialRestriction } from "./agent-turn/credential-restriction";
|
|
39
42
|
|
|
40
43
|
export function createGoalActivities(services: () => Promise<ControlActivityServices>) {
|
|
41
44
|
async function enqueueGoalRetryWake(input: MaybeContinueGoalInput): Promise<void> {
|
|
@@ -124,6 +127,16 @@ export function createGoalActivities(services: () => Promise<ControlActivityServ
|
|
|
124
127
|
latencyMode: continuationLatencyMode,
|
|
125
128
|
latencyModeSource: "continuation",
|
|
126
129
|
});
|
|
130
|
+
const continuationPolicy: NonNullable<
|
|
131
|
+
Parameters<typeof materializeGoalContinuation>[1]["policy"]
|
|
132
|
+
> = {
|
|
133
|
+
model: continuationModel,
|
|
134
|
+
reasoningEffort: continuationReasoningEffort,
|
|
135
|
+
latencyMode: continuationLatencyMode,
|
|
136
|
+
...(turnExecutionPolicy ? { turnExecutionPolicy } : {}),
|
|
137
|
+
tools: withFirstPartyTools(settings, session.tools),
|
|
138
|
+
sandboxBackend: session.sandboxBackend,
|
|
139
|
+
};
|
|
127
140
|
const decision = await materializeGoalContinuation(db, {
|
|
128
141
|
accountId: input.accountId,
|
|
129
142
|
workspaceId: input.workspaceId,
|
|
@@ -140,6 +153,25 @@ export function createGoalActivities(services: () => Promise<ControlActivityServ
|
|
|
140
153
|
// pause can clear on its own; a policy pause needs a model/policy change)
|
|
141
154
|
// and rides the same visible-pause channel.
|
|
142
155
|
admission: async (tx, causalTurn) => {
|
|
156
|
+
// The materializer selects this exact causal row under its session/goal
|
|
157
|
+
// locks and freezes policy only after admission returns. Never infer
|
|
158
|
+
// credential authority from the generated continuation's payload.
|
|
159
|
+
const sourceTurn = causalTurn
|
|
160
|
+
? await getSessionTurn(tx, input.workspaceId, causalTurn.id)
|
|
161
|
+
: null;
|
|
162
|
+
if (causalTurn && (!sourceTurn || sourceTurn.sessionId !== input.sessionId)) {
|
|
163
|
+
throw new Error("Goal continuation source turn is unavailable");
|
|
164
|
+
}
|
|
165
|
+
const sourcePolicy = readTurnExecutionPolicyV1(sourceTurn?.metadata);
|
|
166
|
+
if (turnExecutionPolicy) {
|
|
167
|
+
const credentialRestriction = turnCredentialRestriction(
|
|
168
|
+
sourcePolicy.kind === "valid" ? sourcePolicy.policy : turnExecutionPolicy,
|
|
169
|
+
session.metadata,
|
|
170
|
+
);
|
|
171
|
+
continuationPolicy.turnExecutionPolicy = credentialRestriction
|
|
172
|
+
? { ...turnExecutionPolicy, credentialRestriction }
|
|
173
|
+
: turnExecutionPolicy;
|
|
174
|
+
}
|
|
143
175
|
const budgetBlocked = modelPolicyBlocked
|
|
144
176
|
? null
|
|
145
177
|
: await goalRunBudgetBlocked(
|
|
@@ -158,14 +190,7 @@ export function createGoalActivities(services: () => Promise<ControlActivityServ
|
|
|
158
190
|
: (budgetBlocked?.pausedReason ?? "limits"),
|
|
159
191
|
};
|
|
160
192
|
},
|
|
161
|
-
policy:
|
|
162
|
-
model: continuationModel,
|
|
163
|
-
reasoningEffort: continuationReasoningEffort,
|
|
164
|
-
latencyMode: continuationLatencyMode,
|
|
165
|
-
...(turnExecutionPolicy ? { turnExecutionPolicy } : {}),
|
|
166
|
-
tools: withFirstPartyTools(settings, session.tools),
|
|
167
|
-
sandboxBackend: session.sandboxBackend,
|
|
168
|
-
},
|
|
193
|
+
policy: continuationPolicy,
|
|
169
194
|
// Long-wait guidance is only given when `wait_for_input` is actually in this
|
|
170
195
|
// session's effective first-party selection (the same source the worker
|
|
171
196
|
// signs into the delegated token and the API uses to register tools), so
|
|
@@ -41,6 +41,8 @@ import {
|
|
|
41
41
|
deferRetainedProcessReconciliation,
|
|
42
42
|
forceDrainOverLimitViewerOnlyBoxes,
|
|
43
43
|
listCreditBalancesByAccount,
|
|
44
|
+
countActiveUsers,
|
|
45
|
+
readCreditGrantTotals,
|
|
44
46
|
readVerifiedSignupTrialSwitch,
|
|
45
47
|
listLegacyModalCheckpointSlots,
|
|
46
48
|
listLiveModalSandboxLeaseAttributions,
|
|
@@ -150,7 +152,9 @@ import { assertSandboxDrainInputTiming, sandboxDrainTiming } from "../sandbox-re
|
|
|
150
152
|
import type { ControlActivityServices as ActivityServices } from "./types";
|
|
151
153
|
import { reconcilePendingParentSystemUpdates } from "./parent-wake";
|
|
152
154
|
import {
|
|
155
|
+
recordActiveUserGauges,
|
|
153
156
|
recordCreditBalanceGauges,
|
|
157
|
+
recordCreditGrantGauges,
|
|
154
158
|
recordCreditMicros,
|
|
155
159
|
recordExpiredDrainingSandboxLeaseGauges,
|
|
156
160
|
recordOpenSandboxKubernetesInventoryGauges,
|
|
@@ -2525,6 +2529,24 @@ async function refreshQueueLeaseAndCreditGauges(
|
|
|
2525
2529
|
});
|
|
2526
2530
|
}
|
|
2527
2531
|
})(),
|
|
2532
|
+
(async () => {
|
|
2533
|
+
try {
|
|
2534
|
+
recordActiveUserGauges(observability, await countActiveUsers(db));
|
|
2535
|
+
} catch (error) {
|
|
2536
|
+
observability.warn("sandbox reaper: active-user gauge refresh failed", {
|
|
2537
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
})(),
|
|
2541
|
+
(async () => {
|
|
2542
|
+
try {
|
|
2543
|
+
recordCreditGrantGauges(observability, await readCreditGrantTotals(db));
|
|
2544
|
+
} catch (error) {
|
|
2545
|
+
observability.warn("sandbox reaper: credit-grant gauge refresh failed", {
|
|
2546
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
})(),
|
|
2528
2550
|
(async () => {
|
|
2529
2551
|
recordVerifiedSignupTrialDeploymentFlagGauge(
|
|
2530
2552
|
observability,
|