@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
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { getScheduledTaskClaudeProviderAccountAuthoritySnapshot } from "@opengeni/db";
|
|
2
|
+
import {
|
|
3
|
+
ATLASSIAN_NATIVE_RETIRED_REASON,
|
|
4
|
+
isRetiredNativeAtlassianTask,
|
|
5
|
+
} from "@opengeni/contracts/atlassian-native-retirement";
|
|
1
6
|
import {
|
|
2
7
|
AUTOMATIC_SESSION_TITLE_FALLBACK,
|
|
3
8
|
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
@@ -10,28 +15,46 @@ import {
|
|
|
10
15
|
SessionAgentAccess,
|
|
11
16
|
SessionMemoryScope,
|
|
12
17
|
normalizeAutomaticSessionTitle,
|
|
18
|
+
metadataWithTurnExecutionPolicyV1,
|
|
19
|
+
mergeResourceRefs,
|
|
13
20
|
scheduledOccurrencePayloadUtf8Bytes,
|
|
14
21
|
stableJson,
|
|
15
22
|
TurnExecutionPolicyV1,
|
|
16
23
|
type ScheduledTask,
|
|
17
24
|
type ScheduledTaskRun,
|
|
25
|
+
type ResolvedAgentConfig,
|
|
18
26
|
} from "@opengeni/contracts";
|
|
19
27
|
import {
|
|
20
|
-
defaultSessionMcpServerIds,
|
|
21
28
|
openGeniSlackBotMetadata,
|
|
22
29
|
requireOpenGeniSlackBotConnection,
|
|
30
|
+
withScheduledSlackBotPostingTools,
|
|
23
31
|
resolveWorkspaceCatalogSettings,
|
|
32
|
+
resolveScheduledTaskDefaultModel,
|
|
24
33
|
resolveSessionToolPolicy,
|
|
25
34
|
workspaceCustomModelReference,
|
|
26
35
|
lockActiveCustomModelForAdmission,
|
|
27
36
|
scheduledSlackBotConnectionId,
|
|
37
|
+
freezeConnectionAccounts,
|
|
38
|
+
ConnectionAccountSelectionError,
|
|
39
|
+
scheduledConnectionSurfaceEligibility,
|
|
40
|
+
scheduledConnectionTools,
|
|
41
|
+
settingsWithEnabledCapabilityMcpServers,
|
|
42
|
+
settingsWithSessionMcpServerMetadata,
|
|
28
43
|
swapActiveSandbox,
|
|
44
|
+
applySessionAgentConfigWriteThrough,
|
|
45
|
+
resolveSessionAgentConfigForCreate,
|
|
46
|
+
recordSessionCreated,
|
|
47
|
+
recordUserMessageAccepted,
|
|
48
|
+
type ProductUsageMetricsSink,
|
|
29
49
|
} from "@opengeni/core";
|
|
30
50
|
import {
|
|
31
51
|
appendSessionEvents,
|
|
32
52
|
addSessionSystemUpdateWithSourceMutation,
|
|
33
53
|
bindScheduledTaskRunSessionInTransaction,
|
|
34
54
|
createScheduledTaskRun,
|
|
55
|
+
recordScheduledTaskAdmissionFailure,
|
|
56
|
+
recordScheduledTaskAdmissionRefusal,
|
|
57
|
+
type ScheduledTaskAdmissionRefusalReason,
|
|
35
58
|
createSession,
|
|
36
59
|
createSessionWithIdempotencyKeyResult,
|
|
37
60
|
enqueueSessionWorkflowWakeIfRunnable,
|
|
@@ -41,7 +64,6 @@ import {
|
|
|
41
64
|
getScheduledTaskRunAcceptedExecution,
|
|
42
65
|
getScheduledTaskRunByProducerKey,
|
|
43
66
|
getScheduledTargetSessionExecution,
|
|
44
|
-
getScheduledTaskPersonalConnectionDelegations,
|
|
45
67
|
getScheduledTaskRunPersonalResourceAuthority,
|
|
46
68
|
getScheduledTaskPersonalResourceAuthoritySubject,
|
|
47
69
|
getScheduledTaskRevisionAuthority,
|
|
@@ -53,11 +75,11 @@ import {
|
|
|
53
75
|
getNestedAgentDepthDeploymentPolicy,
|
|
54
76
|
getSessionByCreateIdempotencyKey,
|
|
55
77
|
getSessionCreationExecutionPolicy,
|
|
78
|
+
metadataWithAgentConfigCreateIdentity,
|
|
56
79
|
getVariableSet,
|
|
57
80
|
isCodexBilledModel,
|
|
58
81
|
initializeSessionStartAtomically,
|
|
59
82
|
materializeScheduledTaskReusableSessionFromRun,
|
|
60
|
-
listEnabledMcpCapabilityServerIds,
|
|
61
83
|
listInstalledApiIntegrationServerIdsForDelegations,
|
|
62
84
|
markScheduledTaskRunFailedIfQueued,
|
|
63
85
|
markScheduledTaskRunSkippedIfQueued,
|
|
@@ -112,6 +134,30 @@ type ScheduledTemporalActivityIdentity = {
|
|
|
112
134
|
activityId: string;
|
|
113
135
|
};
|
|
114
136
|
|
|
137
|
+
export function scheduledTaskRunExecutionPolicy(
|
|
138
|
+
policy: TurnExecutionPolicyV1,
|
|
139
|
+
input: DispatchScheduledTaskRunInput,
|
|
140
|
+
creatorRestriction?: "developer_setup",
|
|
141
|
+
): TurnExecutionPolicyV1 {
|
|
142
|
+
return creatorRestriction === "developer_setup" ||
|
|
143
|
+
(input.triggerType !== "scheduled" && input.credentialRestriction === "developer_setup")
|
|
144
|
+
? { ...policy, credentialRestriction: "developer_setup" }
|
|
145
|
+
: policy;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Only a creator ceiling is standing; a manual caller ceiling is per-run. */
|
|
149
|
+
export function scheduledSessionExecutionPolicyMetadata(
|
|
150
|
+
policy: unknown,
|
|
151
|
+
creatorRestriction?: "developer_setup",
|
|
152
|
+
): Record<string, unknown> {
|
|
153
|
+
if (policy === undefined || policy === null) return {};
|
|
154
|
+
const acceptedPolicy = TurnExecutionPolicyV1.parse(policy);
|
|
155
|
+
return creatorRestriction === "developer_setup" &&
|
|
156
|
+
acceptedPolicy.credentialRestriction === "developer_setup"
|
|
157
|
+
? metadataWithTurnExecutionPolicyV1({}, acceptedPolicy)
|
|
158
|
+
: {};
|
|
159
|
+
}
|
|
160
|
+
|
|
115
161
|
export function scheduledTaskRunProducerKey(
|
|
116
162
|
input: DispatchScheduledTaskRunInput,
|
|
117
163
|
suppliedActivityIdentity?: ScheduledTemporalActivityIdentity,
|
|
@@ -181,6 +227,15 @@ export function scheduledTaskGeneratedSessionCreateIdempotencyKey(producerKey: s
|
|
|
181
227
|
* alone, with no Intl call and so no host ICU or tzdata build to make the two
|
|
182
228
|
* texts differ.
|
|
183
229
|
*/
|
|
230
|
+
/** A scheduler-generated run session: a service-created root session. */
|
|
231
|
+
function recordScheduledSessionCreated(observability: ProductUsageMetricsSink | undefined): void {
|
|
232
|
+
recordSessionCreated(observability, {
|
|
233
|
+
surface: "scheduled",
|
|
234
|
+
createdByKind: "service",
|
|
235
|
+
parentSessionId: null,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
184
239
|
export function scheduledTaskSessionTitle(taskName: string): string {
|
|
185
240
|
return normalizeAutomaticSessionTitle(taskName) ?? "Scheduled run";
|
|
186
241
|
}
|
|
@@ -280,6 +335,9 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
280
335
|
producerKey: stableProducerKey,
|
|
281
336
|
});
|
|
282
337
|
if (priorRun?.actionKind === "agent_turn") {
|
|
338
|
+
if (priorRun.admissionDiagnostic || priorRun.admissionRefusal) {
|
|
339
|
+
return scheduledAdmissionRefusalResult(priorRun);
|
|
340
|
+
}
|
|
283
341
|
const acceptedExecution = await getScheduledTaskRunAcceptedExecution(db, {
|
|
284
342
|
workspaceId: input.workspaceId,
|
|
285
343
|
runId: priorRun.id,
|
|
@@ -294,6 +352,15 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
294
352
|
}
|
|
295
353
|
throw new Error("scheduled agent run is missing accepted execution truth");
|
|
296
354
|
}
|
|
355
|
+
if (priorRun.status === "queued" && isRetiredNativeAtlassianTask(acceptedExecution.task)) {
|
|
356
|
+
await markScheduledTaskRunFailedIfQueued(
|
|
357
|
+
db,
|
|
358
|
+
priorRun.workspaceId,
|
|
359
|
+
priorRun.id,
|
|
360
|
+
ATLASSIAN_NATIVE_RETIRED_REASON,
|
|
361
|
+
);
|
|
362
|
+
return scheduledRunTerminalResult(ATLASSIAN_NATIVE_RETIRED_REASON);
|
|
363
|
+
}
|
|
297
364
|
await recordScheduledTaskFiredUsage(db, acceptedExecution, priorRun);
|
|
298
365
|
if (priorRun.status === "dispatched") {
|
|
299
366
|
return await replayScheduledTaskDispatch({
|
|
@@ -317,6 +384,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
317
384
|
try {
|
|
318
385
|
return await recoverBoundScheduledTaskDispatch({
|
|
319
386
|
db,
|
|
387
|
+
observability: baseService.observability,
|
|
320
388
|
bus,
|
|
321
389
|
settings,
|
|
322
390
|
wakeSessionWorkflow,
|
|
@@ -361,6 +429,8 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
361
429
|
if (!task) {
|
|
362
430
|
return { action: "deleted" };
|
|
363
431
|
}
|
|
432
|
+
if (isRetiredNativeAtlassianTask(task))
|
|
433
|
+
return { action: "blocked", reason: ATLASSIAN_NATIVE_RETIRED_REASON };
|
|
364
434
|
if (task.action.kind !== "agent_turn") {
|
|
365
435
|
return { action: "blocked", reason: "legacy_source_schedule_requires_migration" };
|
|
366
436
|
}
|
|
@@ -391,20 +461,6 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
391
461
|
if (incidentDeclaration.action === "blocked") {
|
|
392
462
|
return incidentDeclaration;
|
|
393
463
|
}
|
|
394
|
-
const taskPersonalConnectionDelegations = await getScheduledTaskPersonalConnectionDelegations(
|
|
395
|
-
db,
|
|
396
|
-
task.workspaceId,
|
|
397
|
-
task.id,
|
|
398
|
-
);
|
|
399
|
-
const taskConnectionAuthoritySubjects = [
|
|
400
|
-
...new Set(
|
|
401
|
-
taskPersonalConnectionDelegations.map((delegation) => delegation.ownerSubjectId),
|
|
402
|
-
),
|
|
403
|
-
];
|
|
404
|
-
if (taskConnectionAuthoritySubjects.length > 1) {
|
|
405
|
-
throw new Error("scheduled connection authority has multiple causal humans");
|
|
406
|
-
}
|
|
407
|
-
const taskConnectionAuthoritySubjectId = taskConnectionAuthoritySubjects[0] ?? null;
|
|
408
464
|
const taskPersonalResourceAuthoritySubjectId =
|
|
409
465
|
await getScheduledTaskPersonalResourceAuthoritySubject(db, {
|
|
410
466
|
accountId: task.accountId,
|
|
@@ -418,17 +474,52 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
418
474
|
taskId: task.id,
|
|
419
475
|
taskAuthorityRevision: task.authorityRevision,
|
|
420
476
|
});
|
|
477
|
+
const taskAuthoritySubjectId = task.ownerSubjectId;
|
|
478
|
+
// Every pre-admission refusal below is recorded as a visible run receipt
|
|
479
|
+
// under this producer identity instead of throwing (a thrown activity is
|
|
480
|
+
// retried to exhaustion and leaves no run) or returning a bare blocked
|
|
481
|
+
// result (the occurrence silently disappears). Terminal refusals are
|
|
482
|
+
// deterministic for this task revision and digest; transient ones
|
|
483
|
+
// (`retryable`) are skipped and a later occurrence is admitted normally.
|
|
484
|
+
// Redelivery replays the same receipt, so no occurrence gets two runs.
|
|
485
|
+
const refuseAdmission = async (
|
|
486
|
+
reason: ScheduledTaskAdmissionRefusalReason,
|
|
487
|
+
retryable: boolean,
|
|
488
|
+
detail: string,
|
|
489
|
+
): Promise<DispatchScheduledTaskRunResult> => {
|
|
490
|
+
console.warn(
|
|
491
|
+
`[scheduled-task] refused occurrence of ${task.id} (revision ${task.authorityRevision}): ${reason}: ${detail}`,
|
|
492
|
+
);
|
|
493
|
+
const receipt = await recordScheduledTaskAdmissionRefusal(db, {
|
|
494
|
+
workspaceId: task.workspaceId,
|
|
495
|
+
taskId: task.id,
|
|
496
|
+
taskAuthorityRevision: task.authorityRevision,
|
|
497
|
+
taskExecutionDigest: task.executionDigest,
|
|
498
|
+
triggerType: input.triggerType,
|
|
499
|
+
producerKey: stableProducerKey,
|
|
500
|
+
reason,
|
|
501
|
+
retryable,
|
|
502
|
+
});
|
|
503
|
+
if (!receipt.admissionRefusal) {
|
|
504
|
+
// A concurrent delivery accepted this producer first. Follow the
|
|
505
|
+
// existing exact-receipt recovery path, never replace its outcome.
|
|
506
|
+
return createScheduledTaskActivities(services).dispatchScheduledTaskRun(input);
|
|
507
|
+
}
|
|
508
|
+
return scheduledAdmissionRefusalResult(receipt);
|
|
509
|
+
};
|
|
421
510
|
if (
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
511
|
+
task.action.kind === "agent_turn" &&
|
|
512
|
+
((taskRevisionAuthority?.subjectId ?? null) !== taskAuthoritySubjectId ||
|
|
513
|
+
[taskPersonalResourceAuthoritySubjectId].some(
|
|
514
|
+
(subject) => subject !== null && subject !== taskAuthoritySubjectId,
|
|
515
|
+
))
|
|
425
516
|
) {
|
|
426
|
-
|
|
517
|
+
return await refuseAdmission(
|
|
518
|
+
"scheduled_authority_unavailable",
|
|
519
|
+
false,
|
|
520
|
+
"scheduled authority differs from its immutable execution owner",
|
|
521
|
+
);
|
|
427
522
|
}
|
|
428
|
-
const taskAuthoritySubjectId =
|
|
429
|
-
taskRevisionAuthority?.subjectId ??
|
|
430
|
-
taskPersonalResourceAuthoritySubjectId ??
|
|
431
|
-
taskConnectionAuthoritySubjectId;
|
|
432
523
|
const acceptedTargetSessionId =
|
|
433
524
|
task.runMode === "existing_session"
|
|
434
525
|
? task.targetSessionId
|
|
@@ -450,29 +541,157 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
450
541
|
)
|
|
451
542
|
: null;
|
|
452
543
|
const settings = await settingsForTask(task, targetSessionExecutionBase?.model);
|
|
453
|
-
|
|
454
|
-
|
|
544
|
+
// A task that names no model resolves the new-chat default at each fresh
|
|
545
|
+
// occurrence (saved workspace default, then a usable connected
|
|
546
|
+
// subscription under the task's frozen SuperGrok authority, then the
|
|
547
|
+
// credits default while the organization holds a credit balance, then the
|
|
548
|
+
// deployment default). A frozen SuperGrok pool that is gone only means
|
|
549
|
+
// SuperGrok is not ready. The accepted execution freezes the result, so
|
|
550
|
+
// retries and recovery never resolve again. Existing-session runs keep
|
|
551
|
+
// that session's model.
|
|
552
|
+
const resolvedDefault =
|
|
553
|
+
task.agentConfig.model || targetSessionExecutionBase
|
|
554
|
+
? null
|
|
555
|
+
: await resolveScheduledTaskDefaultModel(db, settings, task);
|
|
556
|
+
const model = task.agentConfig.model ?? resolvedDefault?.model ?? settings.openaiModel;
|
|
557
|
+
const reasoningEffort =
|
|
558
|
+
task.agentConfig.reasoningEffort ??
|
|
559
|
+
resolvedDefault?.reasoningEffort ??
|
|
560
|
+
settings.openaiReasoningEffort;
|
|
455
561
|
let sandboxBackend = task.agentConfig.sandboxBackend ?? settings.sandboxBackend;
|
|
456
562
|
let sandboxOs: "linux" | "macos" | "windows" = "linux";
|
|
457
|
-
|
|
563
|
+
let taskTools = withFirstPartyTools(settings, task.agentConfig.tools);
|
|
458
564
|
// A task created by a live agent attempt froze its creator's effective
|
|
459
565
|
// first-party selection, permission set, and session access policy;
|
|
460
566
|
// its generated sessions inherit that boundary under today's
|
|
461
567
|
// deployment ceiling. A human/API-created task (null policy) keeps the
|
|
462
568
|
// deployment default exactly as before.
|
|
463
569
|
const creatorPolicy = await getScheduledTaskCreatorPolicy(db, task.workspaceId, task.id);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
570
|
+
// A person-chosen Slack channel adds only the two bot posting tools;
|
|
571
|
+
// they post nowhere else, whatever the creator's own selection was.
|
|
572
|
+
let firstPartyMcpTools = withScheduledSlackBotPostingTools(
|
|
573
|
+
creatorPolicy?.firstPartyMcpTools
|
|
574
|
+
? allowedFirstPartyMcpToolsForSession(settings, creatorPolicy.firstPartyMcpTools)
|
|
575
|
+
: resolveFirstPartyMcpToolPolicy(settings).default,
|
|
576
|
+
task.agentConfig,
|
|
577
|
+
resolveFirstPartyMcpToolPolicy(settings).allowed,
|
|
578
|
+
);
|
|
579
|
+
// Agent configuration for generated sessions (null = legacy). The
|
|
580
|
+
// scheduled baseline above (creator policy or deployment default) is
|
|
581
|
+
// what "all" reproduces; capabilities only narrow it. Frozen into the
|
|
582
|
+
// accepted execution so retries and recovery never resolve again.
|
|
583
|
+
let resolvedAgentConfig: ResolvedAgentConfig | null = null;
|
|
584
|
+
let resolvedAgentInstructions: string | undefined;
|
|
585
|
+
const generatedTarget =
|
|
586
|
+
task.runMode === "new_session_per_run" ||
|
|
587
|
+
(task.runMode === "reusable_session" && task.reusableSessionId === null);
|
|
588
|
+
if (generatedTarget) {
|
|
589
|
+
try {
|
|
590
|
+
const agentResolution = resolveSessionAgentConfigForCreate({
|
|
591
|
+
settings,
|
|
592
|
+
creator: "scheduled",
|
|
593
|
+
request: task.agentConfig.agent,
|
|
594
|
+
instructions: undefined,
|
|
595
|
+
workspaceSettings: (await requireWorkspace(db, task.workspaceId)).settings,
|
|
596
|
+
parent: null,
|
|
597
|
+
goal: task.agentConfig.goal !== undefined,
|
|
598
|
+
});
|
|
599
|
+
resolvedAgentConfig = agentResolution.config;
|
|
600
|
+
resolvedAgentInstructions = agentResolution.instructions;
|
|
601
|
+
const written = applySessionAgentConfigWriteThrough({
|
|
602
|
+
config: resolvedAgentConfig,
|
|
603
|
+
firstPartyMcpTools,
|
|
604
|
+
tools: taskTools,
|
|
605
|
+
toolPolicy: { mode: "explicit", inheritedFromSessionId: null },
|
|
606
|
+
productServerIds: task.agentConfig.tools.map((tool) => tool.id),
|
|
607
|
+
});
|
|
608
|
+
firstPartyMcpTools = written.firstPartyMcpTools;
|
|
609
|
+
taskTools = written.tools;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
const status =
|
|
612
|
+
error instanceof Error ? (error as Error & { status?: unknown }).status : undefined;
|
|
613
|
+
if (!(error instanceof Error) || status !== 422) throw error;
|
|
614
|
+
return await refuseAdmission(
|
|
615
|
+
"scheduled_authority_unavailable",
|
|
616
|
+
false,
|
|
617
|
+
`scheduled agent configuration is not admissible: ${error.message}`,
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
467
621
|
const firstPartyMcpPermissions = creatorPolicy?.firstPartyMcpPermissions
|
|
468
622
|
? [...creatorPolicy.firstPartyMcpPermissions]
|
|
469
623
|
: [...DEFAULT_FIRST_PARTY_MCP_PERMISSIONS];
|
|
624
|
+
// A fresh occurrence resolves the immutable owner's current accounts.
|
|
625
|
+
// Retry/recovery above uses the already accepted occurrence snapshot.
|
|
626
|
+
const connectionSettings = await settingsWithEnabledCapabilityMcpServers(
|
|
627
|
+
db,
|
|
628
|
+
task.workspaceId,
|
|
629
|
+
settings,
|
|
630
|
+
taskAuthoritySubjectId ? { subjectId: taskAuthoritySubjectId } : {},
|
|
631
|
+
);
|
|
632
|
+
const connectionTarget =
|
|
633
|
+
acceptedTargetSessionId && targetSessionExecutionBase
|
|
634
|
+
? await requireSession(db, task.workspaceId, acceptedTargetSessionId)
|
|
635
|
+
: null;
|
|
636
|
+
const connectionTools = await scheduledConnectionTools(
|
|
637
|
+
db,
|
|
638
|
+
task.workspaceId,
|
|
639
|
+
connectionSettings,
|
|
640
|
+
connectionTarget,
|
|
641
|
+
taskTools,
|
|
642
|
+
taskAuthoritySubjectId ?? undefined,
|
|
643
|
+
);
|
|
644
|
+
const taskConnections = await freezeConnectionAccounts({
|
|
645
|
+
db,
|
|
646
|
+
accountId: task.accountId,
|
|
647
|
+
workspaceId: task.workspaceId,
|
|
648
|
+
settings: connectionTarget
|
|
649
|
+
? settingsWithSessionMcpServerMetadata(connectionSettings, connectionTarget.mcpServers)
|
|
650
|
+
: connectionSettings,
|
|
651
|
+
tools: connectionTools,
|
|
652
|
+
resources: mergeResourceRefs(connectionTarget?.resources ?? [], task.agentConfig.resources),
|
|
653
|
+
source: taskAuthoritySubjectId
|
|
654
|
+
? { kind: "subject", subjectId: taskAuthoritySubjectId, accountId: task.accountId }
|
|
655
|
+
: { kind: "none" },
|
|
656
|
+
authoritySelections: task.agentConfig.connectionAccounts ?? [],
|
|
657
|
+
authoritySelectionsFrozen: task.agentConfig.connectionAccountsFrozen === true,
|
|
658
|
+
...scheduledConnectionSurfaceEligibility(
|
|
659
|
+
settings,
|
|
660
|
+
connectionTarget ?? {
|
|
661
|
+
firstPartyMcpTools,
|
|
662
|
+
firstPartyMcpPermissions,
|
|
663
|
+
},
|
|
664
|
+
),
|
|
665
|
+
}).catch((error: unknown) => {
|
|
666
|
+
if (error instanceof ConnectionAccountSelectionError) return error;
|
|
667
|
+
throw error;
|
|
668
|
+
});
|
|
669
|
+
if (taskConnections instanceof ConnectionAccountSelectionError) {
|
|
670
|
+
const receipt = await recordScheduledTaskAdmissionFailure(db, {
|
|
671
|
+
workspaceId: task.workspaceId,
|
|
672
|
+
taskId: task.id,
|
|
673
|
+
taskAuthorityRevision: task.authorityRevision,
|
|
674
|
+
taskExecutionDigest: task.executionDigest,
|
|
675
|
+
triggerType: input.triggerType,
|
|
676
|
+
producerKey: stableProducerKey,
|
|
677
|
+
diagnostic: taskConnections.diagnostic,
|
|
678
|
+
});
|
|
679
|
+
if (!receipt.admissionDiagnostic) {
|
|
680
|
+
// A concurrent delivery accepted this producer first. Follow the
|
|
681
|
+
// existing exact-receipt recovery path, never replace its outcome.
|
|
682
|
+
return createScheduledTaskActivities(services).dispatchScheduledTaskRun(input);
|
|
683
|
+
}
|
|
684
|
+
return scheduledAdmissionRefusalResult(receipt);
|
|
685
|
+
}
|
|
686
|
+
const {
|
|
687
|
+
personalConnectionDelegations: taskPersonalConnectionDelegations,
|
|
688
|
+
mcpAccountBindings: taskMcpAccountBindings,
|
|
689
|
+
} = taskConnections;
|
|
690
|
+
const taskConnectionAuthoritySubjectId =
|
|
691
|
+
taskPersonalConnectionDelegations.length > 0 ? taskAuthoritySubjectId : null;
|
|
470
692
|
const creatorSessionPolicy = scheduledCreatorSessionPolicyInput(
|
|
471
693
|
creatorPolicy?.sessionPolicy ?? null,
|
|
472
694
|
);
|
|
473
|
-
const generatedTarget =
|
|
474
|
-
task.runMode === "new_session_per_run" ||
|
|
475
|
-
(task.runMode === "reusable_session" && task.reusableSessionId === null);
|
|
476
695
|
if (generatedTarget && task.agentConfig.machineTarget) {
|
|
477
696
|
const access = {
|
|
478
697
|
accountId: task.accountId,
|
|
@@ -490,16 +709,37 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
490
709
|
!machine.enrollmentId ||
|
|
491
710
|
machine.scope === "user"
|
|
492
711
|
) {
|
|
493
|
-
|
|
712
|
+
return await refuseAdmission(
|
|
713
|
+
"machine_target_unavailable",
|
|
714
|
+
false,
|
|
715
|
+
"scheduled Connected Machine target is unavailable",
|
|
716
|
+
);
|
|
494
717
|
}
|
|
495
718
|
const enrollment = await getEnrollment(db, access, machine.enrollmentId);
|
|
496
|
-
if (!enrollment
|
|
497
|
-
|
|
719
|
+
if (!enrollment) {
|
|
720
|
+
return await refuseAdmission(
|
|
721
|
+
"machine_target_unavailable",
|
|
722
|
+
false,
|
|
723
|
+
"scheduled Connected Machine enrollment is gone",
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
if (enrollment.status !== "active") {
|
|
727
|
+
// A paused/suspended enrollment can be re-activated; skip this
|
|
728
|
+
// occurrence rather than failing the schedule.
|
|
729
|
+
return await refuseAdmission(
|
|
730
|
+
"machine_enrollment_inactive",
|
|
731
|
+
true,
|
|
732
|
+
`scheduled Connected Machine enrollment is ${enrollment.status}`,
|
|
733
|
+
);
|
|
498
734
|
}
|
|
499
735
|
sandboxBackend = "selfhosted";
|
|
500
736
|
sandboxOs = enrollment.os;
|
|
501
737
|
} else if (generatedTarget && sandboxBackend === "selfhosted") {
|
|
502
|
-
|
|
738
|
+
return await refuseAdmission(
|
|
739
|
+
"machine_target_unavailable",
|
|
740
|
+
false,
|
|
741
|
+
"self-hosted scheduled task has no Connected Machine target",
|
|
742
|
+
);
|
|
503
743
|
}
|
|
504
744
|
const generatedSessionDepthPolicy = generatedTarget
|
|
505
745
|
? await (async () => {
|
|
@@ -537,20 +777,16 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
537
777
|
: null;
|
|
538
778
|
const targetSessionExecution = targetSessionExecutionBase
|
|
539
779
|
? await (async () => {
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
listInstalledApiIntegrationServerIdsForDelegations(
|
|
780
|
+
const apiIntegrationServerIds =
|
|
781
|
+
await listInstalledApiIntegrationServerIdsForDelegations(
|
|
543
782
|
db,
|
|
544
783
|
task.workspaceId,
|
|
545
784
|
taskPersonalConnectionDelegations,
|
|
546
|
-
)
|
|
785
|
+
);
|
|
786
|
+
const availableMcpServerIds = new Set([
|
|
787
|
+
...connectionSettings.mcpServers.map((server) => server.id),
|
|
788
|
+
...apiIntegrationServerIds,
|
|
547
789
|
]);
|
|
548
|
-
const workspaceDefaultMcpServerIds = new Set(
|
|
549
|
-
settings.mcpServers.map((server) => server.id),
|
|
550
|
-
);
|
|
551
|
-
for (const id of capabilityServerIds) workspaceDefaultMcpServerIds.add(id);
|
|
552
|
-
for (const id of apiIntegrationServerIds) workspaceDefaultMcpServerIds.add(id);
|
|
553
|
-
const availableMcpServerIds = new Set(workspaceDefaultMcpServerIds);
|
|
554
790
|
for (const id of targetSessionExecutionBase.mcpServerIds) {
|
|
555
791
|
availableMcpServerIds.add(id);
|
|
556
792
|
}
|
|
@@ -558,9 +794,10 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
558
794
|
toolPolicy: targetSessionExecutionBase.toolPolicy,
|
|
559
795
|
sessionTools: targetSessionExecutionBase.tools,
|
|
560
796
|
availableMcpServerIds,
|
|
561
|
-
defaultMcpServerIds:
|
|
562
|
-
|
|
563
|
-
|
|
797
|
+
defaultMcpServerIds: [
|
|
798
|
+
...connectionTools.map((tool) => tool.id),
|
|
799
|
+
...apiIntegrationServerIds,
|
|
800
|
+
],
|
|
564
801
|
});
|
|
565
802
|
return {
|
|
566
803
|
...targetSessionExecutionBase,
|
|
@@ -589,7 +826,11 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
589
826
|
)
|
|
590
827
|
: null;
|
|
591
828
|
if (generatedTarget && task.variableSetId && !acceptedVariableSet) {
|
|
592
|
-
|
|
829
|
+
return await refuseAdmission(
|
|
830
|
+
"variable_set_unavailable",
|
|
831
|
+
false,
|
|
832
|
+
`variable set not found: ${task.variableSetId}`,
|
|
833
|
+
);
|
|
593
834
|
}
|
|
594
835
|
const acceptedRig =
|
|
595
836
|
generatedTarget && task.rigId
|
|
@@ -604,12 +845,17 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
604
845
|
)
|
|
605
846
|
: null;
|
|
606
847
|
if (generatedTarget && task.rigId && (!acceptedRig || !acceptedRig.activeVersion)) {
|
|
607
|
-
|
|
848
|
+
return await refuseAdmission(
|
|
849
|
+
"rig_version_unavailable",
|
|
850
|
+
false,
|
|
851
|
+
`sandbox environment has no active version to bind: ${task.rigId}`,
|
|
852
|
+
);
|
|
608
853
|
}
|
|
609
|
-
const
|
|
854
|
+
const acceptedRigDefaultVariableSetRows = acceptedRig?.activeVersion
|
|
610
855
|
? await Promise.all(
|
|
611
|
-
acceptedRig.activeVersion.defaultVariableSetIds.map(async (variableSetId) => {
|
|
612
|
-
|
|
856
|
+
acceptedRig.activeVersion.defaultVariableSetIds.map(async (variableSetId) => ({
|
|
857
|
+
variableSetId,
|
|
858
|
+
variableSet: await getVariableSet(
|
|
613
859
|
db,
|
|
614
860
|
{
|
|
615
861
|
accountId: task.accountId,
|
|
@@ -617,14 +863,23 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
617
863
|
subjectId: taskAuthoritySubjectId ?? task.createdBy.subjectId,
|
|
618
864
|
},
|
|
619
865
|
variableSetId,
|
|
620
|
-
)
|
|
621
|
-
|
|
622
|
-
throw new Error(`rig default Variable Set not found: ${variableSetId}`);
|
|
623
|
-
}
|
|
624
|
-
return { id: variableSet.id, generation: variableSet.generation };
|
|
625
|
-
}),
|
|
866
|
+
),
|
|
867
|
+
})),
|
|
626
868
|
)
|
|
627
869
|
: [];
|
|
870
|
+
const missingRigDefaultVariableSet = acceptedRigDefaultVariableSetRows.find(
|
|
871
|
+
(row) => !row.variableSet,
|
|
872
|
+
);
|
|
873
|
+
if (missingRigDefaultVariableSet) {
|
|
874
|
+
return await refuseAdmission(
|
|
875
|
+
"variable_set_unavailable",
|
|
876
|
+
false,
|
|
877
|
+
`sandbox environment default Variable Set not found: ${missingRigDefaultVariableSet.variableSetId}`,
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
const acceptedRigDefaultVariableSets = acceptedRigDefaultVariableSetRows.map(
|
|
881
|
+
({ variableSet }) => ({ id: variableSet!.id, generation: variableSet!.generation }),
|
|
882
|
+
);
|
|
628
883
|
let incidentPreflightRequired = incidentDeclaration.action === "required";
|
|
629
884
|
if (incidentPreflightRequired) {
|
|
630
885
|
const existingSessionId =
|
|
@@ -688,6 +943,8 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
688
943
|
}
|
|
689
944
|
const taskXaiProviderAccountAuthoritySnapshot =
|
|
690
945
|
await getScheduledTaskXaiProviderAccountAuthoritySnapshot(db, task.workspaceId, task.id);
|
|
946
|
+
const taskClaudeProviderAccountAuthoritySnapshot =
|
|
947
|
+
await getScheduledTaskClaudeProviderAccountAuthoritySnapshot(db, task.workspaceId, task.id);
|
|
691
948
|
// A scheduled bot selection was authorized when the task was written,
|
|
692
949
|
// but connection status and tenant/role binding are mutable. Revalidate
|
|
693
950
|
// before any session/model cost and never fall back to a personal Slack
|
|
@@ -703,7 +960,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
703
960
|
? openGeniSlackBotMetadata(slackBotConnection.metadata)
|
|
704
961
|
: null;
|
|
705
962
|
if (slackBotConnection && !slackBotMetadata) {
|
|
706
|
-
throw new Error("
|
|
963
|
+
throw new Error("Opengeni Slack bot connection metadata is invalid");
|
|
707
964
|
}
|
|
708
965
|
const xaiAuthoritySubjectId =
|
|
709
966
|
taskXaiProviderAccountAuthoritySnapshot.scope === "user" &&
|
|
@@ -711,21 +968,67 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
711
968
|
? task.createdBy.subjectId
|
|
712
969
|
: null;
|
|
713
970
|
if (taskXaiProviderAccountAuthoritySnapshot.scope === "user" && !xaiAuthoritySubjectId) {
|
|
714
|
-
|
|
971
|
+
return await refuseAdmission(
|
|
972
|
+
"scheduled_authority_unavailable",
|
|
973
|
+
false,
|
|
974
|
+
"scheduled user-scoped xAI authority has no causal human",
|
|
975
|
+
);
|
|
715
976
|
}
|
|
716
977
|
if (
|
|
717
978
|
xaiAuthoritySubjectId &&
|
|
718
979
|
taskAuthoritySubjectId &&
|
|
719
980
|
xaiAuthoritySubjectId !== taskAuthoritySubjectId
|
|
720
981
|
) {
|
|
721
|
-
|
|
982
|
+
return await refuseAdmission(
|
|
983
|
+
"scheduled_authority_unavailable",
|
|
984
|
+
false,
|
|
985
|
+
"scheduled authority classes have different causal humans",
|
|
986
|
+
);
|
|
722
987
|
}
|
|
723
|
-
const
|
|
988
|
+
const claudeAuthoritySubjectId =
|
|
989
|
+
taskClaudeProviderAccountAuthoritySnapshot.scope === "user" && task.ownerSubjectId
|
|
990
|
+
? task.ownerSubjectId
|
|
991
|
+
: null;
|
|
992
|
+
if (
|
|
993
|
+
taskClaudeProviderAccountAuthoritySnapshot.scope === "user" &&
|
|
994
|
+
!claudeAuthoritySubjectId
|
|
995
|
+
) {
|
|
996
|
+
return await refuseAdmission(
|
|
997
|
+
"scheduled_authority_unavailable",
|
|
998
|
+
false,
|
|
999
|
+
"scheduled user-scoped Claude authority has no causal human",
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
if (
|
|
1003
|
+
claudeAuthoritySubjectId &&
|
|
1004
|
+
taskAuthoritySubjectId &&
|
|
1005
|
+
claudeAuthoritySubjectId !== taskAuthoritySubjectId
|
|
1006
|
+
) {
|
|
1007
|
+
return await refuseAdmission(
|
|
1008
|
+
"scheduled_authority_unavailable",
|
|
1009
|
+
false,
|
|
1010
|
+
"scheduled authority classes have different causal humans",
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
const causalHumanSubjectId =
|
|
1014
|
+
taskAuthoritySubjectId ?? xaiAuthoritySubjectId ?? claudeAuthoritySubjectId;
|
|
1015
|
+
if (
|
|
1016
|
+
xaiAuthoritySubjectId &&
|
|
1017
|
+
claudeAuthoritySubjectId &&
|
|
1018
|
+
xaiAuthoritySubjectId !== claudeAuthoritySubjectId
|
|
1019
|
+
)
|
|
1020
|
+
return await refuseAdmission(
|
|
1021
|
+
"scheduled_authority_unavailable",
|
|
1022
|
+
false,
|
|
1023
|
+
"scheduled subscription pools have different causal humans",
|
|
1024
|
+
);
|
|
724
1025
|
if (
|
|
725
1026
|
task.agentConfig.knowledgeSource &&
|
|
726
1027
|
causalHumanSubjectId !== task.agentConfig.knowledgeSource.initiatingSubjectId
|
|
727
1028
|
) {
|
|
728
|
-
|
|
1029
|
+
return await refuseAdmission(
|
|
1030
|
+
"scheduled_authority_unavailable",
|
|
1031
|
+
false,
|
|
729
1032
|
"Source schedule requires its connection owner's current human authorization; update the source schedule to authorize it",
|
|
730
1033
|
);
|
|
731
1034
|
}
|
|
@@ -737,7 +1040,11 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
737
1040
|
(acceptedVariableSet?.scope === "user" || acceptedRig?.scope === "user") &&
|
|
738
1041
|
!causalHumanSubjectId
|
|
739
1042
|
) {
|
|
740
|
-
|
|
1043
|
+
return await refuseAdmission(
|
|
1044
|
+
"scheduled_authority_unavailable",
|
|
1045
|
+
false,
|
|
1046
|
+
"scheduled personal-resource execution has no causal human",
|
|
1047
|
+
);
|
|
741
1048
|
}
|
|
742
1049
|
const admissionDenial = await agentRunAdmissionDenial(
|
|
743
1050
|
{ ...baseService, settings },
|
|
@@ -746,10 +1053,13 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
746
1053
|
workspaceId: task.workspaceId,
|
|
747
1054
|
model: targetSessionExecution?.model ?? model,
|
|
748
1055
|
requestedAgentRuns: input.agentRunUsageIdempotencyKey ? 0 : 1,
|
|
1056
|
+
initiatingHumanSubjectId: causalHumanSubjectId,
|
|
749
1057
|
},
|
|
750
1058
|
);
|
|
751
1059
|
if (admissionDenial) {
|
|
752
|
-
|
|
1060
|
+
// Credits and monthly limits clear on their own (top-up, new period):
|
|
1061
|
+
// skip this occurrence visibly; a later one is admitted normally.
|
|
1062
|
+
return await refuseAdmission(admissionDenial, true, "agent run admission denied");
|
|
753
1063
|
}
|
|
754
1064
|
const acceptedModel = targetSessionExecution?.model ?? model;
|
|
755
1065
|
const acceptedReasoningEffort = targetSessionExecution?.reasoningEffort ?? reasoningEffort;
|
|
@@ -772,23 +1082,28 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
772
1082
|
}
|
|
773
1083
|
}
|
|
774
1084
|
: undefined;
|
|
775
|
-
const turnExecutionPolicy
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1085
|
+
const turnExecutionPolicy = scheduledTaskRunExecutionPolicy(
|
|
1086
|
+
resolveTurnExecutionPolicyV1(settings, {
|
|
1087
|
+
modelId: acceptedModel,
|
|
1088
|
+
requestedModelId:
|
|
1089
|
+
generatedTarget && task.agentConfig.model ? task.agentConfig.model : null,
|
|
1090
|
+
modelSource: generatedTarget
|
|
1091
|
+
? task.agentConfig.model
|
|
1092
|
+
? "explicit"
|
|
1093
|
+
: "deployment"
|
|
1094
|
+
: "session",
|
|
1095
|
+
reasoningEffort: acceptedReasoningEffort,
|
|
1096
|
+
reasoningSource: generatedTarget
|
|
1097
|
+
? task.agentConfig.reasoningEffort
|
|
1098
|
+
? "explicit"
|
|
1099
|
+
: "deployment"
|
|
1100
|
+
: "session",
|
|
1101
|
+
latencyMode: acceptedLatencyMode,
|
|
1102
|
+
latencyModeSource: generatedTarget ? "deployment" : "session",
|
|
1103
|
+
}),
|
|
1104
|
+
input,
|
|
1105
|
+
creatorPolicy?.credentialRestriction,
|
|
1106
|
+
);
|
|
792
1107
|
const deferredEvents: Array<{
|
|
793
1108
|
sessionId: string;
|
|
794
1109
|
events: Awaited<ReturnType<typeof appendSessionEvents>>;
|
|
@@ -821,6 +1136,12 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
821
1136
|
resolvedTools: taskTools,
|
|
822
1137
|
resolvedFirstPartyMcpTools: firstPartyMcpTools,
|
|
823
1138
|
resolvedFirstPartyMcpPermissions: firstPartyMcpPermissions,
|
|
1139
|
+
...(resolvedAgentConfig
|
|
1140
|
+
? {
|
|
1141
|
+
resolvedAgentConfig,
|
|
1142
|
+
...(resolvedAgentInstructions !== undefined ? { resolvedAgentInstructions } : {}),
|
|
1143
|
+
}
|
|
1144
|
+
: {}),
|
|
824
1145
|
resolvedVariableSet: acceptedVariableSet
|
|
825
1146
|
? { id: acceptedVariableSet.id, generation: acceptedVariableSet.generation }
|
|
826
1147
|
: null,
|
|
@@ -843,11 +1164,14 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
843
1164
|
targetSessionExecution,
|
|
844
1165
|
generatedSessionBinding,
|
|
845
1166
|
personalConnectionDelegations: taskPersonalConnectionDelegations,
|
|
1167
|
+
mcpAccountBindings: taskMcpAccountBindings,
|
|
846
1168
|
personalResourceAuthoritySubjectId: taskPersonalResourceAuthoritySubjectId,
|
|
847
1169
|
causalHumanSubjectId,
|
|
848
1170
|
causalHumanAuthority: taskRevisionAuthority,
|
|
849
1171
|
xaiProviderAccountAuthoritySnapshot: taskXaiProviderAccountAuthoritySnapshot,
|
|
1172
|
+
claudeProviderAccountAuthoritySnapshot: taskClaudeProviderAccountAuthoritySnapshot,
|
|
850
1173
|
xaiAuthoritySubjectId,
|
|
1174
|
+
claudeAuthoritySubjectId,
|
|
851
1175
|
connectionAuthoritySubjectId: taskConnectionAuthoritySubjectId,
|
|
852
1176
|
triggerInitiator: input.initiator ?? { kind: "service", subjectId: "scheduler" },
|
|
853
1177
|
agentRunUsageIdempotencyKey: input.agentRunUsageIdempotencyKey ?? null,
|
|
@@ -966,16 +1290,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
966
1290
|
taskId: task.id,
|
|
967
1291
|
},
|
|
968
1292
|
);
|
|
969
|
-
if (
|
|
970
|
-
stableJson({
|
|
971
|
-
task: exactAuthority.task,
|
|
972
|
-
personalConnectionDelegations: exactAuthority.personalConnectionDelegations,
|
|
973
|
-
}) !==
|
|
974
|
-
stableJson({
|
|
975
|
-
task,
|
|
976
|
-
personalConnectionDelegations: taskPersonalConnectionDelegations,
|
|
977
|
-
})
|
|
978
|
-
) {
|
|
1293
|
+
if (stableJson(exactAuthority) !== stableJson(task)) {
|
|
979
1294
|
throw new IncidentTelemetryPreflightBlockedError(
|
|
980
1295
|
"incident_preflight_metadata_missing",
|
|
981
1296
|
);
|
|
@@ -1009,7 +1324,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1009
1324
|
if (task.rigId) {
|
|
1010
1325
|
const rig = acceptedRig;
|
|
1011
1326
|
if (!rig || !rig.activeVersion) {
|
|
1012
|
-
throw new Error(`
|
|
1327
|
+
throw new Error(`sandbox environment has no active version to bind: ${task.rigId}`);
|
|
1013
1328
|
}
|
|
1014
1329
|
frozenRigId = rig.id;
|
|
1015
1330
|
frozenRigVersionId =
|
|
@@ -1017,7 +1332,9 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1017
1332
|
(resource) => resource.resourceKind === "rig" && resource.resourceId === rig.id,
|
|
1018
1333
|
)?.resourceVersionId ?? rig.activeVersion.id;
|
|
1019
1334
|
if (frozenRigVersionId !== rig.activeVersion.id) {
|
|
1020
|
-
throw new Error(
|
|
1335
|
+
throw new Error(
|
|
1336
|
+
"scheduled run sandbox environment version changed during admission",
|
|
1337
|
+
);
|
|
1021
1338
|
}
|
|
1022
1339
|
}
|
|
1023
1340
|
let session: Awaited<ReturnType<typeof createSession>>;
|
|
@@ -1034,6 +1351,10 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1034
1351
|
tools: taskTools,
|
|
1035
1352
|
firstPartyMcpTools,
|
|
1036
1353
|
firstPartyMcpPermissions,
|
|
1354
|
+
...(resolvedAgentConfig ? { agentConfig: resolvedAgentConfig } : {}),
|
|
1355
|
+
...(resolvedAgentInstructions !== undefined
|
|
1356
|
+
? { instructions: resolvedAgentInstructions }
|
|
1357
|
+
: {}),
|
|
1037
1358
|
...creatorSessionPolicy,
|
|
1038
1359
|
...(task.agentConfig.knowledgeSource?.destination.kind === "personal"
|
|
1039
1360
|
? {
|
|
@@ -1043,6 +1364,10 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1043
1364
|
: {}),
|
|
1044
1365
|
metadata: {
|
|
1045
1366
|
...taskMetadata,
|
|
1367
|
+
...scheduledSessionExecutionPolicyMetadata(
|
|
1368
|
+
turnExecutionPolicy,
|
|
1369
|
+
creatorPolicy?.credentialRestriction,
|
|
1370
|
+
),
|
|
1046
1371
|
model,
|
|
1047
1372
|
reasoningEffort,
|
|
1048
1373
|
scheduledTaskId: task.id,
|
|
@@ -1074,6 +1399,8 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1074
1399
|
rigVersionId: frozenRigVersionId,
|
|
1075
1400
|
personalConnectionDelegations: [],
|
|
1076
1401
|
initialXaiProviderAccountAuthoritySnapshot: taskXaiProviderAccountAuthoritySnapshot,
|
|
1402
|
+
initialClaudeProviderAccountAuthoritySnapshot:
|
|
1403
|
+
taskClaudeProviderAccountAuthoritySnapshot,
|
|
1077
1404
|
maxNestedAgentDepthOverride: task.agentConfig.maxNestedAgentDepth ?? null,
|
|
1078
1405
|
frozenNestedAgentDepthPolicy: {
|
|
1079
1406
|
effectiveMaxNestedAgentDepth:
|
|
@@ -1138,6 +1465,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1138
1465
|
}
|
|
1139
1466
|
session = created.session;
|
|
1140
1467
|
sessionCreated = created.created;
|
|
1468
|
+
if (sessionCreated) recordScheduledSessionCreated(baseService.observability);
|
|
1141
1469
|
if (!sessionCreated) {
|
|
1142
1470
|
await bindScheduledTaskRunSessionInTransaction(dispatchDb, {
|
|
1143
1471
|
accountId: task.accountId,
|
|
@@ -1171,7 +1499,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1171
1499
|
(task.agentConfig.slackBotConnectionId ?? null)
|
|
1172
1500
|
) {
|
|
1173
1501
|
throw new Error(
|
|
1174
|
-
"scheduled alert occurrence
|
|
1502
|
+
"scheduled alert occurrence Opengeni Slack bot binding does not match its canonical session",
|
|
1175
1503
|
);
|
|
1176
1504
|
}
|
|
1177
1505
|
}
|
|
@@ -1366,9 +1694,12 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1366
1694
|
task.createdBy.kind === "subject"
|
|
1367
1695
|
? { xaiAuthoritySubjectId: task.createdBy.subjectId }
|
|
1368
1696
|
: {}),
|
|
1697
|
+
...(claudeAuthoritySubjectId ? { claudeAuthoritySubjectId } : {}),
|
|
1369
1698
|
},
|
|
1370
1699
|
personalConnectionDelegations: taskPersonalConnectionDelegations,
|
|
1700
|
+
mcpAccountBindings: taskMcpAccountBindings,
|
|
1371
1701
|
xaiProviderAccountAuthoritySnapshot: taskXaiProviderAccountAuthoritySnapshot,
|
|
1702
|
+
claudeProviderAccountAuthoritySnapshot: taskClaudeProviderAccountAuthoritySnapshot,
|
|
1372
1703
|
scheduledTaskRunId: run.id,
|
|
1373
1704
|
},
|
|
1374
1705
|
async (tx, wakeEventId, _updateId, rejectionReason) => {
|
|
@@ -1421,6 +1752,9 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1421
1752
|
run: { ...run, status: "skipped" as const, error },
|
|
1422
1753
|
};
|
|
1423
1754
|
}
|
|
1755
|
+
if (scheduledUpdate.added) {
|
|
1756
|
+
recordUserMessageAccepted(baseService.observability, { surface: "scheduled" });
|
|
1757
|
+
}
|
|
1424
1758
|
if (scheduledUpdate.added && scheduledUpdate.events.length > 0) {
|
|
1425
1759
|
if (deferPublications) {
|
|
1426
1760
|
deferredEvents.push({
|
|
@@ -1460,9 +1794,8 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1460
1794
|
// the locked admission check below remains authoritative. Mirrors
|
|
1461
1795
|
// apps/api/src/domain/sessions.ts.
|
|
1462
1796
|
assertReusableSessionRevivable(session.status);
|
|
1463
|
-
//
|
|
1464
|
-
//
|
|
1465
|
-
// fail the run instead of silently running with the wrong secrets.
|
|
1797
|
+
// Slack routing remains bound to the reusable chat; execution
|
|
1798
|
+
// attachments come from its accepted target snapshot.
|
|
1466
1799
|
assertReusableSessionBindingMatches(session, task);
|
|
1467
1800
|
const bundled = await addSessionSystemUpdateWithSourceMutation(
|
|
1468
1801
|
dispatchDb,
|
|
@@ -1493,9 +1826,12 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1493
1826
|
task.createdBy.kind === "subject"
|
|
1494
1827
|
? { xaiAuthoritySubjectId: task.createdBy.subjectId }
|
|
1495
1828
|
: {}),
|
|
1829
|
+
...(claudeAuthoritySubjectId ? { claudeAuthoritySubjectId } : {}),
|
|
1496
1830
|
},
|
|
1497
1831
|
personalConnectionDelegations: taskPersonalConnectionDelegations,
|
|
1832
|
+
mcpAccountBindings: taskMcpAccountBindings,
|
|
1498
1833
|
xaiProviderAccountAuthoritySnapshot: taskXaiProviderAccountAuthoritySnapshot,
|
|
1834
|
+
claudeProviderAccountAuthoritySnapshot: taskClaudeProviderAccountAuthoritySnapshot,
|
|
1499
1835
|
scheduledTaskRunId: run.id,
|
|
1500
1836
|
},
|
|
1501
1837
|
async (tx, wakeEventId, _updateId, rejectionReason) => {
|
|
@@ -1563,6 +1899,9 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
|
|
|
1563
1899
|
run: { ...run, status: "skipped" as const, error },
|
|
1564
1900
|
};
|
|
1565
1901
|
}
|
|
1902
|
+
if (bundled.added) {
|
|
1903
|
+
recordUserMessageAccepted(baseService.observability, { surface: "scheduled" });
|
|
1904
|
+
}
|
|
1566
1905
|
if (bundled.added && bundled.events.length > 0) {
|
|
1567
1906
|
if (deferPublications) {
|
|
1568
1907
|
deferredEvents.push({
|
|
@@ -1687,28 +2026,24 @@ class IncidentTelemetryPreflightBlockedError extends Error {
|
|
|
1687
2026
|
}
|
|
1688
2027
|
|
|
1689
2028
|
/**
|
|
1690
|
-
* Defensive backstop for the API-level
|
|
1691
|
-
*
|
|
1692
|
-
*
|
|
1693
|
-
* the wrong secrets - on the first attempt and on every recovery attempt.
|
|
2029
|
+
* Defensive backstop for the API-level Slack binding guard. Variable Sets
|
|
2030
|
+
* belong to the live target and are fenced by its accepted execution snapshot,
|
|
2031
|
+
* not by the task's retained creation defaults.
|
|
1694
2032
|
*/
|
|
1695
2033
|
function assertReusableSessionBindingMatches(
|
|
1696
|
-
session: {
|
|
1697
|
-
task: Pick<ScheduledTask, "
|
|
2034
|
+
session: { metadata: Record<string, unknown> },
|
|
2035
|
+
task: Pick<ScheduledTask, "runMode" | "agentConfig">,
|
|
1698
2036
|
): void {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
"scheduled task variableSet attachment does not match its reusable session",
|
|
1703
|
-
);
|
|
1704
|
-
}
|
|
2037
|
+
// Existing-chat messages use the target policy frozen at admission. Task
|
|
2038
|
+
// creation defaults are not an additional authority or binding constraint.
|
|
2039
|
+
if (task.runMode === "existing_session") return;
|
|
1705
2040
|
if (
|
|
1706
2041
|
scheduledSlackBotConnectionId(session.metadata) !==
|
|
1707
2042
|
(task.agentConfig.slackBotConnectionId ?? null)
|
|
1708
2043
|
) {
|
|
1709
2044
|
throw new ScheduledRunTerminalAuthorityError(
|
|
1710
2045
|
"scheduled_reusable_binding_changed",
|
|
1711
|
-
"scheduled task
|
|
2046
|
+
"scheduled task Opengeni Slack bot binding does not match its reusable session",
|
|
1712
2047
|
);
|
|
1713
2048
|
}
|
|
1714
2049
|
}
|
|
@@ -1766,9 +2101,31 @@ function scheduledRunRecoveryTerminalError(
|
|
|
1766
2101
|
return null;
|
|
1767
2102
|
}
|
|
1768
2103
|
|
|
2104
|
+
/** The blocked result of a diagnostic (refused) run receipt, fresh or replayed. */
|
|
2105
|
+
function scheduledAdmissionRefusalResult(
|
|
2106
|
+
run: Pick<ScheduledTaskRun, "id" | "admissionDiagnostic" | "admissionRefusal">,
|
|
2107
|
+
): Extract<DispatchScheduledTaskRunResult, { action: "blocked" }> {
|
|
2108
|
+
if (run.admissionRefusal) {
|
|
2109
|
+
return {
|
|
2110
|
+
action: "blocked",
|
|
2111
|
+
reason: run.admissionRefusal.reason as ScheduledTaskAdmissionRefusalReason,
|
|
2112
|
+
runId: run.id,
|
|
2113
|
+
refusal: run.admissionRefusal,
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
return {
|
|
2117
|
+
action: "blocked",
|
|
2118
|
+
reason: "connection_account_unavailable",
|
|
2119
|
+
runId: run.id,
|
|
2120
|
+
...(run.admissionDiagnostic ? { diagnostic: run.admissionDiagnostic } : {}),
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
|
|
1769
2124
|
function scheduledRunTerminalResult(
|
|
1770
2125
|
error: string | null,
|
|
1771
2126
|
): Extract<DispatchScheduledTaskRunResult, { action: "blocked" }> {
|
|
2127
|
+
if (error === ATLASSIAN_NATIVE_RETIRED_REASON)
|
|
2128
|
+
return { action: "blocked", reason: ATLASSIAN_NATIVE_RETIRED_REASON };
|
|
1772
2129
|
if (error === "scheduled_authority_exhausted") {
|
|
1773
2130
|
return { action: "blocked", reason: "scheduled_authority_exhausted" };
|
|
1774
2131
|
}
|
|
@@ -1799,18 +2156,10 @@ async function prepareIncidentTelemetrySource(input: {
|
|
|
1799
2156
|
workspaceId: string;
|
|
1800
2157
|
sessionId: string;
|
|
1801
2158
|
alertOccurrenceLabels: Readonly<Record<string, string>> | null;
|
|
1802
|
-
acceptedExecution
|
|
2159
|
+
acceptedExecution: ScheduledTaskRunAcceptedExecution;
|
|
1803
2160
|
}) {
|
|
1804
2161
|
const session = await requireSession(input.tx, input.workspaceId, input.sessionId);
|
|
1805
|
-
const { task, personalConnectionDelegations } = input.acceptedExecution
|
|
1806
|
-
? {
|
|
1807
|
-
task: input.acceptedExecution.task,
|
|
1808
|
-
personalConnectionDelegations: input.acceptedExecution.personalConnectionDelegations,
|
|
1809
|
-
}
|
|
1810
|
-
: await requireScheduledTaskIncidentAuthorityInTransaction(input.tx, {
|
|
1811
|
-
workspaceId: input.workspaceId,
|
|
1812
|
-
taskId: input.taskId,
|
|
1813
|
-
});
|
|
2162
|
+
const { task, personalConnectionDelegations } = input.acceptedExecution;
|
|
1814
2163
|
const responder = await resolveIncidentTelemetryResponderMetadata({
|
|
1815
2164
|
db: input.tx,
|
|
1816
2165
|
settings: input.settings,
|
|
@@ -1818,39 +2167,34 @@ async function prepareIncidentTelemetrySource(input: {
|
|
|
1818
2167
|
session,
|
|
1819
2168
|
personalConnectionDelegations,
|
|
1820
2169
|
personalResourceAuthoritySubjectId:
|
|
1821
|
-
input.acceptedExecution
|
|
1822
|
-
|
|
2170
|
+
input.acceptedExecution.personalResourceAuthoritySubjectId ?? null,
|
|
2171
|
+
executionPolicy: input.acceptedExecution.targetSessionExecution
|
|
1823
2172
|
? {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
toolPolicy: input.acceptedExecution.targetSessionExecution.toolPolicy,
|
|
1838
|
-
mcpServerIds: input.acceptedExecution.targetSessionExecution.mcpServerIds,
|
|
1839
|
-
toolPolicyVersion: input.acceptedExecution.targetSessionExecution.toolPolicyVersion,
|
|
1840
|
-
}
|
|
1841
|
-
: {
|
|
1842
|
-
tools: input.acceptedExecution.resolvedTools,
|
|
1843
|
-
firstPartyMcpTools: input.acceptedExecution.resolvedFirstPartyMcpTools,
|
|
1844
|
-
firstPartyMcpPermissions: input.acceptedExecution.resolvedFirstPartyMcpPermissions,
|
|
1845
|
-
variableSetId: input.acceptedExecution.resolvedVariableSet?.id ?? null,
|
|
1846
|
-
rigId: input.acceptedExecution.resolvedRig?.id ?? null,
|
|
1847
|
-
rigVersionId: input.acceptedExecution.resolvedRig?.versionId ?? null,
|
|
1848
|
-
toolPolicy: session.toolPolicy,
|
|
1849
|
-
mcpServerIds: [],
|
|
1850
|
-
toolPolicyVersion: session.toolPolicyVersion,
|
|
1851
|
-
},
|
|
2173
|
+
tools: input.acceptedExecution.targetSessionExecution.tools,
|
|
2174
|
+
firstPartyMcpTools: input.acceptedExecution.targetSessionExecution.firstPartyMcpTools,
|
|
2175
|
+
firstPartyMcpPermissions:
|
|
2176
|
+
input.acceptedExecution.targetSessionExecution.firstPartyMcpPermissions,
|
|
2177
|
+
variableSetIds: input.acceptedExecution.targetSessionExecution.variableSets.map(
|
|
2178
|
+
(variableSet) => variableSet.id,
|
|
2179
|
+
),
|
|
2180
|
+
variableSetId: input.acceptedExecution.targetSessionExecution.variableSetId,
|
|
2181
|
+
rigId: input.acceptedExecution.targetSessionExecution.rigId,
|
|
2182
|
+
rigVersionId: input.acceptedExecution.targetSessionExecution.rigVersionId,
|
|
2183
|
+
toolPolicy: input.acceptedExecution.targetSessionExecution.toolPolicy,
|
|
2184
|
+
mcpServerIds: input.acceptedExecution.targetSessionExecution.mcpServerIds,
|
|
2185
|
+
toolPolicyVersion: input.acceptedExecution.targetSessionExecution.toolPolicyVersion,
|
|
1852
2186
|
}
|
|
1853
|
-
: {
|
|
2187
|
+
: {
|
|
2188
|
+
tools: input.acceptedExecution.resolvedTools,
|
|
2189
|
+
firstPartyMcpTools: input.acceptedExecution.resolvedFirstPartyMcpTools,
|
|
2190
|
+
firstPartyMcpPermissions: input.acceptedExecution.resolvedFirstPartyMcpPermissions,
|
|
2191
|
+
variableSetId: input.acceptedExecution.resolvedVariableSet?.id ?? null,
|
|
2192
|
+
rigId: input.acceptedExecution.resolvedRig?.id ?? null,
|
|
2193
|
+
rigVersionId: input.acceptedExecution.resolvedRig?.versionId ?? null,
|
|
2194
|
+
toolPolicy: session.toolPolicy,
|
|
2195
|
+
mcpServerIds: [],
|
|
2196
|
+
toolPolicyVersion: session.toolPolicyVersion,
|
|
2197
|
+
},
|
|
1854
2198
|
});
|
|
1855
2199
|
const preflight = evaluateIncidentTelemetryPreflight({
|
|
1856
2200
|
agentConfig: task.agentConfig,
|
|
@@ -1967,6 +2311,7 @@ async function seedScheduledGeneratedSessionRoute(input: {
|
|
|
1967
2311
|
|
|
1968
2312
|
async function recoverBoundScheduledTaskDispatch(input: {
|
|
1969
2313
|
db: Database;
|
|
2314
|
+
observability?: ProductUsageMetricsSink | undefined;
|
|
1970
2315
|
bus: ControlActivityServices["bus"];
|
|
1971
2316
|
settings: ControlActivityServices["settings"];
|
|
1972
2317
|
wakeSessionWorkflow: WakeSessionWorkflowSignal | null;
|
|
@@ -1981,6 +2326,11 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
1981
2326
|
const generatedSession =
|
|
1982
2327
|
task.runMode === "new_session_per_run" ||
|
|
1983
2328
|
(task.runMode === "reusable_session" && task.reusableSessionId === null);
|
|
2329
|
+
// The immutable creator policy determines standing session authority, not
|
|
2330
|
+
// a manual caller's per-run ceiling. Read it for creation and recovery checks.
|
|
2331
|
+
const recoveredCreatorPolicy = generatedSession
|
|
2332
|
+
? await getScheduledTaskCreatorPolicy(input.db, task.workspaceId, task.id)
|
|
2333
|
+
: null;
|
|
1984
2334
|
const frozenSlack = input.acceptedExecution.resolvedSlackBotConnection;
|
|
1985
2335
|
if (frozenSlack) {
|
|
1986
2336
|
const currentSlack = await requireOpenGeniSlackBotConnection(
|
|
@@ -2003,9 +2353,8 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2003
2353
|
let session: Awaited<ReturnType<typeof createSession>>;
|
|
2004
2354
|
if (input.run.sessionId) {
|
|
2005
2355
|
session = await requireSession(input.db, task.workspaceId, input.run.sessionId);
|
|
2006
|
-
//
|
|
2007
|
-
//
|
|
2008
|
-
// run terminally rather than deliver into a diverged session.
|
|
2356
|
+
// Preserve the reusable chat's Slack routing; the accepted target snapshot
|
|
2357
|
+
// independently fences its current Variable Set attachments during recovery.
|
|
2009
2358
|
if (!generatedSession) assertReusableSessionBindingMatches(session, task);
|
|
2010
2359
|
} else if (generatedSession) {
|
|
2011
2360
|
const variableSet = input.acceptedExecution.resolvedVariableSet;
|
|
@@ -2049,14 +2398,6 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2049
2398
|
}
|
|
2050
2399
|
const taskMetadata = { ...task.agentConfig.metadata };
|
|
2051
2400
|
delete taskMetadata[OPENGENI_SLACK_BOT_SESSION_METADATA_KEY];
|
|
2052
|
-
// Tools and permissions were frozen into the accepted execution. The
|
|
2053
|
-
// creator session policy is immutable on the task row (a tombstoned task
|
|
2054
|
-
// still answers), so re-reading it here is deterministic for the same run.
|
|
2055
|
-
const recoveredCreatorPolicy = await getScheduledTaskCreatorPolicy(
|
|
2056
|
-
input.db,
|
|
2057
|
-
task.workspaceId,
|
|
2058
|
-
task.id,
|
|
2059
|
-
);
|
|
2060
2401
|
const created = await createSessionWithIdempotencyKeyResult(input.db, {
|
|
2061
2402
|
accountId: task.accountId,
|
|
2062
2403
|
workspaceId: task.workspaceId,
|
|
@@ -2066,6 +2407,12 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2066
2407
|
tools: input.acceptedExecution.resolvedTools,
|
|
2067
2408
|
firstPartyMcpTools: input.acceptedExecution.resolvedFirstPartyMcpTools,
|
|
2068
2409
|
firstPartyMcpPermissions: input.acceptedExecution.resolvedFirstPartyMcpPermissions,
|
|
2410
|
+
...(input.acceptedExecution.resolvedAgentConfig
|
|
2411
|
+
? { agentConfig: input.acceptedExecution.resolvedAgentConfig }
|
|
2412
|
+
: {}),
|
|
2413
|
+
...(input.acceptedExecution.resolvedAgentInstructions !== undefined
|
|
2414
|
+
? { instructions: input.acceptedExecution.resolvedAgentInstructions }
|
|
2415
|
+
: {}),
|
|
2069
2416
|
...scheduledCreatorSessionPolicyInput(recoveredCreatorPolicy?.sessionPolicy ?? null),
|
|
2070
2417
|
...(task.agentConfig.knowledgeSource?.destination.kind === "personal"
|
|
2071
2418
|
? {
|
|
@@ -2075,6 +2422,10 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2075
2422
|
: {}),
|
|
2076
2423
|
metadata: {
|
|
2077
2424
|
...taskMetadata,
|
|
2425
|
+
...scheduledSessionExecutionPolicyMetadata(
|
|
2426
|
+
input.acceptedExecution.turnExecutionPolicy,
|
|
2427
|
+
recoveredCreatorPolicy?.credentialRestriction,
|
|
2428
|
+
),
|
|
2078
2429
|
model: input.acceptedExecution.resolvedModel,
|
|
2079
2430
|
reasoningEffort: input.acceptedExecution.resolvedReasoningEffort,
|
|
2080
2431
|
scheduledTaskId: task.id,
|
|
@@ -2103,6 +2454,8 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2103
2454
|
personalConnectionDelegations: [],
|
|
2104
2455
|
initialXaiProviderAccountAuthoritySnapshot:
|
|
2105
2456
|
input.acceptedExecution.xaiProviderAccountAuthoritySnapshot,
|
|
2457
|
+
initialClaudeProviderAccountAuthoritySnapshot:
|
|
2458
|
+
input.acceptedExecution.claudeProviderAccountAuthoritySnapshot,
|
|
2106
2459
|
maxNestedAgentDepthOverride: task.agentConfig.maxNestedAgentDepth ?? null,
|
|
2107
2460
|
frozenNestedAgentDepthPolicy: {
|
|
2108
2461
|
effectiveMaxNestedAgentDepth:
|
|
@@ -2133,6 +2486,7 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2133
2486
|
});
|
|
2134
2487
|
if (created.denied) throw new SessionSpawnDeniedDbError(created.denial);
|
|
2135
2488
|
session = created.session;
|
|
2489
|
+
if (created.created) recordScheduledSessionCreated(input.observability);
|
|
2136
2490
|
if (!created.created) {
|
|
2137
2491
|
await bindScheduledTaskRunSessionInTransaction(input.db, {
|
|
2138
2492
|
accountId: task.accountId,
|
|
@@ -2203,20 +2557,27 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2203
2557
|
);
|
|
2204
2558
|
const expectedTaskMetadata = { ...task.agentConfig.metadata };
|
|
2205
2559
|
delete expectedTaskMetadata[OPENGENI_SLACK_BOT_SESSION_METADATA_KEY];
|
|
2206
|
-
const expectedMetadata =
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2560
|
+
const expectedMetadata = metadataWithAgentConfigCreateIdentity(
|
|
2561
|
+
{
|
|
2562
|
+
...expectedTaskMetadata,
|
|
2563
|
+
...scheduledSessionExecutionPolicyMetadata(
|
|
2564
|
+
input.acceptedExecution.turnExecutionPolicy,
|
|
2565
|
+
recoveredCreatorPolicy?.credentialRestriction,
|
|
2566
|
+
),
|
|
2567
|
+
model: input.acceptedExecution.resolvedModel,
|
|
2568
|
+
reasoningEffort: input.acceptedExecution.resolvedReasoningEffort,
|
|
2569
|
+
scheduledTaskId: task.id,
|
|
2570
|
+
scheduledTaskRunMode: task.runMode,
|
|
2571
|
+
...(task.agentConfig.goal ? { scheduledTaskGoal: task.agentConfig.goal } : {}),
|
|
2572
|
+
scheduledTaskRunId: canonicalGeneratedRunId,
|
|
2573
|
+
...(frozenSlack ? { [OPENGENI_SLACK_BOT_SESSION_METADATA_KEY]: frozenSlack.id } : {}),
|
|
2574
|
+
},
|
|
2575
|
+
input.acceptedExecution.resolvedAgentConfig,
|
|
2576
|
+
);
|
|
2216
2577
|
if (
|
|
2217
2578
|
session.createIdempotencyKey !== expectedCreateKey ||
|
|
2218
2579
|
session.initialMessage !== task.agentConfig.prompt ||
|
|
2219
|
-
session.instructions !== null ||
|
|
2580
|
+
session.instructions !== (input.acceptedExecution.resolvedAgentInstructions ?? null) ||
|
|
2220
2581
|
session.policyRole !== null ||
|
|
2221
2582
|
stableJson(session.skills) !== "[]" ||
|
|
2222
2583
|
stableJson(session.toolPolicy) !==
|
|
@@ -2258,6 +2619,8 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2258
2619
|
stableJson(input.acceptedExecution.resolvedFirstPartyMcpTools) ||
|
|
2259
2620
|
stableJson(session.firstPartyMcpPermissions) !==
|
|
2260
2621
|
stableJson(input.acceptedExecution.resolvedFirstPartyMcpPermissions) ||
|
|
2622
|
+
stableJson(session.agent) !==
|
|
2623
|
+
stableJson(input.acceptedExecution.resolvedAgentConfig ?? null) ||
|
|
2261
2624
|
session.maxNestedAgentDepthOverride !== (task.agentConfig.maxNestedAgentDepth ?? null) ||
|
|
2262
2625
|
(session.variableSetId ?? null) !==
|
|
2263
2626
|
(input.acceptedExecution.resolvedVariableSet?.id ?? null) ||
|
|
@@ -2354,10 +2717,16 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2354
2717
|
...(input.acceptedExecution.xaiAuthoritySubjectId
|
|
2355
2718
|
? { xaiAuthoritySubjectId: input.acceptedExecution.xaiAuthoritySubjectId }
|
|
2356
2719
|
: {}),
|
|
2720
|
+
...(input.acceptedExecution.claudeAuthoritySubjectId
|
|
2721
|
+
? { claudeAuthoritySubjectId: input.acceptedExecution.claudeAuthoritySubjectId }
|
|
2722
|
+
: {}),
|
|
2357
2723
|
},
|
|
2358
2724
|
personalConnectionDelegations: input.acceptedExecution.personalConnectionDelegations,
|
|
2725
|
+
mcpAccountBindings: input.acceptedExecution.mcpAccountBindings ?? null,
|
|
2359
2726
|
xaiProviderAccountAuthoritySnapshot:
|
|
2360
2727
|
input.acceptedExecution.xaiProviderAccountAuthoritySnapshot,
|
|
2728
|
+
claudeProviderAccountAuthoritySnapshot:
|
|
2729
|
+
input.acceptedExecution.claudeProviderAccountAuthoritySnapshot,
|
|
2361
2730
|
scheduledTaskRunId: input.run.id,
|
|
2362
2731
|
},
|
|
2363
2732
|
async (tx, wakeEventId, _updateId, rejectionReason) => {
|
|
@@ -2422,6 +2791,9 @@ async function recoverBoundScheduledTaskDispatch(input: {
|
|
|
2422
2791
|
) {
|
|
2423
2792
|
return { action: "blocked", reason: "scheduled_run_terminal" };
|
|
2424
2793
|
}
|
|
2794
|
+
if (scheduledUpdate.added) {
|
|
2795
|
+
recordUserMessageAccepted(input.observability, { surface: "scheduled" });
|
|
2796
|
+
}
|
|
2425
2797
|
if (scheduledUpdate.added && scheduledUpdate.events.length > 0) {
|
|
2426
2798
|
await publishDurableSessionEvents(
|
|
2427
2799
|
input.bus,
|