@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
@@ -1,8 +1,24 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { errorCodeToJSON } from "@opengeni/agent-proto";
3
- import { SandboxBackend, type SessionEventType } from "@opengeni/contracts";
4
- import type { SessionEventAppendPhaseObservation } from "@opengeni/db";
5
- import type { EventLogger } from "@opengeni/events";
3
+ import {
4
+ BundledSkillId,
5
+ CREDIT_GRANT_CLASSES,
6
+ SandboxBackend,
7
+ type SessionEventType,
8
+ type SkillReadKind,
9
+ type SkillUseSource,
10
+ } from "@opengeni/contracts";
11
+ import {
12
+ ACTIVE_USER_WINDOWS,
13
+ type ActiveUserWindow,
14
+ type CreditGrantTotals,
15
+ type SessionEventAppendPhaseObservation,
16
+ } from "@opengeni/db";
17
+ import {
18
+ natsSubscriptionTerminationCounter,
19
+ type EventBusOptions,
20
+ type EventLogger,
21
+ } from "@opengeni/events";
6
22
  import type { Attributes, AttributeValue, Observability } from "@opengeni/observability";
7
23
  import type { CompanyBrainContributionReceipt } from "./model-context-contributions";
8
24
  import {
@@ -16,6 +32,7 @@ import {
16
32
  type RuntimeMetricsHooks,
17
33
  type SelfhostedOpObservation,
18
34
  type SelfhostedOpObserver,
35
+ type ToolPreparationPhaseMeasurement,
19
36
  } from "@opengeni/runtime";
20
37
 
21
38
  export type TurnOutcome = "completed" | "failed" | "cancelled" | "recovering";
@@ -79,6 +96,16 @@ const CONTEXT_COMPACTIONS_METRIC = {
79
96
  help: "Total completed context compactions, by trigger.",
80
97
  } as const;
81
98
 
99
+ /** Logger plus the closed-label subscription-termination counter for NATS connections. */
100
+ export function observabilityEventBusOptions(
101
+ observability: Observability,
102
+ ): Pick<EventBusOptions, "logger" | "onSubscriptionTerminated"> {
103
+ return {
104
+ logger: observabilityEventLogger(observability),
105
+ onSubscriptionTerminated: natsSubscriptionTerminationCounter(observability),
106
+ };
107
+ }
108
+
82
109
  export function observabilityEventLogger(observability: Observability): EventLogger {
83
110
  return {
84
111
  debug: (message, attributes) => observability.debug(message, eventAttributes(attributes)),
@@ -119,6 +146,10 @@ export function runtimeMetricsHooksForObservability(
119
146
  ): RuntimeMetricsHooks {
120
147
  return {
121
148
  onModelCall: ({ provider, outcome, durationSeconds }) => {
149
+ completedOperationSpan(observability, "worker.model.call", durationSeconds, {
150
+ provider,
151
+ outcome,
152
+ });
122
153
  observability.incrementCounter({
123
154
  name: "opengeni_model_calls_total",
124
155
  help: "Total model calls by provider and outcome.",
@@ -151,6 +182,13 @@ export function runtimeMetricsHooksForObservability(
151
182
  labels: { backend, stage },
152
183
  });
153
184
  },
185
+ onSandboxReadinessReplacement: ({ backend, outcome }) => {
186
+ observability.incrementCounter({
187
+ name: "opengeni_sandbox_readiness_replacements_total",
188
+ help: "Fresh sandbox command-readiness replacement decisions by backend and outcome.",
189
+ labels: { backend, outcome },
190
+ });
191
+ },
154
192
  onSandboxProviderApiThrottle: ({ backend, operation }) => {
155
193
  observability.incrementCounter({
156
194
  name: "opengeni_sandbox_provider_api_throttles_total",
@@ -172,6 +210,20 @@ export function runtimeMetricsHooksForObservability(
172
210
  labels: { outcome, port: String(port) },
173
211
  });
174
212
  },
213
+ onWorkspaceCapture: ({ backend, outcome, durationSeconds }) => {
214
+ if (!Number.isFinite(durationSeconds) || durationSeconds < 0) return;
215
+ const safeBackend = SandboxBackend.safeParse(backend).success ? backend : "unknown";
216
+ completedOperationSpan(observability, "worker.workspace_capture", durationSeconds, {
217
+ backend: safeBackend,
218
+ outcome,
219
+ });
220
+ observability.observeHistogram({
221
+ name: "opengeni_workspace_capture_duration_seconds",
222
+ help: "Physical warm workspace capture and publication duration, including late settlement after caller timeout.",
223
+ labels: { backend: safeBackend, outcome },
224
+ value: durationSeconds,
225
+ });
226
+ },
175
227
  onWorkspaceArchiveObject: ({ outcome, backend }) => {
176
228
  observability.incrementCounter({
177
229
  name: "opengeni_workspace_archive_object_total",
@@ -180,6 +232,7 @@ export function runtimeMetricsHooksForObservability(
180
232
  });
181
233
  },
182
234
  onMcpToolCall: ({ outcome, durationSeconds }) => {
235
+ completedOperationSpan(observability, "worker.mcp.tool_call", durationSeconds, { outcome });
183
236
  observability.incrementCounter({
184
237
  name: "opengeni_mcp_tool_calls_total",
185
238
  help: "Total physical MCP tool calls by bounded structural outcome.",
@@ -1013,6 +1066,7 @@ export function recordOpenSandboxKubernetesInventoryGauges(
1013
1066
  export const SANDBOX_INVENTORY_PROJECTION_DOMAINS = [
1014
1067
  "leases",
1015
1068
  "checkpoint_artifacts",
1069
+ "recovery_observations",
1016
1070
  "rotation_backlog",
1017
1071
  "retained_processes",
1018
1072
  "expired_drains",
@@ -1074,6 +1128,106 @@ export function recordCreditBalanceGauges(
1074
1128
  creditBalanceGaugeAccounts.set(observability, current);
1075
1129
  }
1076
1130
 
1131
+ /**
1132
+ * Distinct managed people with authenticated browser activity in each fixed
1133
+ * window (migration 0565 presence). Every control worker publishes the same
1134
+ * global value, so dashboards must aggregate with `max()` across pods, never
1135
+ * `sum()`. API keys, services and embedded hosts are never counted.
1136
+ */
1137
+ export function recordActiveUserGauges(
1138
+ observability: Observability,
1139
+ counts: Record<ActiveUserWindow, number>,
1140
+ ): void {
1141
+ for (const window of ACTIVE_USER_WINDOWS) {
1142
+ observability.setGauge({
1143
+ name: "opengeni_active_users",
1144
+ help: "Distinct managed users with authenticated activity within the window (global; use max across pods).",
1145
+ labels: { window },
1146
+ value: counts[window],
1147
+ });
1148
+ }
1149
+ }
1150
+
1151
+ /**
1152
+ * Positive credit grants observed by the ledger trigger since migration 0565,
1153
+ * by closed class. These are cumulative database totals published as gauges by
1154
+ * every control worker: aggregate with `max()` across pods, then `increase()`.
1155
+ * Counting in the database covers the grants no application process writes:
1156
+ * the verified-signup trial grant (a setup trigger) and operator grants.
1157
+ */
1158
+ export function recordCreditGrantGauges(
1159
+ observability: Observability,
1160
+ totals: CreditGrantTotals,
1161
+ ): void {
1162
+ for (const grantClass of CREDIT_GRANT_CLASSES) {
1163
+ const total = totals[grantClass];
1164
+ observability.setGauge({
1165
+ name: "opengeni_credit_grants_total",
1166
+ help: "Positive credit grants observed in the ledger since migration 0565, by grant class (global cumulative; use max across pods).",
1167
+ labels: { grant_class: grantClass },
1168
+ value: total.count,
1169
+ });
1170
+ observability.setGauge({
1171
+ name: "opengeni_credit_granted_micros_total",
1172
+ help: "Credit micros granted in the ledger since migration 0565, by grant class (global cumulative; use max across pods).",
1173
+ labels: { grant_class: grantClass },
1174
+ value: total.micros,
1175
+ });
1176
+ }
1177
+ }
1178
+
1179
+ /**
1180
+ * The deployment-level runtime switch for the one-time verified signup trial
1181
+ * credit (migration 0521): 1 while it allows grants, 0 when an operator has
1182
+ * disabled it or no revision exists. A grant also needs the API's
1183
+ * OPENGENI_VERIFIED_SIGNUP_TRIAL_CREDITS_ENABLED master opt-in, which
1184
+ * {@link recordVerifiedSignupTrialDeploymentFlagGauge} reports separately.
1185
+ */
1186
+ export function recordVerifiedSignupTrialSwitchGauge(
1187
+ observability: Observability,
1188
+ grantsEnabled: boolean,
1189
+ ): void {
1190
+ observability.setGauge({
1191
+ name: "opengeni_verified_signup_trial_credits_runtime_enabled",
1192
+ help: "Whether the runtime switch allows new verified signup trial credit grants (1) or blocks them (0).",
1193
+ value: grantsEnabled ? 1 : 0,
1194
+ });
1195
+ }
1196
+
1197
+ /**
1198
+ * The deployment-level runtime switch for new managed account sign-ups
1199
+ * (migration 0585): 1 while it allows new accounts (also when no revision
1200
+ * exists), 0 when an operator has paused them. The API additionally honours
1201
+ * its OPENGENI_MANAGED_AUTH_NEW_SIGNUPS_ENABLED ceiling, which this gauge does
1202
+ * not see; `GET /v1/config/client` reports the combined decision.
1203
+ */
1204
+ export function recordManagedAuthNewSignupsSwitchGauge(
1205
+ observability: Observability,
1206
+ signupsEnabled: boolean,
1207
+ ): void {
1208
+ observability.setGauge({
1209
+ name: "opengeni_managed_auth_new_signups_runtime_enabled",
1210
+ help: "Whether the runtime switch allows new managed account sign-ups (1) or has paused them (0).",
1211
+ value: signupsEnabled ? 1 : 0,
1212
+ });
1213
+ }
1214
+
1215
+ /**
1216
+ * The OPENGENI_VERIFIED_SIGNUP_TRIAL_CREDITS_ENABLED master opt-in as this
1217
+ * worker's configuration sees it. The API reads the same shared setting; new
1218
+ * grants happen only while this gauge and the runtime switch gauge are both 1.
1219
+ */
1220
+ export function recordVerifiedSignupTrialDeploymentFlagGauge(
1221
+ observability: Observability,
1222
+ enabled: boolean,
1223
+ ): void {
1224
+ observability.setGauge({
1225
+ name: "opengeni_verified_signup_trial_credits_deployment_enabled",
1226
+ help: "Whether the OPENGENI_VERIFIED_SIGNUP_TRIAL_CREDITS_ENABLED master opt-in is on (1) or off (0) in this deployment's configuration.",
1227
+ value: enabled ? 1 : 0,
1228
+ });
1229
+ }
1230
+
1077
1231
  export function recordSandboxOrphansTerminated(observability: Observability, count: number): void {
1078
1232
  if (count <= 0) {
1079
1233
  return;
@@ -1149,6 +1303,101 @@ export function recordSandboxDeadlineRotationsRequested(
1149
1303
  });
1150
1304
  }
1151
1305
 
1306
+ /** Fixed outcomes of legacy retained-command containment: per-candidate
1307
+ * enrollment inspection, then the enrolled drain's exact cold commit. */
1308
+ export const SANDBOX_COMMAND_CONTAINMENT_OUTCOMES = [
1309
+ "idle_enrolled",
1310
+ "deadline_enrolled",
1311
+ "resumed_enrolled",
1312
+ "not_eligible",
1313
+ "inspection_failed",
1314
+ "contained",
1315
+ "provider_missing",
1316
+ ] as const;
1317
+
1318
+ export type SandboxCommandContainmentOutcome =
1319
+ (typeof SANDBOX_COMMAND_CONTAINMENT_OUTCOMES)[number];
1320
+
1321
+ export function recordSandboxCommandContainment(
1322
+ observability: Observability,
1323
+ outcome: SandboxCommandContainmentOutcome,
1324
+ ): void {
1325
+ observability.incrementCounter({
1326
+ name: "opengeni_sandbox_command_containment_total",
1327
+ help: "Legacy retained-command containment inspections and enrolled drain commits by fixed outcome.",
1328
+ labels: { outcome },
1329
+ });
1330
+ }
1331
+
1332
+ /** Only call after the exact draining->cold commit reports wentCold. The
1333
+ * backend is validated against the closed contract so provider IDs and other
1334
+ * per-sandbox values can never become metric labels. */
1335
+ export function recordSandboxProviderMissingBeforeCapture(
1336
+ observability: Observability,
1337
+ backend: string,
1338
+ ): void {
1339
+ const safeBackend = SandboxBackend.safeParse(backend).success ? backend : "unknown";
1340
+ observability.incrementCounter({
1341
+ name: "opengeni_sandbox_provider_missing_before_capture_total",
1342
+ help: "Exact sandbox cold commits after definitive provider disappearance before workspace capture.",
1343
+ labels: { backend: safeBackend },
1344
+ });
1345
+ }
1346
+
1347
+ export function recordSandboxRecoveryObservationGauges(
1348
+ observability: Observability,
1349
+ observations: {
1350
+ providerLosses: number;
1351
+ fallbackSelections: number;
1352
+ freshWorkspaceSelections?: number;
1353
+ },
1354
+ ): void {
1355
+ for (const [kind, value] of [
1356
+ ["provider_missing_before_capture", observations.providerLosses],
1357
+ ["checkpoint_fallback_selected", observations.fallbackSelections],
1358
+ ["fresh_workspace_selected", observations.freshWorkspaceSelections ?? 0],
1359
+ ] as const) {
1360
+ observability.setGauge({
1361
+ name: "opengeni_sandbox_recovery_observations_recent",
1362
+ help: "Committed sandbox recovery observations in the last 30 minutes by fixed kind.",
1363
+ labels: { kind },
1364
+ value,
1365
+ });
1366
+ }
1367
+ }
1368
+
1369
+ /** Fixed outcomes for a committed automatic continuity decision after
1370
+ * definitive managed-provider loss: a singleton checkpoint (`selected`), a
1371
+ * shared-group checkpoint (`selected_shared`), or a new empty workspace
1372
+ * (`fresh_workspace`). Call only after the durable authorization committed. */
1373
+ export const SANDBOX_AUTOMATIC_RECOVERY_OUTCOMES = [
1374
+ "selected",
1375
+ "selected_shared",
1376
+ "fresh_workspace",
1377
+ ] as const;
1378
+ export type SandboxAutomaticRecoveryOutcome = (typeof SANDBOX_AUTOMATIC_RECOVERY_OUTCOMES)[number];
1379
+
1380
+ export function sandboxAutomaticRecoveryOutcome(input: {
1381
+ lane: "checkpoint" | "fresh_workspace";
1382
+ groupSessionCount: number;
1383
+ }): SandboxAutomaticRecoveryOutcome {
1384
+ if (input.lane === "fresh_workspace") return "fresh_workspace";
1385
+ return input.groupSessionCount > 1 ? "selected_shared" : "selected";
1386
+ }
1387
+
1388
+ export function recordSandboxAutomaticRecoverySelected(
1389
+ observability: Observability,
1390
+ backend: string,
1391
+ outcome: SandboxAutomaticRecoveryOutcome,
1392
+ ): void {
1393
+ const safeBackend = SandboxBackend.safeParse(backend).success ? backend : "unknown";
1394
+ observability.incrementCounter({
1395
+ name: "opengeni_sandbox_checkpoint_fallback_total",
1396
+ help: "System-selected continuity after managed provider loss: verified checkpoint or empty workspace.",
1397
+ labels: { backend: safeBackend, outcome },
1398
+ });
1399
+ }
1400
+
1152
1401
  export function recordSandboxRotationBacklogGauges(
1153
1402
  observability: Observability,
1154
1403
  backlog: {
@@ -1266,6 +1515,7 @@ export function recordExpiredDrainingSandboxLeaseGauges(
1266
1515
 
1267
1516
  export const RETAINED_PROCESS_RECONCILIATION_OUTCOMES = [
1268
1517
  "claim_failed",
1518
+ "background_recovered",
1269
1519
  "proof_exited",
1270
1520
  "proof_lost",
1271
1521
  "proof_checkpoint_failed",
@@ -1353,10 +1603,18 @@ export function recordModelRequestPhase(
1353
1603
  }
1354
1604
 
1355
1605
  export type TurnStartupPhase =
1606
+ | "services_initialization"
1607
+ | "claim_catalog_read"
1608
+ | "claim_atomic"
1609
+ | "claim_session_read"
1610
+ | "claim_capability_settings"
1611
+ | "learning_policy_freeze"
1612
+ | "attachment_authority_projection"
1356
1613
  | "claim_and_policy"
1357
1614
  | "turn_start_settlement"
1358
1615
  | "credential_selection"
1359
1616
  | "runtime_preparation"
1617
+ | "session_mcp_settings"
1360
1618
  | "sandbox_establish"
1361
1619
  | "file_resolution"
1362
1620
  | "tool_context_preparation"
@@ -1386,7 +1644,7 @@ export type TurnStartupPhase =
1386
1644
  | "history_generated_image_materialization"
1387
1645
  | "history_position_load"
1388
1646
  | "owned_sandbox_setup"
1389
- | "provider_dispatch"
1647
+ | "runtime_stream_initialization"
1390
1648
  | "model_request_preparation"
1391
1649
  | "model_sdk_serialization"
1392
1650
  | "model_prepare_sandbox_agent_preparation"
@@ -1492,7 +1750,8 @@ export function turnStartupCountBucket(count: number | null): TurnStartupCountBu
1492
1750
  }
1493
1751
 
1494
1752
  /**
1495
- * Measure the critical path from a durable turn start to provider dispatch.
1753
+ * Measure startup operations, including nested and parallel work. These are
1754
+ * not additive critical-path intervals; use milestones for elapsed latency.
1496
1755
  * Every label is a closed or configuration-derived enum; high-cardinality turn,
1497
1756
  * session, credential, connection, file, and model identifiers are forbidden.
1498
1757
  */
@@ -1506,8 +1765,19 @@ export function recordTurnStartupPhase(
1506
1765
  durationSeconds: number;
1507
1766
  count?: number | null;
1508
1767
  cache?: TurnStartupCache;
1768
+ /** Trace-only lookup for the completed claim while its execution root is still open. */
1769
+ executionCorrelationId?: string;
1509
1770
  },
1510
1771
  ): void {
1772
+ completedOperationSpan(observability, `worker.prepare.${input.phase}`, input.durationSeconds, {
1773
+ provider: input.provider,
1774
+ backend: input.backend,
1775
+ outcome: input.outcome,
1776
+ ...(input.phase === "claim_and_policy" &&
1777
+ /^turn_[0-9a-f]{32}$/.test(input.executionCorrelationId ?? "")
1778
+ ? { correlationId: input.executionCorrelationId }
1779
+ : {}),
1780
+ });
1511
1781
  observability.observeHistogram({
1512
1782
  name: "opengeni_turn_startup_phase_duration_seconds",
1513
1783
  help: "Turn startup phase duration before the model response stream begins.",
@@ -1524,6 +1794,103 @@ export function recordTurnStartupPhase(
1524
1794
  });
1525
1795
  }
1526
1796
 
1797
+ /** Observe an existing dependency only. Child intervals can overlap and are
1798
+ * not additive; observer failure must never change authority or error identity. */
1799
+ export async function measureTurnStartupPhase<T>(
1800
+ observability: Observability,
1801
+ input: Omit<Parameters<typeof recordTurnStartupPhase>[1], "durationSeconds" | "outcome">,
1802
+ work: () => Promise<T>,
1803
+ ): Promise<T> {
1804
+ const started = performance.now();
1805
+ let outcome: TurnStartupOutcome = "failed";
1806
+ try {
1807
+ const result = await work();
1808
+ outcome = "completed";
1809
+ return result;
1810
+ } finally {
1811
+ try {
1812
+ recordTurnStartupPhase(observability, {
1813
+ ...input,
1814
+ outcome,
1815
+ durationSeconds: (performance.now() - started) / 1_000,
1816
+ });
1817
+ } catch {
1818
+ // Telemetry is not an execution gate.
1819
+ }
1820
+ }
1821
+ }
1822
+
1823
+ /** Background MCP preparation must not inflate startup phase distributions. */
1824
+ export function recordToolPreparationPhase(
1825
+ observability: Observability,
1826
+ input: ToolPreparationPhaseMeasurement & { provider: string; backend: string },
1827
+ ): void {
1828
+ if (input.execution === "blocking") {
1829
+ recordTurnStartupPhase(observability, {
1830
+ ...input,
1831
+ phase: `tool_${input.phase}`,
1832
+ });
1833
+ return;
1834
+ }
1835
+ completedOperationSpan(
1836
+ observability,
1837
+ `worker.tool_prepare.${input.phase}`,
1838
+ input.durationSeconds,
1839
+ {
1840
+ provider: input.provider,
1841
+ backend: input.backend,
1842
+ outcome: input.outcome,
1843
+ },
1844
+ );
1845
+ observability.observeHistogram({
1846
+ name: "opengeni_tool_background_preparation_duration_seconds",
1847
+ help: "Nonblocking MCP preparation operations; may overlap startup and later execution.",
1848
+ buckets: TURN_STARTUP_PHASE_BUCKETS,
1849
+ labels: {
1850
+ phase: input.phase,
1851
+ provider: input.provider,
1852
+ backend: input.backend,
1853
+ outcome: input.outcome,
1854
+ },
1855
+ value: Math.max(0, input.durationSeconds),
1856
+ });
1857
+ }
1858
+
1859
+ /** Completed measurements become siblings under the scoped physical attempt.
1860
+ * They never establish ambient ancestry for work which has already finished. */
1861
+ function completedOperationSpan(
1862
+ observability: Observability,
1863
+ name: string,
1864
+ durationSeconds: number,
1865
+ attributes: {
1866
+ outcome: string;
1867
+ provider?: string;
1868
+ backend?: string;
1869
+ correlationId?: string | undefined;
1870
+ },
1871
+ ): void {
1872
+ if (!Number.isFinite(durationSeconds) || durationSeconds < 0) return;
1873
+ try {
1874
+ const failed = [
1875
+ "failed",
1876
+ "error",
1877
+ "provider_declared_error",
1878
+ "auth_needed",
1879
+ "outcome_uncertain",
1880
+ "timeout",
1881
+ "thrown_transport_error",
1882
+ "thrown_protocol_error",
1883
+ ].includes(attributes.outcome);
1884
+ observability
1885
+ .startSpan(name, attributes, { startTimeMs: Date.now() - durationSeconds * 1_000 })
1886
+ .end({
1887
+ ...(failed ? { error: true } : {}),
1888
+ });
1889
+ } catch {
1890
+ // Observers cannot change the completed model/tool/phase outcome.
1891
+ }
1892
+ }
1893
+
1527
1894
  /**
1528
1895
  * Explain why a turn did or did not keep provider sandbox work off the
1529
1896
  * pre-model critical path. The reason is a closed enum: never attach session,
@@ -2161,3 +2528,141 @@ export function modelCallAccountContext(input: {
2161
2528
  accountChangedFromPrevCall,
2162
2529
  };
2163
2530
  }
2531
+
2532
+ export type CodeSearchCallOutcome =
2533
+ | "completed"
2534
+ | "jev_unavailable"
2535
+ | "jev_rejected"
2536
+ | "workspace_unavailable"
2537
+ | "invalid_arguments"
2538
+ | "breaker_open"
2539
+ | "cancelled"
2540
+ | "failed";
2541
+
2542
+ /** One `code_search` tool call: outcome, wall time and the Jev work it used. */
2543
+ export function recordCodeSearchCall(
2544
+ observability: Observability,
2545
+ input: {
2546
+ outcome: CodeSearchCallOutcome;
2547
+ durationSeconds: number;
2548
+ jevRequests: number;
2549
+ jevCostUsd: number;
2550
+ },
2551
+ ): void {
2552
+ observability.incrementCounter({
2553
+ name: "opengeni_code_search_calls_total",
2554
+ help: "Jev-backed code_search tool calls by outcome.",
2555
+ labels: { outcome: input.outcome },
2556
+ });
2557
+ observability.observeHistogram({
2558
+ name: "opengeni_code_search_duration_seconds",
2559
+ help: "Wall time of one code_search tool call.",
2560
+ buckets: [0.5, 1, 2, 4, 8, 15, 30, 60],
2561
+ labels: { outcome: input.outcome },
2562
+ value: Math.max(0, input.durationSeconds),
2563
+ });
2564
+ if (input.jevRequests > 0) {
2565
+ observability.incrementCounter({
2566
+ name: "opengeni_code_search_jev_requests_total",
2567
+ help: "Jev requests made by code_search.",
2568
+ amount: input.jevRequests,
2569
+ });
2570
+ }
2571
+ if (input.jevCostUsd > 0) {
2572
+ observability.incrementCounter({
2573
+ name: "opengeni_code_search_jev_cost_micro_usd_total",
2574
+ help: "Estimated Jev list-price cost of code_search, in micro-USD.",
2575
+ amount: Math.round(input.jevCostUsd * 1_000_000),
2576
+ });
2577
+ }
2578
+ }
2579
+
2580
+ /**
2581
+ * One skill_read call. Labels are closed sets: `skill` is a built-in id or
2582
+ * `custom` for every other Skill, so tenant Skill ids, names, and requested
2583
+ * identifiers never become labels. `source` is `unknown` when the read was
2584
+ * refused before a Skill resolved.
2585
+ */
2586
+ export function recordSkillRead(
2587
+ observability: Observability,
2588
+ read: {
2589
+ caller: "model" | "codemode";
2590
+ kind: SkillReadKind;
2591
+ source: SkillUseSource | null;
2592
+ /** The resolved Skill id, or the requested identifier when none resolved. */
2593
+ skill: string;
2594
+ },
2595
+ ): void {
2596
+ observability.incrementCounter({
2597
+ name: "opengeni_skill_reads_total",
2598
+ help: "skill_read calls by Skill source, built-in Skill id (custom for any other Skill), result kind, and caller.",
2599
+ labels: {
2600
+ source: read.source ?? "unknown",
2601
+ skill: skillReadMetricLabel(read.source, read.skill),
2602
+ kind: read.kind,
2603
+ caller: read.caller,
2604
+ },
2605
+ });
2606
+ }
2607
+
2608
+ /**
2609
+ * One skill_checkout call. Labels are closed sets and never carry Skill ids,
2610
+ * names, or paths. Phases that did not run are not observed.
2611
+ */
2612
+ export function recordSkillCheckout(
2613
+ observability: Observability,
2614
+ checkout: {
2615
+ outcome: "written" | "unchanged" | "refused" | "failed";
2616
+ selection: "all" | "paths";
2617
+ written: number;
2618
+ unchanged: number;
2619
+ resolveSeconds: number | null;
2620
+ sandboxSeconds: number | null;
2621
+ writeSeconds: number | null;
2622
+ totalSeconds: number;
2623
+ },
2624
+ ): void {
2625
+ observability.incrementCounter({
2626
+ name: "opengeni_skill_checkouts_total",
2627
+ help: "skill_checkout calls by outcome and whether they selected specific paths.",
2628
+ labels: { outcome: checkout.outcome, selection: checkout.selection },
2629
+ });
2630
+ const phases = [
2631
+ ["resolve", checkout.resolveSeconds],
2632
+ ["sandbox", checkout.sandboxSeconds],
2633
+ ["write", checkout.writeSeconds],
2634
+ ["total", checkout.totalSeconds],
2635
+ ] as const;
2636
+ for (const [phase, seconds] of phases) {
2637
+ if (seconds === null) continue;
2638
+ observability.observeHistogram({
2639
+ name: "opengeni_skill_checkout_duration_seconds",
2640
+ help: "Wall time of skill_checkout phases: resolve (authority and Skill read), sandbox (filesystem handle, including lazy box start), write (batched file write), and total.",
2641
+ buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 4, 8, 15, 30, 60],
2642
+ labels: { phase, outcome: checkout.outcome },
2643
+ value: Math.max(0, seconds),
2644
+ });
2645
+ }
2646
+ for (const [result, amount] of [
2647
+ ["written", checkout.written],
2648
+ ["unchanged", checkout.unchanged],
2649
+ ] as const) {
2650
+ if (amount <= 0) continue;
2651
+ observability.incrementCounter({
2652
+ name: "opengeni_skill_checkout_files_total",
2653
+ help: "Files skill_checkout wrote or found already present with the same content.",
2654
+ labels: { result },
2655
+ amount,
2656
+ });
2657
+ }
2658
+ }
2659
+
2660
+ function skillReadMetricLabel(source: SkillUseSource | null, skill: string): string {
2661
+ if (source !== null && source !== "builtin") return "custom";
2662
+ // A refused read may name a built-in by its plain name.
2663
+ for (const candidate of source === null ? [skill, `builtin:${skill}`] : [skill]) {
2664
+ const parsed = BundledSkillId.safeParse(candidate);
2665
+ if (parsed.success) return parsed.data;
2666
+ }
2667
+ return "custom";
2668
+ }
@@ -295,6 +295,8 @@ export function personalGitBrokerOrigin(settings: Settings): string | null {
295
295
  (url.hostname === "host.docker.internal" ||
296
296
  url.hostname === cachedDockerBridgeGateway ||
297
297
  /^[a-z][a-z0-9-]{0,62}$/iu.test(url.hostname));
298
+ // The `local` and `test` environments accept any origin, which covers the
299
+ // local launcher's Linux Docker sandbox route on the Compose network gateway.
298
300
  const privateExecutionOrigin =
299
301
  (url.protocol === "http:" &&
300
302
  (url.hostname === "127.0.0.1" || url.hostname === "localhost" || dockerPrivateOrigin)) ||
@@ -329,7 +331,6 @@ function exactPersonalGitHubDelegation(
329
331
  delegation.providerDomain !== "github.com" ||
330
332
  delegation.kind !== "oauth2" ||
331
333
  !delegation.originWorkspaceId ||
332
- !delegation.userDelegation ||
333
334
  !delegation.personalGitHubRepositorySelection
334
335
  ) {
335
336
  throw new Error("personal GitHub Git delegation is unavailable");
@@ -5,7 +5,6 @@ import type {
5
5
  GitCredentialsRequest,
6
6
  } from "@opengeni/contracts";
7
7
  import { prReviewRegistrationIdFromCredentialBinding } from "@opengeni/core";
8
- import { createNativeRemoteMcpCredentialsPort } from "@opengeni/core/remote-mcp-credentials";
9
8
  import { decryptVariableSetValue, resolvePrReviewGitCredential, type Database } from "@opengeni/db";
10
9
  import {
11
10
  createGitHubAppInstallationTokenWithExpiry,
@@ -19,7 +18,6 @@ export function createStandaloneConnectionCredentialsPort(
19
18
  db: Database,
20
19
  ): ConnectionCredentialsPort {
21
20
  return {
22
- ...createNativeRemoteMcpCredentialsPort(settings, db),
23
21
  gitCredentials: async (request) => await resolveStandaloneGitCredentials(settings, db, request),
24
22
  };
25
23
  }
@@ -113,7 +111,7 @@ async function resolveStandaloneGitCredentials(
113
111
  authority.credentialKind === "managed_github_app" &&
114
112
  settings.prReviewGithubAppId !== authority.appId
115
113
  ) {
116
- throw new Error("OpenGeni Lens App identity no longer matches this registration");
114
+ throw new Error("Opengeni Lens App identity no longer matches this registration");
117
115
  }
118
116
  const minted = await createGitHubAppInstallationTokenWithSigningSettings(signingSettings, {
119
117
  installationId: request.installationId,