@opengeni/worker-bundle 1.0.0-canary.1 → 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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** One durable, same-logical-turn handoff, not a retry of model/tool effects. */
|
|
2
|
+
export function finalReplyNudge(turnId: string) {
|
|
3
|
+
return {
|
|
4
|
+
type: "message" as const,
|
|
5
|
+
role: "developer" as const,
|
|
6
|
+
content: [
|
|
7
|
+
{
|
|
8
|
+
type: "input_text" as const,
|
|
9
|
+
text: `[Runtime final-reply handoff for turn ${turnId}]\nYour final user-facing answer was empty. Reply to the user now with the requested deliverable or a concise outcome and its retained artifact link. Goal evidence is a short ledger proof, not the answer, and goal_complete does not deliver a chat reply. Use the completed work and tool results already in history; do not repeat completed tools or restart the task. If this is a late child result after goal completion, integrate material new findings and deliver any still-missing handoff. Do not change the completed goal or invent a result.`,
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function hasFinalReplyNudge(history: readonly unknown[], turnId: string): boolean {
|
|
16
|
+
const text = finalReplyNudge(turnId).content[0]!.text;
|
|
17
|
+
return history.some((item) => {
|
|
18
|
+
const message = item as { role?: unknown; content?: unknown } | null;
|
|
19
|
+
return (
|
|
20
|
+
message?.role === "developer" &&
|
|
21
|
+
Array.isArray(message.content) &&
|
|
22
|
+
message.content.some(
|
|
23
|
+
(part: { type?: unknown; text?: unknown }) =>
|
|
24
|
+
part?.type === "input_text" && part.text === text,
|
|
25
|
+
)
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function needsFinalReply(input: {
|
|
31
|
+
output: unknown;
|
|
32
|
+
inputWaitYielded: boolean;
|
|
33
|
+
interrupted: boolean;
|
|
34
|
+
maintenance: boolean;
|
|
35
|
+
toolsExecuted: boolean;
|
|
36
|
+
completedGoal: boolean;
|
|
37
|
+
}): boolean {
|
|
38
|
+
return (
|
|
39
|
+
typeof input.output === "string" &&
|
|
40
|
+
input.output.trim().length === 0 &&
|
|
41
|
+
!input.inputWaitYielded &&
|
|
42
|
+
!input.interrupted &&
|
|
43
|
+
!input.maintenance &&
|
|
44
|
+
(input.toolsExecuted || input.completedGoal)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Observability } from "@opengeni/observability";
|
|
2
|
+
import type { TurnHeartbeatDetails } from "../../op-journal";
|
|
3
|
+
import { armTurnQuiescenceWatchdog } from "./quiescence";
|
|
4
|
+
|
|
5
|
+
export const TURN_FINALIZATION_STAGES = [
|
|
6
|
+
"tool_writers",
|
|
7
|
+
"credential_renewals",
|
|
8
|
+
"credential_cleanup",
|
|
9
|
+
"quiescence_receipt",
|
|
10
|
+
"event_flush",
|
|
11
|
+
"provider_leases",
|
|
12
|
+
"workspace_capture",
|
|
13
|
+
"tool_close",
|
|
14
|
+
"sandbox_provisioning",
|
|
15
|
+
"sandbox_rotation",
|
|
16
|
+
"workspace_snapshot",
|
|
17
|
+
"sandbox_release",
|
|
18
|
+
] as const;
|
|
19
|
+
export type TurnFinalizationStage = (typeof TURN_FINALIZATION_STAGES)[number];
|
|
20
|
+
|
|
21
|
+
const INFLIGHT = {
|
|
22
|
+
name: "opengeni_turn_finalization_inflight",
|
|
23
|
+
help: "Physical turn finalizers currently waiting in each cleanup stage.",
|
|
24
|
+
};
|
|
25
|
+
const SLOW_STAGES = {
|
|
26
|
+
name: "opengeni_turn_finalization_slow_total",
|
|
27
|
+
help: "Turn cleanup stages observed to exceed thirty seconds.",
|
|
28
|
+
};
|
|
29
|
+
const initialized = new WeakSet<Observability>();
|
|
30
|
+
function diagnose(operation: () => void): void {
|
|
31
|
+
try {
|
|
32
|
+
operation();
|
|
33
|
+
} catch {
|
|
34
|
+
// Diagnostics cannot own physical cleanup or containment.
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Starts only after agent execution ends. A cleanup-stage deadline never caps
|
|
39
|
+
* agent work and never detaches a physical writer to manufacture quiescence. */
|
|
40
|
+
export function startTurnFinalizationMonitor(input: {
|
|
41
|
+
observability: Observability;
|
|
42
|
+
details: TurnHeartbeatDetails;
|
|
43
|
+
heartbeat: (details: TurnHeartbeatDetails) => void;
|
|
44
|
+
requestWorkerDrain: () => void;
|
|
45
|
+
timeoutMs?: number;
|
|
46
|
+
slowAfterMs?: number;
|
|
47
|
+
}) {
|
|
48
|
+
const { observability, details } = input;
|
|
49
|
+
if (!initialized.has(observability)) {
|
|
50
|
+
for (const stage of TURN_FINALIZATION_STAGES) {
|
|
51
|
+
diagnose(() => observability.incrementGauge({ ...INFLIGHT, labels: { stage }, amount: 0 }));
|
|
52
|
+
diagnose(() =>
|
|
53
|
+
observability.incrementCounter({ ...SLOW_STAGES, labels: { stage }, amount: 0 }),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
initialized.add(observability);
|
|
57
|
+
}
|
|
58
|
+
let stage: TurnFinalizationStage | null = null;
|
|
59
|
+
let disarm = () => {};
|
|
60
|
+
let stopped = false;
|
|
61
|
+
let slowTimer: ReturnType<typeof setTimeout> | undefined;
|
|
62
|
+
const leave = () => {
|
|
63
|
+
disarm();
|
|
64
|
+
clearTimeout(slowTimer);
|
|
65
|
+
if (stage) {
|
|
66
|
+
const previous = stage;
|
|
67
|
+
diagnose(() =>
|
|
68
|
+
observability.incrementGauge({ ...INFLIGHT, labels: { stage: previous }, amount: -1 }),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
stage = null;
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
enter(next: TurnFinalizationStage) {
|
|
75
|
+
if (stopped || stage === next) return;
|
|
76
|
+
leave();
|
|
77
|
+
stage = next;
|
|
78
|
+
details.phase = "finalizing";
|
|
79
|
+
details.finalizationStage = next;
|
|
80
|
+
details.finalizationStageStartedAt = new Date().toISOString();
|
|
81
|
+
diagnose(() => observability.incrementGauge({ ...INFLIGHT, labels: { stage: next } }));
|
|
82
|
+
disarm = armTurnQuiescenceWatchdog({
|
|
83
|
+
enabled: true,
|
|
84
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
85
|
+
onTimeout: () => {
|
|
86
|
+
try {
|
|
87
|
+
observability.error("turn finalization stalled; containing worker", {
|
|
88
|
+
surface: "turn_finalization",
|
|
89
|
+
outcome: "containment",
|
|
90
|
+
reason: next,
|
|
91
|
+
});
|
|
92
|
+
} catch {
|
|
93
|
+
// Diagnostic failure must never disable physical containment.
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
terminateWorker: input.requestWorkerDrain,
|
|
97
|
+
});
|
|
98
|
+
// Record the precursor while the process remains scrapeable.
|
|
99
|
+
slowTimer = setTimeout(
|
|
100
|
+
() =>
|
|
101
|
+
diagnose(() => {
|
|
102
|
+
observability.incrementCounter({ ...SLOW_STAGES, labels: { stage: next } });
|
|
103
|
+
observability.warn("turn finalization is taking longer than expected", {
|
|
104
|
+
surface: "turn_finalization",
|
|
105
|
+
outcome: "slow",
|
|
106
|
+
reason: next,
|
|
107
|
+
});
|
|
108
|
+
}),
|
|
109
|
+
input.slowAfterMs ?? 30_000,
|
|
110
|
+
);
|
|
111
|
+
slowTimer.unref?.();
|
|
112
|
+
diagnose(() => input.heartbeat(details));
|
|
113
|
+
},
|
|
114
|
+
stop() {
|
|
115
|
+
if (stopped) return;
|
|
116
|
+
stopped = true;
|
|
117
|
+
leave();
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
commitSessionAttemptQuiescence,
|
|
3
3
|
listPendingSessionTurns,
|
|
4
|
-
|
|
4
|
+
recordCodexAccountUsageForFinalization,
|
|
5
|
+
recordClaudeAccountUsage,
|
|
6
|
+
releaseClaudeCredentialLease,
|
|
5
7
|
releaseCodexCredentialLease,
|
|
6
8
|
releaseXaiCredentialLease,
|
|
7
9
|
updateXaiQuotaMetadata,
|
|
@@ -11,9 +13,10 @@ import { appendAndPublishTurnEventsFenced, publishDurableSessionEvents } from "@
|
|
|
11
13
|
import { sandboxLeaseTelemetryKey } from "@opengeni/observability";
|
|
12
14
|
import { clearRunCredentialsForAttempt } from "@opengeni/runtime";
|
|
13
15
|
import { fetchXaiSubscriptionQuota } from "@opengeni/xai-subscription";
|
|
14
|
-
import type
|
|
16
|
+
import { environmentsEncryptionKeyBytes, type Settings } from "@opengeni/config";
|
|
15
17
|
import { signalCodexCapacityWakeTargets } from "../codex-capacity";
|
|
16
|
-
import type
|
|
18
|
+
import { startActivityHeartbeat, type currentActivityContext } from "../streaming";
|
|
19
|
+
import { startTurnFinalizationMonitor } from "./finalization-monitor";
|
|
17
20
|
import type { CodemodeTokenRenewalController } from "../codemode-token-renewal";
|
|
18
21
|
import type { RunCredentialRenewalController } from "../run-credential-renewal";
|
|
19
22
|
import type {
|
|
@@ -32,6 +35,7 @@ import {
|
|
|
32
35
|
makeMachineOpObserver,
|
|
33
36
|
recordSessionEventAppendPhase,
|
|
34
37
|
turnLifecycleMetricsFor,
|
|
38
|
+
runtimeMetricsHooksForObservability,
|
|
35
39
|
} from "../../observability-metrics";
|
|
36
40
|
import {
|
|
37
41
|
maybePersistWarmWorkspaceSnapshot,
|
|
@@ -43,7 +47,6 @@ import { safeErrorDiagnostic, safeErrorForTelemetry } from "./errors";
|
|
|
43
47
|
import {
|
|
44
48
|
assertPhysicalToolQuiescenceForCancellation,
|
|
45
49
|
assertSessionAttemptQuiescenceRecoveryDurable,
|
|
46
|
-
armTurnQuiescenceWatchdog,
|
|
47
50
|
clearAttemptCredentialsWithSettledFence,
|
|
48
51
|
drainAttemptOwnedSandboxWriters,
|
|
49
52
|
persistOrSignalSessionAttemptQuiescence,
|
|
@@ -72,6 +75,8 @@ export type TurnFinalizationDeps = {
|
|
|
72
75
|
wakeSessionWorkflow: ActivityServices["wakeSessionWorkflow"];
|
|
73
76
|
signalSessionAttemptQuiesced: ActivityServices["signalSessionAttemptQuiesced"];
|
|
74
77
|
signalCodexCapacityWorkflow: ActivityServices["signalCodexCapacityWorkflow"];
|
|
78
|
+
requestWorkerDrain: ActivityServices["requestWorkerDrain"];
|
|
79
|
+
turnFinalizationTimeoutMs: ActivityServices["turnFinalizationTimeoutMs"];
|
|
75
80
|
cancellationSignal: AbortSignal | undefined;
|
|
76
81
|
sandboxResumeController: AbortController;
|
|
77
82
|
activityContext: ReturnType<typeof currentActivityContext>;
|
|
@@ -99,6 +104,45 @@ export type TurnFinalizationDeps = {
|
|
|
99
104
|
};
|
|
100
105
|
|
|
101
106
|
export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<void> {
|
|
107
|
+
const details = deps.eventing.heartbeatDetails ?? {
|
|
108
|
+
sessionId: deps.input.sessionId,
|
|
109
|
+
turnId: deps.attempt.turnId,
|
|
110
|
+
opAcks: {},
|
|
111
|
+
};
|
|
112
|
+
deps.eventing.heartbeatDetails = details;
|
|
113
|
+
// Keep one heartbeat owner through all physical cleanup, with the same op
|
|
114
|
+
// acknowledgements used during execution. It must no longer say "running".
|
|
115
|
+
if (deps.eventing.heartbeatTimer) clearInterval(deps.eventing.heartbeatTimer);
|
|
116
|
+
deps.eventing.heartbeatTimer = startActivityHeartbeat(deps.activityContext, details);
|
|
117
|
+
const monitor = startTurnFinalizationMonitor({
|
|
118
|
+
observability: deps.observability,
|
|
119
|
+
...(deps.turnFinalizationTimeoutMs === undefined
|
|
120
|
+
? {}
|
|
121
|
+
: { timeoutMs: deps.turnFinalizationTimeoutMs }),
|
|
122
|
+
details,
|
|
123
|
+
heartbeat: (value) => {
|
|
124
|
+
try {
|
|
125
|
+
deps.activityContext?.heartbeat({ ...value, at: new Date().toISOString() });
|
|
126
|
+
} catch {
|
|
127
|
+
// A closed Temporal transport is not proof of physical quiescence.
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
requestWorkerDrain: deps.requestWorkerDrain,
|
|
131
|
+
});
|
|
132
|
+
try {
|
|
133
|
+
monitor.enter("tool_writers");
|
|
134
|
+
await finalizeTurnAttemptSteps(deps, monitor);
|
|
135
|
+
} finally {
|
|
136
|
+
monitor.stop();
|
|
137
|
+
if (deps.eventing.heartbeatTimer) clearInterval(deps.eventing.heartbeatTimer);
|
|
138
|
+
deps.eventing.heartbeatTimer = undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function finalizeTurnAttemptSteps(
|
|
143
|
+
deps: TurnFinalizationDeps,
|
|
144
|
+
monitor: ReturnType<typeof startTurnFinalizationMonitor>,
|
|
145
|
+
): Promise<void> {
|
|
102
146
|
const {
|
|
103
147
|
input,
|
|
104
148
|
settings,
|
|
@@ -142,17 +186,6 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
142
186
|
let finalizationError: unknown;
|
|
143
187
|
let physicalToolQuiescenceConfirmed = !control.acknowledgeQuiescence;
|
|
144
188
|
let quiescenceReceiptOrProofDurable = !control.acknowledgeQuiescence;
|
|
145
|
-
const disarmQuiescenceWatchdog = armTurnQuiescenceWatchdog({
|
|
146
|
-
enabled: control.acknowledgeQuiescence,
|
|
147
|
-
onTimeout: () => {
|
|
148
|
-
observability.error("turn quiescence drain exceeded hard containment deadline", {
|
|
149
|
-
"opengeni.session_id": input.sessionId,
|
|
150
|
-
"opengeni.turn_id": attempt.turnId ?? "",
|
|
151
|
-
"opengeni.attempt_id": input.attemptId,
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
terminateWorker: () => process.exit(1),
|
|
155
|
-
});
|
|
156
189
|
const finalizerSignal = turnFinalizerCancellationSignal(
|
|
157
190
|
cancellationSignal,
|
|
158
191
|
control.activityStatus,
|
|
@@ -187,6 +220,8 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
187
220
|
renewals.codemodeTokenRenewal as CodemodeTokenRenewalController | null;
|
|
188
221
|
renewals.codemodeTokenRenewal = null;
|
|
189
222
|
renewals.runCredentialRenewalClosed = true;
|
|
223
|
+
renewals.runMcpCredentials?.close();
|
|
224
|
+
delete renewals.runMcpCredentials;
|
|
190
225
|
const runRenewalToStop = renewals.runCredentialRenewal as RunCredentialRenewalController | null;
|
|
191
226
|
renewals.runCredentialRenewal = null;
|
|
192
227
|
|
|
@@ -200,6 +235,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
200
235
|
// and durably settled before workspace capture. Only receipt
|
|
201
236
|
// publication remains conditional on acknowledgeQuiescence.
|
|
202
237
|
toolCancellationFence,
|
|
238
|
+
onStage: monitor.enter,
|
|
203
239
|
cancellationReason: cancellationSignal?.reason ?? new Error("TURN_ATTEMPT_FINALIZED"),
|
|
204
240
|
gitCredentialRenewals: gitRenewalsToStop,
|
|
205
241
|
codemodeTokenRenewal: codemodeRenewalToStop,
|
|
@@ -211,6 +247,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
211
247
|
// attempt's generation before publishing physical quiescence. A failure
|
|
212
248
|
// deliberately keeps the receipt closed.
|
|
213
249
|
if (credentialSessionToClear) {
|
|
250
|
+
monitor.enter("credential_cleanup");
|
|
214
251
|
const clearAttemptCredentials = async (): Promise<void> =>
|
|
215
252
|
await clearRunCredentialsForAttempt(credentialSessionToClear, {
|
|
216
253
|
sessionId: input.sessionId,
|
|
@@ -258,6 +295,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
258
295
|
// and before lease, cache, recording, or provider cleanup. Its
|
|
259
296
|
// transaction also enqueues the exact workflow wake that will admit
|
|
260
297
|
// the replacement; Temporal activity terminalization does neither.
|
|
298
|
+
monitor.enter("quiescence_receipt");
|
|
261
299
|
const proof: SessionAttemptQuiescenceProof = {
|
|
262
300
|
accountId: input.accountId,
|
|
263
301
|
workspaceId: input.workspaceId,
|
|
@@ -304,6 +342,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
304
342
|
signalProof: signalSessionAttemptQuiesced,
|
|
305
343
|
heartbeat: (deliveryAttempt, retryMs) => {
|
|
306
344
|
activityContext?.heartbeat({
|
|
345
|
+
...eventing.heartbeatDetails,
|
|
307
346
|
phase: "quiescence-proof-delivery",
|
|
308
347
|
sessionId: input.sessionId,
|
|
309
348
|
attemptId: input.attemptId,
|
|
@@ -336,7 +375,6 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
336
375
|
},
|
|
337
376
|
});
|
|
338
377
|
quiescenceReceiptOrProofDurable = true;
|
|
339
|
-
disarmQuiescenceWatchdog();
|
|
340
378
|
if (recoveryMode === "signal") {
|
|
341
379
|
observability.info("agent turn quiescence proof handed to workflow recovery", {
|
|
342
380
|
"opengeni.session_id": input.sessionId,
|
|
@@ -351,6 +389,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
351
389
|
// the turn. Sync observer → buffer → single awaited append here (no unawaited
|
|
352
390
|
// DB write inside the activity). Scoped to this turn; skipped if no turnId
|
|
353
391
|
// (the op ran under a turn, so on the normal path turnId is set).
|
|
392
|
+
monitor.enter("event_flush");
|
|
354
393
|
const machineOpEvents = machineOpObserver.drainEvents();
|
|
355
394
|
if (machineOpEvents.length > 0 && attempt.turnId && attempt.executionGeneration > 0) {
|
|
356
395
|
await waitForTurnFinalizerStep(
|
|
@@ -377,17 +416,65 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
377
416
|
// Multi-account P4: flush the serving account's free per-turn caches ONCE,
|
|
378
417
|
// best-effort (same discipline as today's usage write). Both writers skip
|
|
379
418
|
// version/updatedAt, so neither can race the token-refresh CAS.
|
|
419
|
+
monitor.enter("provider_leases");
|
|
420
|
+
const claudeEncryptionKey = environmentsEncryptionKeyBytes(settings);
|
|
421
|
+
if (claudeEncryptionKey && providerTurn.claudeAuthoritySnapshot && leases.claude.subjectId) {
|
|
422
|
+
for (const snapshot of providerTurn.latestClaudeUsage.values()) {
|
|
423
|
+
if (
|
|
424
|
+
(!snapshot.observation && !snapshot.refresh) ||
|
|
425
|
+
snapshot.expectedConnectionId !== providerTurn.effectiveClaudeCredentialId ||
|
|
426
|
+
snapshot.expectedCredentialVersion !== providerTurn.effectiveClaudeCredentialVersion
|
|
427
|
+
)
|
|
428
|
+
continue;
|
|
429
|
+
await waitForTurnFinalizerStep(
|
|
430
|
+
recordClaudeAccountUsage(
|
|
431
|
+
db,
|
|
432
|
+
{
|
|
433
|
+
accountId: input.accountId,
|
|
434
|
+
workspaceId: input.workspaceId,
|
|
435
|
+
subjectId: leases.claude.subjectId,
|
|
436
|
+
credentialId: snapshot.expectedConnectionId,
|
|
437
|
+
authoritySnapshot: providerTurn.claudeAuthoritySnapshot,
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
encryptionKey: claudeEncryptionKey,
|
|
441
|
+
token: snapshot.token,
|
|
442
|
+
expectedCredentialVersion: snapshot.expectedCredentialVersion,
|
|
443
|
+
...(snapshot.observation ? { observation: snapshot.observation } : {}),
|
|
444
|
+
...(snapshot.refresh ? { refresh: snapshot.refresh } : {}),
|
|
445
|
+
},
|
|
446
|
+
).catch(() => null),
|
|
447
|
+
finalizerSignal,
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
380
451
|
if (providerTurn.effectiveCodexCredentialId) {
|
|
381
452
|
// Part A: the latest scraped usage-header snapshot → the P2 usage cache. A
|
|
382
|
-
// full
|
|
383
|
-
//
|
|
384
|
-
if (
|
|
453
|
+
// full duration-identified snapshot (parseCodexUsageHeaders gates on both),
|
|
454
|
+
// so untyped response headers cannot mislabel weekly-only quota.
|
|
455
|
+
if (
|
|
456
|
+
providerTurn.latestCodexUsage &&
|
|
457
|
+
attempt.turnId &&
|
|
458
|
+
leases.codex.held &&
|
|
459
|
+
leases.codex.holderId &&
|
|
460
|
+
leases.codex.generation !== null &&
|
|
461
|
+
providerTurn.effectiveCodexCredentialVersion !== null
|
|
462
|
+
) {
|
|
385
463
|
const usageMutation = await waitForTurnFinalizerStep(
|
|
386
|
-
|
|
464
|
+
recordCodexAccountUsageForFinalization(
|
|
387
465
|
db,
|
|
388
466
|
input.workspaceId,
|
|
389
467
|
providerTurn.effectiveCodexCredentialId,
|
|
390
468
|
providerTurn.latestCodexUsage,
|
|
469
|
+
{
|
|
470
|
+
turnId: attempt.turnId,
|
|
471
|
+
sessionId: input.sessionId,
|
|
472
|
+
attemptId: input.attemptId,
|
|
473
|
+
executionGeneration: attempt.executionGeneration,
|
|
474
|
+
holderId: leases.codex.holderId,
|
|
475
|
+
generation: leases.codex.generation,
|
|
476
|
+
credentialVersion: providerTurn.effectiveCodexCredentialVersion,
|
|
477
|
+
},
|
|
391
478
|
).catch(() => null),
|
|
392
479
|
finalizerSignal,
|
|
393
480
|
);
|
|
@@ -450,25 +537,30 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
450
537
|
);
|
|
451
538
|
}
|
|
452
539
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
leases.
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
540
|
+
for (const [lease, release] of [
|
|
541
|
+
[leases.xai, releaseXaiCredentialLease],
|
|
542
|
+
[leases.claude, releaseClaudeCredentialLease],
|
|
543
|
+
] as const) {
|
|
544
|
+
lease.stopHeartbeat();
|
|
545
|
+
if (
|
|
546
|
+
lease.held &&
|
|
547
|
+
attempt.turnId &&
|
|
548
|
+
lease.subjectId &&
|
|
549
|
+
lease.holderId &&
|
|
550
|
+
lease.generation !== null
|
|
551
|
+
) {
|
|
552
|
+
await waitForTurnFinalizerStep(
|
|
553
|
+
release(db, {
|
|
554
|
+
workspaceId: input.workspaceId,
|
|
555
|
+
subjectId: lease.subjectId,
|
|
556
|
+
turnId: attempt.turnId,
|
|
557
|
+
holderId: lease.holderId,
|
|
558
|
+
generation: lease.generation,
|
|
559
|
+
}).catch(() => undefined),
|
|
560
|
+
finalizerSignal,
|
|
561
|
+
);
|
|
562
|
+
lease.held = false;
|
|
563
|
+
}
|
|
472
564
|
}
|
|
473
565
|
// Workbench v2 turn-end workspace capture — runs FIRST in
|
|
474
566
|
// the turn-end finally, while the box is MAXIMALLY ALIVE. The agent's last
|
|
@@ -502,6 +594,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
502
594
|
) {
|
|
503
595
|
// Review reads yield to queued work. Recovery snapshots have their own
|
|
504
596
|
// physical-settlement requirement and are drained later in finalization.
|
|
597
|
+
monitor.enter("workspace_capture");
|
|
505
598
|
sandboxState.turnEndCaptureInProgress = true;
|
|
506
599
|
const captureSandbox = sandboxState.resolvedSandbox;
|
|
507
600
|
const captureSession = sandboxState.setupBoxSession as ChannelASession;
|
|
@@ -549,6 +642,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
549
642
|
},
|
|
550
643
|
});
|
|
551
644
|
}
|
|
645
|
+
monitor.enter("tool_close");
|
|
552
646
|
eventing.toolPreparationClosing = true;
|
|
553
647
|
if (eventing.toolPreparationReady) {
|
|
554
648
|
await waitForTurnFinalizerStep(
|
|
@@ -569,9 +663,7 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
569
663
|
finalizerSignal,
|
|
570
664
|
);
|
|
571
665
|
}
|
|
572
|
-
|
|
573
|
-
clearInterval(eventing.heartbeatTimer);
|
|
574
|
-
}
|
|
666
|
+
monitor.enter("sandbox_provisioning");
|
|
575
667
|
if (sandboxState.turnSandboxProvisioner?.hasStarted()) {
|
|
576
668
|
await waitForTurnFinalizerStep(
|
|
577
669
|
sandboxState.turnSandboxProvisioner.waitForSettled(30_000),
|
|
@@ -599,12 +691,14 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
599
691
|
if (sandboxState.leaseHeartbeatTimer) {
|
|
600
692
|
stopLeaseHeartbeat();
|
|
601
693
|
}
|
|
694
|
+
monitor.enter("sandbox_rotation");
|
|
602
695
|
if (sandboxState.rotationPreemptionInFlight) {
|
|
603
696
|
await sandboxState.rotationPreemptionInFlight.catch(() => undefined);
|
|
604
697
|
}
|
|
605
698
|
// No heartbeat can register another capture after this point. Join the
|
|
606
699
|
// actual provider continuation before either starting a turn-end capture
|
|
607
700
|
// or entering the proof-bearing holder release.
|
|
701
|
+
monitor.enter("workspace_snapshot");
|
|
608
702
|
await drainInFlightWarmSnapshot();
|
|
609
703
|
if (sandboxState.resolvedSandbox) {
|
|
610
704
|
// TURN-END mid-session snapshot (sandbox-file-persistence): fold the
|
|
@@ -622,7 +716,13 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
622
716
|
settledTurnId
|
|
623
717
|
) {
|
|
624
718
|
const snapshot = maybePersistWarmWorkspaceSnapshot(
|
|
625
|
-
{
|
|
719
|
+
{
|
|
720
|
+
db,
|
|
721
|
+
settings,
|
|
722
|
+
objectStorage,
|
|
723
|
+
sandboxMetrics: runtimeMetricsHooksForObservability(observability),
|
|
724
|
+
observability,
|
|
725
|
+
},
|
|
626
726
|
{
|
|
627
727
|
accountId: input.accountId,
|
|
628
728
|
workspaceId: input.workspaceId,
|
|
@@ -667,10 +767,13 @@ export async function finalizeTurnAttempt(deps: TurnFinalizationDeps): Promise<v
|
|
|
667
767
|
// Temporal cancellation: the eager listener may already have dropped
|
|
668
768
|
// the holder, and this idempotent proof-bearing pass still must run.
|
|
669
769
|
stopLeaseHeartbeat();
|
|
770
|
+
monitor.enter("sandbox_rotation");
|
|
670
771
|
if (sandboxState.rotationPreemptionInFlight) {
|
|
671
772
|
await sandboxState.rotationPreemptionInFlight.catch(() => undefined);
|
|
672
773
|
}
|
|
774
|
+
monitor.enter("workspace_snapshot");
|
|
673
775
|
await drainInFlightWarmSnapshot();
|
|
776
|
+
monitor.enter("sandbox_release");
|
|
674
777
|
const sandboxReleaseTargets = new Set(sandboxState.lateSandboxesAwaitingWriterDrain);
|
|
675
778
|
sandboxState.lateSandboxesAwaitingWriterDrain.clear();
|
|
676
779
|
if (sandboxState.resolvedSandbox) {
|
|
@@ -229,6 +229,8 @@ export type ApplyTurnGitHubRepositoryBindingsInput = {
|
|
|
229
229
|
workspaceId: string;
|
|
230
230
|
sessionId: string;
|
|
231
231
|
activeSandboxBackend: Settings["sandboxBackend"] | undefined;
|
|
232
|
+
/** Product-owned credentials take precedence over inferred platform bindings. */
|
|
233
|
+
hasCredentialProvider?: boolean;
|
|
232
234
|
claimedTurnResources: readonly ResourceRef[];
|
|
233
235
|
claimedRuntimeResources: readonly ResourceRef[];
|
|
234
236
|
/** Publishes one attempt-fenced session event batch. */
|
|
@@ -258,7 +260,7 @@ export async function applyTurnGitHubRepositoryBindings(
|
|
|
258
260
|
turnResources: [...input.claimedTurnResources],
|
|
259
261
|
runtimeResources: [...input.claimedRuntimeResources],
|
|
260
262
|
};
|
|
261
|
-
if (input.activeSandboxBackend === "selfhosted") {
|
|
263
|
+
if (input.activeSandboxBackend === "selfhosted" || input.hasCredentialProvider) {
|
|
262
264
|
return passthrough;
|
|
263
265
|
}
|
|
264
266
|
let resolved: TurnGitHubRepositoryBindings;
|