@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.
Files changed (244) hide show
  1. package/dist/activities/agent-run-admission.d.ts +3 -1
  2. package/dist/activities/agent-turn/admission.d.ts +24 -3
  3. package/dist/activities/agent-turn/agent-build.d.ts +4 -0
  4. package/dist/activities/agent-turn/claude-usage-observer.d.ts +58 -0
  5. package/dist/activities/agent-turn/code-search.d.ts +60 -0
  6. package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
  7. package/dist/activities/agent-turn/codex-plan-entitlement.d.ts +105 -0
  8. package/dist/activities/agent-turn/codex.d.ts +3 -2
  9. package/dist/activities/agent-turn/compaction-prep.d.ts +21 -5
  10. package/dist/activities/agent-turn/credential-leases.d.ts +19 -33
  11. package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
  12. package/dist/activities/agent-turn/errors.d.ts +82 -11
  13. package/dist/activities/agent-turn/failure-settlement.d.ts +6 -3
  14. package/dist/activities/agent-turn/final-reply.d.ts +18 -0
  15. package/dist/activities/agent-turn/finalization-monitor.d.ts +17 -0
  16. package/dist/activities/agent-turn/finalization.d.ts +4 -2
  17. package/dist/activities/agent-turn/github-repository-bindings.d.ts +2 -0
  18. package/dist/activities/agent-turn/governance-model.d.ts +9 -2
  19. package/dist/activities/agent-turn/history-sink.d.ts +2 -0
  20. package/dist/activities/agent-turn/history.d.ts +2 -0
  21. package/dist/activities/agent-turn/input-wait-reply.d.ts +41 -0
  22. package/dist/activities/agent-turn/media-artifacts.d.ts +5 -3
  23. package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
  24. package/dist/activities/agent-turn/model-usage.d.ts +6 -0
  25. package/dist/activities/agent-turn/model-wire-dispatch.d.ts +15 -0
  26. package/dist/activities/agent-turn/optional-repositories.d.ts +59 -0
  27. package/dist/activities/agent-turn/provider-dispatch-barrier.d.ts +12 -1
  28. package/dist/activities/agent-turn/quiescence.d.ts +7 -7
  29. package/dist/activities/agent-turn/recovery-warning.d.ts +9 -0
  30. package/dist/activities/agent-turn/refresh-credentials.d.ts +6 -0
  31. package/dist/activities/agent-turn/run-credentials.d.ts +8 -3
  32. package/dist/activities/agent-turn/sandbox-establish.d.ts +2 -1
  33. package/dist/activities/agent-turn/sandbox-provision.d.ts +3 -1
  34. package/dist/activities/agent-turn/sandbox-route.d.ts +3 -20
  35. package/dist/activities/agent-turn/sandbox-runtime.d.ts +2 -2
  36. package/dist/activities/agent-turn/session-title.d.ts +34 -2
  37. package/dist/activities/agent-turn/skill-checkout.d.ts +25 -6
  38. package/dist/activities/agent-turn/skill-read.d.ts +70 -2
  39. package/dist/activities/agent-turn/skill-remove.d.ts +14 -0
  40. package/dist/activities/agent-turn/skill-search.d.ts +3 -1
  41. package/dist/activities/agent-turn/skill-tools.d.ts +15 -2
  42. package/dist/activities/agent-turn/skill-transfer.d.ts +18 -6
  43. package/dist/activities/agent-turn/stream-attempt.d.ts +7 -3
  44. package/dist/activities/agent-turn/subscription-lease.d.ts +38 -0
  45. package/dist/activities/agent-turn/tool-environment.d.ts +56 -6
  46. package/dist/activities/agent-turn/tool-policy.d.ts +43 -0
  47. package/dist/activities/agent-turn/turn-context.d.ts +29 -0
  48. package/dist/activities/agent-turn/turn-sandbox-access.d.ts +3 -0
  49. package/dist/activities/agent-turn/xai-capacity.d.ts +2 -1
  50. package/dist/activities/automations.d.ts +3 -1
  51. package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
  52. package/dist/activities/codemode-dispatcher.d.ts +9 -2
  53. package/dist/activities/codex-capacity.d.ts +18 -2
  54. package/dist/activities/codex-rotation.d.ts +7 -1
  55. package/dist/activities/context-compaction.d.ts +16 -2
  56. package/dist/activities/gmail-files.d.ts +32 -0
  57. package/dist/activities/goals.d.ts +8 -0
  58. package/dist/activities/knowledge-indexing.d.ts +19 -0
  59. package/dist/activities/mcp-account-routes.d.ts +3 -0
  60. package/dist/activities/mcp-credentials.d.ts +12 -13
  61. package/dist/activities/mcp-operation-authority.d.ts +0 -5
  62. package/dist/activities/model-call-fact-reconciler.d.ts +34 -0
  63. package/dist/activities/open-suffix-resume.d.ts +13 -0
  64. package/dist/activities/parent-wake.d.ts +6 -12
  65. package/dist/activities/retained-screenshots.d.ts +7 -2
  66. package/dist/activities/rig-verification.d.ts +2 -3
  67. package/dist/activities/run-credential-renewal.d.ts +1 -0
  68. package/dist/activities/run-credentials.d.ts +15 -3
  69. package/dist/activities/sandbox-images.d.ts +1 -1
  70. package/dist/activities/sandbox-lease.d.ts +47 -9
  71. package/dist/activities/scheduled-tasks.d.ts +4 -35
  72. package/dist/activities/session-state.d.ts +70 -3
  73. package/dist/activities/types.d.ts +55 -6
  74. package/dist/activities/workspace-capture.d.ts +2 -0
  75. package/dist/activities/workspace-credential-provider.d.ts +46 -0
  76. package/dist/{activities-control-HMFGSKC5.js → activities-control-BNPTRTOE.js} +1896 -418
  77. package/dist/activities-control-BNPTRTOE.js.map +1 -0
  78. package/dist/activities-control.d.ts +182 -4
  79. package/dist/{activities-turn-AP67JADS.js → activities-turn-5LGZOSVU.js} +4476 -1327
  80. package/dist/activities-turn-5LGZOSVU.js.map +1 -0
  81. package/dist/activities.d.ts +182 -4
  82. package/dist/artifact-materializer-entry.js +5 -2
  83. package/dist/artifact-materializer-entry.js.map +1 -1
  84. package/dist/artifact-outbox-entry.js +5 -2
  85. package/dist/artifact-outbox-entry.js.map +1 -1
  86. package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
  87. package/dist/{chunk-A4XQWVZK.js → chunk-3ZTRWDMN.js} +307 -4
  88. package/dist/chunk-3ZTRWDMN.js.map +1 -0
  89. package/dist/{chunk-RAMNYSAW.js → chunk-4ER3YXOT.js} +22 -4
  90. package/dist/chunk-4ER3YXOT.js.map +1 -0
  91. package/dist/{chunk-CYITU5UH.js → chunk-LJX7Z2KP.js} +1445 -343
  92. package/dist/chunk-LJX7Z2KP.js.map +1 -0
  93. package/dist/editable-artifact-materializer-service.d.ts +2 -2
  94. package/dist/editable-artifact-outbox-service.d.ts +2 -2
  95. package/dist/host-export-pump.d.ts +3 -1
  96. package/dist/host-export.d.ts +1 -1
  97. package/dist/host-export.js +1 -1
  98. package/dist/http.d.ts +1 -1
  99. package/dist/index.d.ts +95 -3
  100. package/dist/index.js +137 -43
  101. package/dist/index.js.map +1 -1
  102. package/dist/observability-metrics.d.ts +118 -8
  103. package/dist/retained-process-diagnostics.d.ts +4 -0
  104. package/dist/retained-process-retry.d.ts +7 -0
  105. package/dist/sandbox-resume.d.ts +55 -13
  106. package/dist/sandbox-routing.d.ts +5 -3
  107. package/dist/sandbox-snapshot-diagnostics.d.ts +20 -0
  108. package/dist/session-event-fanout.d.ts +6 -0
  109. package/dist/warm-capture-holder.d.ts +3 -0
  110. package/dist/worker-service-lifecycle.d.ts +12 -0
  111. package/dist/workflow-bundle.js +273 -41
  112. package/dist/workflows/activities.d.ts +1 -1
  113. package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
  114. package/dist/workflows/scheduled-tasks.d.ts +4 -0
  115. package/dist/workflows/session.d.ts +36 -0
  116. package/dist/workflows.d.ts +1 -0
  117. package/package.json +21 -19
  118. package/src/activities/agent-run-admission.ts +17 -1
  119. package/src/activities/agent-turn/admission.ts +66 -3
  120. package/src/activities/agent-turn/agent-build.ts +84 -10
  121. package/src/activities/agent-turn/claim.ts +186 -43
  122. package/src/activities/agent-turn/claude-usage-observer.ts +221 -0
  123. package/src/activities/agent-turn/code-search.ts +275 -0
  124. package/src/activities/agent-turn/codex-capacity.ts +172 -8
  125. package/src/activities/agent-turn/codex-plan-entitlement.ts +254 -0
  126. package/src/activities/agent-turn/codex.ts +13 -5
  127. package/src/activities/agent-turn/compaction-prep.ts +170 -102
  128. package/src/activities/agent-turn/credential-leases.ts +122 -216
  129. package/src/activities/agent-turn/credential-restriction.ts +14 -0
  130. package/src/activities/agent-turn/errors.ts +647 -48
  131. package/src/activities/agent-turn/failure-settlement.ts +682 -130
  132. package/src/activities/agent-turn/final-reply.ts +46 -0
  133. package/src/activities/agent-turn/finalization-monitor.ts +120 -0
  134. package/src/activities/agent-turn/finalization.ts +146 -43
  135. package/src/activities/agent-turn/github-repository-bindings.ts +3 -1
  136. package/src/activities/agent-turn/governance-model.ts +69 -28
  137. package/src/activities/agent-turn/history-sink.ts +16 -2
  138. package/src/activities/agent-turn/history.ts +38 -11
  139. package/src/activities/agent-turn/input-wait-reply.ts +103 -0
  140. package/src/activities/agent-turn/knowledge-source-tools.ts +2 -0
  141. package/src/activities/agent-turn/media-artifacts.ts +2 -1
  142. package/src/activities/agent-turn/model-call-admission.ts +94 -0
  143. package/src/activities/agent-turn/model-usage.ts +64 -3
  144. package/src/activities/agent-turn/model-wire-dispatch.ts +27 -0
  145. package/src/activities/agent-turn/optional-repositories.ts +224 -0
  146. package/src/activities/agent-turn/provider-dispatch-barrier.ts +22 -0
  147. package/src/activities/agent-turn/quiescence.ts +10 -7
  148. package/src/activities/agent-turn/recovery-warning.ts +16 -0
  149. package/src/activities/agent-turn/refresh-credentials.ts +44 -0
  150. package/src/activities/agent-turn/run-credentials.ts +116 -55
  151. package/src/activities/agent-turn/run.ts +320 -93
  152. package/src/activities/agent-turn/sandbox-establish.ts +84 -8
  153. package/src/activities/agent-turn/sandbox-provision.ts +3 -1
  154. package/src/activities/agent-turn/sandbox-route.ts +4 -21
  155. package/src/activities/agent-turn/sandbox-runtime.ts +343 -18
  156. package/src/activities/agent-turn/session-title.ts +81 -5
  157. package/src/activities/agent-turn/skill-checkout.ts +111 -24
  158. package/src/activities/agent-turn/skill-install.ts +1 -1
  159. package/src/activities/agent-turn/skill-read.ts +374 -28
  160. package/src/activities/agent-turn/skill-remove.ts +46 -0
  161. package/src/activities/agent-turn/skill-save.ts +1 -1
  162. package/src/activities/agent-turn/skill-search.ts +10 -1
  163. package/src/activities/agent-turn/skill-selection.ts +4 -0
  164. package/src/activities/agent-turn/skill-tools.ts +112 -18
  165. package/src/activities/agent-turn/skill-transfer.ts +68 -23
  166. package/src/activities/agent-turn/stream-attempt.ts +313 -77
  167. package/src/activities/agent-turn/subscription-lease.ts +115 -0
  168. package/src/activities/agent-turn/tool-environment.ts +316 -167
  169. package/src/activities/agent-turn/tool-policy.ts +80 -1
  170. package/src/activities/agent-turn/turn-context.ts +35 -0
  171. package/src/activities/agent-turn/turn-sandbox-access.ts +7 -1
  172. package/src/activities/agent-turn/xai-capacity.ts +94 -51
  173. package/src/activities/automations.ts +76 -4
  174. package/src/activities/browser-deadline-checkpoint.ts +279 -0
  175. package/src/activities/capabilities.ts +108 -11
  176. package/src/activities/codemode-dispatcher.ts +36 -8
  177. package/src/activities/codex-capacity.ts +60 -25
  178. package/src/activities/codex-rotation.ts +39 -17
  179. package/src/activities/context-compaction.ts +75 -18
  180. package/src/activities/gmail-files.ts +88 -0
  181. package/src/activities/goals.ts +116 -121
  182. package/src/activities/google-drive-publication.ts +1 -3
  183. package/src/activities/image-generation-operation.ts +1 -1
  184. package/src/activities/knowledge-indexing.ts +269 -15
  185. package/src/activities/knowledge-source-sync.ts +10 -0
  186. package/src/activities/mcp-account-routes.ts +17 -0
  187. package/src/activities/mcp-credentials.ts +83 -194
  188. package/src/activities/mcp-operation-authority.ts +16 -41
  189. package/src/activities/model-call-fact-reconciler.ts +112 -0
  190. package/src/activities/open-suffix-resume.ts +15 -2
  191. package/src/activities/parent-wake.ts +46 -21
  192. package/src/activities/retained-screenshots.ts +82 -11
  193. package/src/activities/rig-verification.ts +38 -37
  194. package/src/activities/run-credential-renewal.ts +13 -1
  195. package/src/activities/run-credentials.ts +59 -17
  196. package/src/activities/run-input.ts +25 -16
  197. package/src/activities/sandbox-images.ts +0 -1
  198. package/src/activities/sandbox-lease.ts +798 -82
  199. package/src/activities/scheduled-tasks.ts +550 -178
  200. package/src/activities/session-state.ts +245 -6
  201. package/src/activities/site-auth-maintenance.ts +3 -0
  202. package/src/activities/types.ts +72 -5
  203. package/src/activities/workflow-wake.ts +2 -17
  204. package/src/activities/workspace-capture.ts +13 -2
  205. package/src/activities/workspace-credential-provider.ts +283 -0
  206. package/src/activities-control.ts +4 -0
  207. package/src/activities-turn.ts +5 -0
  208. package/src/activities.ts +13 -0
  209. package/src/activity-services.ts +16 -4
  210. package/src/browser-deadline-checkpoint-contract.ts +5 -0
  211. package/src/editable-artifact-hint-broker.ts +3 -0
  212. package/src/editable-artifact-materializer-service.ts +7 -3
  213. package/src/editable-artifact-outbox-service.ts +4 -4
  214. package/src/github-rest-mcp.ts +1 -2
  215. package/src/host-export-pump.ts +26 -4
  216. package/src/host-export.ts +3 -0
  217. package/src/http.ts +4 -2
  218. package/src/index.ts +99 -37
  219. package/src/observability-metrics.ts +510 -5
  220. package/src/personal-github-git-credentials.ts +2 -1
  221. package/src/pr-review-credentials.ts +1 -3
  222. package/src/retained-process-diagnostics.ts +50 -0
  223. package/src/retained-process-retry.ts +36 -0
  224. package/src/sandbox-resume.ts +388 -101
  225. package/src/sandbox-routing.ts +150 -25
  226. package/src/sandbox-snapshot-diagnostics.ts +112 -0
  227. package/src/session-event-fanout.ts +23 -0
  228. package/src/warm-capture-holder.ts +15 -0
  229. package/src/worker-service-lifecycle.ts +53 -0
  230. package/src/workflows/activities.ts +16 -1
  231. package/src/workflows/browser-deadline-checkpoint.ts +50 -0
  232. package/src/workflows/file-upload-reaper.ts +2 -0
  233. package/src/workflows/scheduled-tasks.ts +26 -13
  234. package/src/workflows/session.ts +242 -22
  235. package/src/workflows.ts +4 -0
  236. package/dist/activities/agent-turn/knowledge-sources.d.ts +0 -20
  237. package/dist/activities/packs.d.ts +0 -55
  238. package/dist/activities-control-HMFGSKC5.js.map +0 -1
  239. package/dist/activities-turn-AP67JADS.js.map +0 -1
  240. package/dist/chunk-A4XQWVZK.js.map +0 -1
  241. package/dist/chunk-CYITU5UH.js.map +0 -1
  242. package/dist/chunk-RAMNYSAW.js.map +0 -1
  243. package/src/activities/agent-turn/knowledge-sources.ts +0 -86
  244. package/src/activities/packs.ts +0 -166
@@ -8,6 +8,7 @@ const reaperActivity = proxyActivities<
8
8
  | "maintainRetainedScreenshots"
9
9
  | "maintainBrowserStateArtifacts"
10
10
  | "recoverVideoGenerationWorkflows"
11
+ | "reconcileRecentModelCallFacts"
11
12
  >
12
13
  >({
13
14
  startToCloseTimeout: "5 minutes",
@@ -20,4 +21,5 @@ export async function fileUploadReaperWorkflow(): Promise<void> {
20
21
  await reaperActivity.maintainRetainedScreenshots();
21
22
  await reaperActivity.maintainBrowserStateArtifacts();
22
23
  await reaperActivity.recoverVideoGenerationWorkflows();
24
+ await reaperActivity.reconcileRecentModelCallFacts();
23
25
  }
@@ -7,6 +7,7 @@ import {
7
7
  WorkflowIdReusePolicy,
8
8
  } from "@temporalio/workflow";
9
9
  import type { TurnInitiator } from "@opengeni/contracts";
10
+ import type { DispatchScheduledTaskRunInput } from "../activities/types";
10
11
  import { scheduledTaskActivity } from "./activities";
11
12
  import {
12
13
  knowledgeSourceSyncWake,
@@ -26,14 +27,38 @@ export type ScheduledTaskFireWorkflowInput = ScheduledTaskFireWorkflowBase &
26
27
  triggerType: "scheduled";
27
28
  agentRunUsageIdempotencyKey?: never;
28
29
  initiator?: never;
30
+ credentialRestriction?: never;
29
31
  }
30
32
  | {
31
33
  triggerType: "manual" | "initial" | "provider_event" | "retry" | "repair";
32
34
  agentRunUsageIdempotencyKey: string;
33
35
  initiator: TurnInitiator;
36
+ credentialRestriction?: "developer_setup";
34
37
  }
35
38
  );
36
39
 
40
+ export function scheduledTaskDispatchInput(
41
+ input: ScheduledTaskFireWorkflowInput,
42
+ producerKey: string,
43
+ ): DispatchScheduledTaskRunInput {
44
+ const base = {
45
+ workspaceId: input.workspaceId,
46
+ taskId: input.taskId,
47
+ producerKey,
48
+ };
49
+ return input.triggerType !== "scheduled"
50
+ ? {
51
+ ...base,
52
+ triggerType: input.triggerType,
53
+ agentRunUsageIdempotencyKey: input.agentRunUsageIdempotencyKey,
54
+ initiator: input.initiator,
55
+ ...(input.credentialRestriction === "developer_setup"
56
+ ? { credentialRestriction: input.credentialRestriction }
57
+ : {}),
58
+ }
59
+ : { ...base, triggerType: "scheduled" };
60
+ }
61
+
37
62
  export async function scheduledTaskFireWorkflow(
38
63
  input: ScheduledTaskFireWorkflowInput,
39
64
  ): Promise<void> {
@@ -47,20 +72,8 @@ export async function scheduledTaskFireWorkflow(
47
72
  ) {
48
73
  return;
49
74
  }
50
- const base = {
51
- workspaceId: input.workspaceId,
52
- taskId: input.taskId,
53
- producerKey: workflowInfo().workflowId,
54
- };
55
75
  const result = await scheduledTaskActivity.dispatchScheduledTaskRun(
56
- input.triggerType !== "scheduled"
57
- ? {
58
- ...base,
59
- triggerType: input.triggerType,
60
- agentRunUsageIdempotencyKey: input.agentRunUsageIdempotencyKey,
61
- initiator: input.initiator,
62
- }
63
- : { ...base, triggerType: "scheduled" },
76
+ scheduledTaskDispatchInput(input, workflowInfo().workflowId),
64
77
  );
65
78
  if (result.action !== "knowledge_source_sync") return;
66
79
 
@@ -58,6 +58,56 @@ const HUMAN_INPUT_EXPIRY_STALE_RETRY_MS = 1_000;
58
58
  */
59
59
  const ROTATION_IDLE_FLOOR_MS = 60_000; // 60s
60
60
 
61
+ /**
62
+ * Provider capacity waits are shared: every waiter of one exhausted pool learns
63
+ * the same authoritative reset time, and one capacity mutation (for example the
64
+ * bounded refresh that verifies a quota reset) wakes every waiter at once, both
65
+ * as the typed capacity signal and as the generic durable workflow wake. Without
66
+ * spread, a reset resumes the whole backlog in the same few seconds and its
67
+ * turns stampede sandbox creation and the provider. Each workflow therefore
68
+ * delays its reconciliation by a bounded, replay-deterministic (Temporal-seeded
69
+ * `Math.random`) jitter: up to one minute past a scheduled reset timer and up to
70
+ * 30 seconds after a capacity or queue wake or an already-due waiter. A wake
71
+ * that lands inside a waiter's timer spread does not shorten it. The Postgres
72
+ * waiter stays authoritative; jitter only delays the same reconciliation
73
+ * activity and never creates queue rows, input, or inference. Interruptions are
74
+ * never delayed.
75
+ *
76
+ * The patch marker is not understood by workers built before it: rolling the
77
+ * worker image back past this change while a session has recorded the marker
78
+ * (it waited on capacity in its current run) fails that workflow's tasks as
79
+ * nondeterministic until a patched worker returns.
80
+ */
81
+ export const CAPACITY_WAKE_JITTER_PATCH = "session-capacity-wake-jitter-v1";
82
+ /**
83
+ * A scheduled run's approval timeout sleeps on a durable Temporal timer. A
84
+ * history recorded by a worker that ignored the deadline has no timer command
85
+ * there, so replay only arms it behind this marker.
86
+ */
87
+ export const SCHEDULED_HUMAN_WAIT_TIMEOUT_PATCH = "session-scheduled-human-wait-timeout-v1";
88
+ export const CAPACITY_TIMER_WAKE_JITTER_MAX_MS = 60_000;
89
+ export const CAPACITY_WAKE_JITTER_MAX_MS = 30_000;
90
+
91
+ /**
92
+ * Pure + exported so the bound is unit-testable without a workflow environment.
93
+ * `overrideMaxMs` is the test-only SessionWorkflowInput ceiling; it can only
94
+ * narrow the production bound.
95
+ */
96
+ export function capacityWakeJitterMs(
97
+ kind: "timer" | "wake",
98
+ sample: number,
99
+ overrideMaxMs?: number,
100
+ ): number {
101
+ const productionMax =
102
+ kind === "timer" ? CAPACITY_TIMER_WAKE_JITTER_MAX_MS : CAPACITY_WAKE_JITTER_MAX_MS;
103
+ const max =
104
+ overrideMaxMs !== undefined && Number.isFinite(overrideMaxMs)
105
+ ? Math.min(productionMax, Math.max(0, Math.trunc(overrideMaxMs)))
106
+ : productionMax;
107
+ const unit = Number.isFinite(sample) ? Math.min(Math.max(sample, 0), 1 - Number.EPSILON) : 0;
108
+ return Math.floor(unit * max);
109
+ }
110
+
61
111
  /**
62
112
  * How long the continuation loop must hold before re-admitting the next turn. 0 ⇒ no
63
113
  * hold (re-dispatch immediately — a rotation candidate is ready, or no idle delay was
@@ -229,7 +279,15 @@ export function preClaimFailureDetail(error: unknown): PreClaimFailureDetail | u
229
279
  ) {
230
280
  return undefined;
231
281
  }
232
- const detail = cause.details?.[0] as { disposition?: unknown; code?: unknown } | undefined;
282
+ const detail = cause.details?.[0] as
283
+ | {
284
+ disposition?: unknown;
285
+ code?: unknown;
286
+ sqlState?: unknown;
287
+ reason?: unknown;
288
+ retryPolicy?: unknown;
289
+ }
290
+ | undefined;
233
291
  if (
234
292
  detail?.code !== "db_deadlock" &&
235
293
  detail?.code !== "db_serialization_failure" &&
@@ -239,6 +297,27 @@ export function preClaimFailureDetail(error: unknown): PreClaimFailureDetail | u
239
297
  return undefined;
240
298
  }
241
299
  const disposition = detail.disposition;
300
+ if (disposition === "blocked") {
301
+ if (
302
+ detail.code !== "db_failure" ||
303
+ detail.retryPolicy !== "explicit_recheck" ||
304
+ (detail.reason !== "database_claim_rejected" &&
305
+ detail.reason !== "initiator_membership_required" &&
306
+ detail.reason !== "personal_resource_grant_required") ||
307
+ !(
308
+ detail.sqlState === null ||
309
+ (typeof detail.sqlState === "string" && /^[0-9A-Z]{5}$/.test(detail.sqlState))
310
+ )
311
+ )
312
+ return undefined;
313
+ return {
314
+ disposition,
315
+ code: detail.code,
316
+ reason: detail.reason,
317
+ sqlState: detail.sqlState,
318
+ retryPolicy: "explicit_recheck",
319
+ };
320
+ }
242
321
  if (disposition !== "retryable" && disposition !== "permanent") return undefined;
243
322
  if (
244
323
  (detail.code === "db_deadlock" || detail.code === "db_serialization_failure") &&
@@ -286,6 +365,14 @@ export function postClaimDatabaseRecoveryDetail(
286
365
  const hasProviderRecoveryCount = detail.providerRecoveryCount !== undefined;
287
366
  const hasProviderFailureCode = detail.providerFailureCode !== undefined;
288
367
  if (
368
+ (detail.sandboxSetupOutcomeUnknown !== undefined &&
369
+ detail.sandboxSetupOutcomeUnknown !== true) ||
370
+ (detail.sandboxSetupRecoveryExhausted !== undefined &&
371
+ detail.sandboxSetupRecoveryExhausted !== true) ||
372
+ (detail.sandboxSetupOutcomeUnknown === true && detail.sandboxSetupRecoveryExhausted === true) ||
373
+ ((detail.sandboxSetupOutcomeUnknown === true ||
374
+ detail.sandboxSetupRecoveryExhausted === true) &&
375
+ hasProviderRecoveryCount) ||
289
376
  hasProviderRecoveryCount !== hasProviderFailureCode ||
290
377
  (hasProviderRecoveryCount &&
291
378
  (!Number.isSafeInteger(detail.providerRecoveryCount) ||
@@ -340,6 +427,9 @@ export type SessionWorkflowInput = {
340
427
  // Test-only override for the durable capacity-wait continue-as-new
341
428
  // backstop. Production uses CODEX_CAPACITY_CHECKS_PER_RUN_BACKSTOP.
342
429
  maxCapacityChecksPerRun?: number;
430
+ // Test-only ceiling for capacity-wake jitter (0 disables it) so real-server
431
+ // workflow tests stay fast. Production omits it and uses the bounds above.
432
+ capacityWakeJitterMaxMs?: number;
343
433
  };
344
434
 
345
435
  export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void> {
@@ -351,6 +441,7 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
351
441
  const preserveQuiescenceWake = patched("session-quiescence-reconciliation-wake-v1");
352
442
  const staleControlSignalIsOnlyWakeHint = patched("session-control-stale-wake-v1");
353
443
  const unclaimedAttemptRecovery = patched("session-unclaimed-attempt-recovery-v1");
444
+ let durableAdmissionBlocking = false;
354
445
  // PR #2208 changed a typed-cancelled result from a plain re-peek into a
355
446
  // recoverDispatch activity. Version that new command so histories which
356
447
  // already recorded the legacy re-peek remain deterministic on replay.
@@ -446,7 +537,14 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
446
537
  const timerMs = Number.isFinite(parsedDeadline)
447
538
  ? Math.max(0, parsedDeadline - Date.now())
448
539
  : 0;
540
+ const observedCause = (): activities.ReconcileCodexCapacityWaitInput["cause"] =>
541
+ wakeups !== seenWakeups
542
+ ? "queue"
543
+ : capacityWakeups !== seenCapacityWakeups
544
+ ? "signal"
545
+ : "timer";
449
546
  let cause: activities.ReconcileCodexCapacityWaitInput["cause"] = "timer";
547
+ let spread = false;
450
548
  if (wakeups !== seenWakeups) {
451
549
  cause = "queue";
452
550
  } else if (capacityWakeups !== seenCapacityWakeups) {
@@ -462,12 +560,48 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
462
560
  if (interruptionWakeups !== seenInterruptionWakeups) {
463
561
  return;
464
562
  }
465
- cause =
466
- wakeups !== seenWakeups
467
- ? "queue"
468
- : capacityWakeups !== seenCapacityWakeups
469
- ? "signal"
470
- : "timer";
563
+ cause = observedCause();
564
+ // Histories recorded before the jitter replay without the marker and
565
+ // reconcile right at the deadline, exactly as they did.
566
+ if (cause === "timer" && patched(CAPACITY_WAKE_JITTER_PATCH)) {
567
+ // The shared reset deadline itself fired. The first waiter to
568
+ // reconcile usually refreshes usage and wakes every other waiter; a
569
+ // waiter already inside its own spread keeps it instead of starting a
570
+ // second, shorter one, so the backlog resumes across the whole window.
571
+ spread = true;
572
+ const timerJitterMs = capacityWakeJitterMs(
573
+ "timer",
574
+ Math.random(),
575
+ input.capacityWakeJitterMaxMs,
576
+ );
577
+ if (timerJitterMs > 0) {
578
+ await condition(() => interruptionWakeups !== seenInterruptionWakeups, timerJitterMs);
579
+ if (interruptionWakeups !== seenInterruptionWakeups) {
580
+ return;
581
+ }
582
+ }
583
+ cause = observedCause();
584
+ }
585
+ }
586
+ if (!spread && patched(CAPACITY_WAKE_JITTER_PATCH)) {
587
+ // One capacity mutation wakes every waiter of the pool at once (the typed
588
+ // capacity signal and the generic durable wake), and a fresh run after
589
+ // continue-as-new, restart, or Resume sees every unobserved wake as an
590
+ // already-due waiter. Spread those reconciliations too. A later wake
591
+ // does not cut the pause short (that would re-synchronize the herd); a
592
+ // queued prompt stays behind the blocked turn either way, so only an
593
+ // interruption (Pause/Steer/Cancel) wins immediately.
594
+ const wakeJitterMs = capacityWakeJitterMs(
595
+ "wake",
596
+ Math.random(),
597
+ input.capacityWakeJitterMaxMs,
598
+ );
599
+ if (wakeJitterMs > 0) {
600
+ await condition(() => interruptionWakeups !== seenInterruptionWakeups, wakeJitterMs);
601
+ if (interruptionWakeups !== seenInterruptionWakeups) {
602
+ return;
603
+ }
604
+ }
471
605
  }
472
606
  const reconcileInput = {
473
607
  accountId: input.accountId,
@@ -506,6 +640,9 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
506
640
  ...(input.maxCapacityChecksPerRun !== undefined
507
641
  ? { maxCapacityChecksPerRun: input.maxCapacityChecksPerRun }
508
642
  : {}),
643
+ ...(input.capacityWakeJitterMaxMs !== undefined
644
+ ? { capacityWakeJitterMaxMs: input.capacityWakeJitterMaxMs }
645
+ : {}),
509
646
  });
510
647
  }
511
648
  current = result;
@@ -552,6 +689,9 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
552
689
  ...(input.maxCapacityChecksPerRun !== undefined
553
690
  ? { maxCapacityChecksPerRun: input.maxCapacityChecksPerRun }
554
691
  : {}),
692
+ ...(input.capacityWakeJitterMaxMs !== undefined
693
+ ? { capacityWakeJitterMaxMs: input.capacityWakeJitterMaxMs }
694
+ : {}),
555
695
  });
556
696
  }
557
697
  }
@@ -561,10 +701,51 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
561
701
  const closeSignalVersion = signalVersion;
562
702
  const closeNonControlSignalVersion = nonControlSignalVersion;
563
703
  const workflowId = workflowInfo().workflowId;
704
+ // Re-evaluate at the changed command, not only workflow entry. A replay
705
+ // without the marker keeps its old shape; the next live admission cycle
706
+ // can activate this fix without waiting for continueAsNew.
707
+ durableAdmissionBlocking = patched("session-durable-admission-block-v1");
708
+ const safeObservation = patched("session-safe-control-observation-v1");
564
709
  const peek = await activity.peekSessionWork({
565
710
  workspaceId: input.workspaceId,
566
711
  sessionId: input.sessionId,
712
+ ...(durableAdmissionBlocking ? { includeAdmissionFence: true } : {}),
713
+ ...(safeObservation ? { observerAccountId: input.accountId } : {}),
567
714
  });
715
+ if (peek.kind === "unavailable" || peek.kind === "attempt-owned") {
716
+ if (
717
+ peek.kind === "attempt-owned" &&
718
+ "ownerActivityState" in peek &&
719
+ peek.ownerActivityState === "settled" &&
720
+ patched("session-settled-owner-recovery-v1")
721
+ ) {
722
+ const reconciliation = await activity.reconcileSettledSessionAttempt({
723
+ accountId: input.accountId,
724
+ workspaceId: input.workspaceId,
725
+ sessionId: input.sessionId,
726
+ turnId: peek.turnId,
727
+ attemptId: peek.attemptId,
728
+ executionGeneration: peek.executionGeneration,
729
+ // Continue-as-new observers carry no owner authority. Always use
730
+ // the DB-stored original run/activity, not this observer's run.
731
+ workflowId: peek.activityRef.workflowId,
732
+ workflowRunId: peek.activityRef.workflowRunId,
733
+ activityId: peek.activityRef.activityId,
734
+ });
735
+ if (reconciliation.action === "recovering") continue;
736
+ if (reconciliation.action === "exceeded") return;
737
+ }
738
+ // No terminal/idle projection and no successor dispatch. Restoration
739
+ // need not produce a wake, so retain the observer with a bounded timer
740
+ // instead of closing and stranding durable work. Signals interrupt the
741
+ // wait; continue-as-new above bounds history, never business execution.
742
+ await condition(() => signalVersion !== closeSignalVersion, "30s");
743
+ continue;
744
+ }
745
+ if (peek.kind === "admission-blocked") {
746
+ if (signalVersion !== closeSignalVersion || pendingQuiescenceProofs.size > 0) continue;
747
+ return;
748
+ }
568
749
  if (peek.kind === "interruption-pending") {
569
750
  const settlement = await activity.settleSessionInterruptions({
570
751
  accountId: input.accountId,
@@ -630,6 +811,7 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
630
811
  const finalPeek = await activity.peekSessionWork({
631
812
  workspaceId: input.workspaceId,
632
813
  sessionId: input.sessionId,
814
+ ...(safeObservation ? { observerAccountId: input.accountId } : {}),
633
815
  });
634
816
  if (
635
817
  finalPeek.kind !== "sandbox-lifecycle-wait" ||
@@ -645,8 +827,13 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
645
827
  const seenApprovalWakeups = approvalWakeups;
646
828
  const seenWakeups = wakeups;
647
829
  const seenInterruptionWakeups = interruptionWakeups;
830
+ const scheduledRunTimeout =
831
+ peek.scheduledRunTimeout && peek.expiresAt && patched(SCHEDULED_HUMAN_WAIT_TIMEOUT_PATCH)
832
+ ? peek.scheduledRunTimeout
833
+ : undefined;
648
834
  const timeoutMs =
649
- (peek.humanInputRequestId || peek.interactionInterventionId) && peek.expiresAt
835
+ (peek.humanInputRequestId || peek.interactionInterventionId || scheduledRunTimeout) &&
836
+ peek.expiresAt
650
837
  ? humanInputDeadlineWaitMs(peek.expiresAt)
651
838
  : undefined;
652
839
  const wakeCondition = () =>
@@ -681,6 +868,20 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
681
868
  if (expiry.action === "stale") {
682
869
  await condition(wakeCondition, HUMAN_INPUT_EXPIRY_STALE_RETRY_MS);
683
870
  }
871
+ } else if (!woke && scheduledRunTimeout) {
872
+ // The scheduler answers for the unanswered person through the same
873
+ // acceptance boundary (a labelled system rejection/skip); the loop
874
+ // then re-peeks and resumes the turn like any decision.
875
+ const expiry = await activity.expireScheduledRunHumanWait({
876
+ accountId: input.accountId,
877
+ workspaceId: input.workspaceId,
878
+ sessionId: input.sessionId,
879
+ turnId: scheduledRunTimeout.turnId,
880
+ runId: scheduledRunTimeout.runId,
881
+ });
882
+ if (expiry.action === "stale") {
883
+ await condition(wakeCondition, HUMAN_INPUT_EXPIRY_STALE_RETRY_MS);
884
+ }
684
885
  }
685
886
  continue;
686
887
  }
@@ -695,8 +896,8 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
695
896
  if (settlement.action !== "held") continue;
696
897
 
697
898
  // The durable outbox owns the long deadline. Keep this workflow run open
698
- // only for the same bounded close-race window used by ordinary idle; any
699
- // signal is a hint to re-peek PostgreSQL truth.
899
+ // for its bounded close-race window; unlike ordinary idle, this held-wait
900
+ // path is unchanged. Any signal is a hint to re-peek PostgreSQL truth.
700
901
  const seenWakeups = wakeups;
701
902
  const seenApprovalWakeups = approvalWakeups;
702
903
  const seenInterruptionWakeups = interruptionWakeups;
@@ -711,6 +912,7 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
711
912
  const finalPeek = await activity.peekSessionWork({
712
913
  workspaceId: input.workspaceId,
713
914
  sessionId: input.sessionId,
915
+ ...(safeObservation ? { observerAccountId: input.accountId } : {}),
714
916
  });
715
917
  if (
716
918
  finalPeek.kind !== "input-wait" ||
@@ -749,20 +951,28 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
749
951
  // idle-backoff goal keeps its durable obligation armed; the delayed
750
952
  // wake-outbox row at the pacing deadline or any producer signal restarts
751
953
  // the workflow. No Temporal timer is used for pacing.
752
- const seenWakeups = wakeups;
753
- const seenApprovalWakeups = approvalWakeups;
754
- const seenInterruptionWakeups = interruptionWakeups;
755
- const woke = await condition(
756
- () =>
757
- interruptionWakeups !== seenInterruptionWakeups ||
758
- wakeups !== seenWakeups ||
759
- approvalWakeups !== seenApprovalWakeups,
760
- "5s",
761
- );
762
- if (woke) continue;
954
+ // Evaluate at the changed command so old recorded timers still replay,
955
+ // while the next live idle cycle can close without a grace period.
956
+ if (!patched("session-normal-idle-no-grace-v1")) {
957
+ const seenWakeups = wakeups;
958
+ const seenApprovalWakeups = approvalWakeups;
959
+ const seenInterruptionWakeups = interruptionWakeups;
960
+ const woke = await condition(
961
+ () =>
962
+ interruptionWakeups !== seenInterruptionWakeups ||
963
+ wakeups !== seenWakeups ||
964
+ approvalWakeups !== seenApprovalWakeups,
965
+ "5s",
966
+ );
967
+ if (woke) continue;
968
+ }
969
+ // Keep both the durable recheck and the transactional idle/parent-outbox
970
+ // fence. A signal accepted during this activity chain makes us loop;
971
+ // later work restarts the same session via durable signalWithStart.
763
972
  const finalPeek = await activity.peekSessionWork({
764
973
  workspaceId: input.workspaceId,
765
974
  sessionId: input.sessionId,
975
+ ...(safeObservation ? { observerAccountId: input.accountId } : {}),
766
976
  });
767
977
  if (finalPeek.kind !== "idle") continue;
768
978
  await activity.markSessionIdle({
@@ -779,7 +989,15 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
779
989
  peek.kind === "approval-pending"
780
990
  ? ({ kind: "approval", triggerEventId: peek.triggerEventId } as const)
781
991
  : ({ kind: "next" } as const);
782
- if (!(await runTurn(input.accountId, input.workspaceId, input.sessionId, trigger))) {
992
+ if (
993
+ !(await runTurn(
994
+ input.accountId,
995
+ input.workspaceId,
996
+ input.sessionId,
997
+ trigger,
998
+ "admissionFence" in peek ? peek.admissionFence : undefined,
999
+ ))
1000
+ ) {
783
1001
  if (signalVersion !== closeSignalVersion) continue;
784
1002
  return;
785
1003
  }
@@ -790,6 +1008,7 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
790
1008
  workspaceId: string,
791
1009
  sessionId: string,
792
1010
  trigger: activities.RunAgentTurnInput["trigger"],
1011
+ admissionFence?: activities.FailSessionAttemptInput["admissionFence"],
793
1012
  ): Promise<boolean> {
794
1013
  const capacityWaitEntryBaseline = { wakeups, capacityWakeups };
795
1014
  // Capture every admission-relevant signal before activity dispatch. A
@@ -1072,6 +1291,7 @@ export async function sessionWorkflow(input: SessionWorkflowInput): Promise<void
1072
1291
  ? { preClaimFailureDisposition: admissionFailureDisposition }
1073
1292
  : {}),
1074
1293
  ...(admissionFailure ? { preClaimFailure: admissionFailure } : {}),
1294
+ ...(durableAdmissionBlocking && admissionFence ? { admissionFence } : {}),
1075
1295
  ...(postClaimDatabaseRecovery ? { postClaimDatabaseRecovery } : {}),
1076
1296
  trigger,
1077
1297
  error: workflowFailureMessage(outcome.error),
package/src/workflows.ts CHANGED
@@ -28,6 +28,10 @@ export {
28
28
  sandboxReaperWorkflowV2,
29
29
  } from "./workflows/sandbox-reaper";
30
30
  export { fileUploadReaperWorkflow } from "./workflows/file-upload-reaper";
31
+ export {
32
+ browserDeadlineCheckpointWorkflow,
33
+ browserDeadlineCheckpointSweepWorkflow,
34
+ } from "./workflows/browser-deadline-checkpoint";
31
35
  export { siteAuthMaintenanceWorkflow } from "./workflows/site-auth-maintenance";
32
36
  export {
33
37
  videoGenerationWorkflow,
@@ -1,20 +0,0 @@
1
- import { type FirstPartyMcpToolName, type Permission, type ResourceRef, type KnowledgeFilePreparationResult } from "@opengeni/contracts";
2
- import { type Settings } from "@opengeni/config";
3
- import { createFirstPartyAttemptClient } from "@opengeni/runtime";
4
- export type KnowledgeSourcePreparationOutcome = KnowledgeFilePreparationResult | {
5
- status: "failed";
6
- fileId: string;
7
- message: string;
8
- };
9
- /** Accepted chat/schedule resources use ordinary agent authority and policy. */
10
- export declare function prepareTurnKnowledgeSources(input: {
11
- settings: Settings;
12
- scope: Parameters<typeof createFirstPartyAttemptClient>[0]["scope"];
13
- resources: readonly ResourceRef[];
14
- selectedTools?: readonly FirstPartyMcpToolName[] | undefined;
15
- permissions?: readonly Permission[] | null | undefined;
16
- learningMode: "automatic" | "review_first" | "off";
17
- signal?: AbortSignal | undefined;
18
- onOutcome: (outcome: KnowledgeSourcePreparationOutcome) => Promise<void>;
19
- prepare?: (fileId: string) => Promise<KnowledgeFilePreparationResult>;
20
- }): Promise<string | undefined>;
@@ -1,55 +0,0 @@
1
- import { CapabilityPack } from "@opengeni/contracts";
2
- import { type Database } from "@opengeni/db";
3
- import { packInstallationUsesLegacyRuntime } from "@opengeni/core";
4
- import { type InstalledSkillActivation, type PackSkillActivation } from "@opengeni/runtime";
5
- export { resolveRigProviderImageSelection, rigProviderImageSourceImage, settingsWithPackSandboxImage, settingsWithRigImage, settingsWithRigProviderImage, } from "./sandbox-images.js";
6
- export { packInstallationUsesLegacyRuntime };
7
- /**
8
- * Legacy pack-scoped runtime compatibility. V2 Pack installations own ordinary
9
- * Skill components and select an explicit Rig; they contribute nothing here.
10
- */
11
- export type WorkspacePackRuntime = {
12
- sandboxImage: string | null;
13
- sandboxProviderImages: CapabilityPack["sandboxProviderImages"] | null;
14
- skillActivations: PackSkillActivation[];
15
- };
16
- export type WorkspaceInstalledSkillRuntime = {
17
- activations: InstalledSkillActivation[];
18
- };
19
- /**
20
- * Resolves only pre-V2 active Pack installations. A frozen manifest/digest is
21
- * the protocol marker for V2: inline Skills were migrated into the ordinary
22
- * Skill ledger and sandboxImage was resolved to selectedRigId during install,
23
- * so reading either field directly here would duplicate ownership and silently
24
- * override session compute.
25
- */
26
- export declare function resolveWorkspacePackRuntime(db: Database, workspaceId: string): Promise<WorkspacePackRuntime>;
27
- /**
28
- * Resolves every active immutable Skill through the normalized Plugin/Skill-
29
- * Facet ledger. The data layer has already filtered ineffective owner edges;
30
- * this boundary independently verifies exact files before runtime activation.
31
- */
32
- export declare function resolveWorkspaceInstalledSkillRuntime(db: Database, workspaceId: string): Promise<WorkspaceInstalledSkillRuntime>;
33
- /**
34
- * Pure pre-V2 compatibility rule for enabled Pack manifests. At most one
35
- * legacy Pack may declare a sandbox image, and legacy Skill names must be
36
- * unique. V2 rows never reach this function through runtime resolution.
37
- */
38
- export declare function workspacePackRuntimeFromPacks(packs: CapabilityPack[]): WorkspacePackRuntime;
39
- /**
40
- * Resolves the per-workspace agent persona override (the white-label surface).
41
- * Returns the workspace's stored template when set, else null to mean "use the
42
- * deployment default" (settings.agentInstructionsTemplate). The runtime always
43
- * injects the non-bypassable CORE regardless, so a null here keeps the
44
- * byte-identical default and a non-null value only restyles the persona.
45
- *
46
- * This is the workspace tier of the session > workspace > deployment-default
47
- * resolution; per-session overrides do not exist in this slice, so the worker
48
- * resolves workspace > default and passes the result as instructionsTemplate.
49
- */
50
- export declare function resolveWorkspaceAgentInstructions(db: Database, workspaceId: string): Promise<string | null>;
51
- /**
52
- * Applies a pack-declared sandbox image to run settings. With no pack image
53
- * the settings pass through untouched, so deployments without packs keep the
54
- * global OPENGENI_DOCKER_IMAGE / OPENGENI_MODAL_IMAGE_REF behavior exactly.
55
- */