@opengeni/worker-bundle 3.3.0 → 3.4.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 (35) hide show
  1. package/dist/{activities-control-G2W4FEFP.js → activities-control-EWP3UDZP.js} +5 -5
  2. package/dist/{activities-turn-CE2VIWIS.js → activities-turn-COUX2R3A.js} +16 -4
  3. package/dist/activities-turn-COUX2R3A.js.map +1 -0
  4. package/dist/artifact-materializer-entry.js +1 -0
  5. package/dist/artifact-materializer-entry.js.map +1 -1
  6. package/dist/artifact-outbox-entry.js +3 -1
  7. package/dist/artifact-outbox-entry.js.map +1 -1
  8. package/dist/{chunk-5NNS4327.js → chunk-BX3KRGDM.js} +10 -4
  9. package/dist/{chunk-5NNS4327.js.map → chunk-BX3KRGDM.js.map} +1 -1
  10. package/dist/{chunk-5DF4V5RD.js → chunk-PFCSGZGA.js} +7 -4
  11. package/dist/{chunk-5DF4V5RD.js.map → chunk-PFCSGZGA.js.map} +1 -1
  12. package/dist/{chunk-RSI63RZG.js → chunk-PG66GHGH.js} +3 -3
  13. package/dist/{chunk-R5BHILMQ.js → chunk-XUIWRRTY.js} +5 -4
  14. package/dist/chunk-XUIWRRTY.js.map +1 -0
  15. package/dist/editable-artifact-outbox-dispatcher.d.ts +2 -0
  16. package/dist/index.js +30 -5
  17. package/dist/index.js.map +1 -1
  18. package/dist/internal-maintenance.d.ts +3 -1
  19. package/dist/observability-metrics.d.ts +14 -0
  20. package/dist/{sandbox-lease-2IV3DNXR.js → sandbox-lease-XBZWILZ3.js} +4 -4
  21. package/package.json +26 -26
  22. package/src/activities/agent-turn/run.ts +15 -0
  23. package/src/activity-services.ts +3 -0
  24. package/src/editable-artifact-materializer-service.ts +3 -0
  25. package/src/editable-artifact-outbox-dispatcher.ts +5 -0
  26. package/src/editable-artifact-outbox-service.ts +3 -0
  27. package/src/index.ts +6 -0
  28. package/src/internal-maintenance.ts +24 -0
  29. package/src/observability-metrics.ts +20 -3
  30. package/src/sandbox-routing.ts +3 -0
  31. package/dist/activities-turn-CE2VIWIS.js.map +0 -1
  32. package/dist/chunk-R5BHILMQ.js.map +0 -1
  33. /package/dist/{activities-control-G2W4FEFP.js.map → activities-control-EWP3UDZP.js.map} +0 -0
  34. /package/dist/{chunk-RSI63RZG.js.map → chunk-PG66GHGH.js.map} +0 -0
  35. /package/dist/{sandbox-lease-2IV3DNXR.js.map → sandbox-lease-XBZWILZ3.js.map} +0 -0
@@ -14,7 +14,9 @@ export declare const SITE_AUTH_MAINTENANCE_WORKFLOW_ID = "opengeni-site-auth-mai
14
14
  export declare const SITE_AUTH_MAINTENANCE_PERIOD_MS: number;
15
15
  /** The Schedule earlier releases used to drive the sandbox lease reaper. */
16
16
  export declare const SANDBOX_REAPER_SCHEDULE_ID = "opengeni-sandbox-lease-reaper";
17
- export declare const INTERNAL_MAINTENANCE_JOBS: readonly ["session-workflow-wake-dispatcher", "knowledge-indexing", "site-auth-maintenance", "sandbox-lease-reaper", "sandbox-idle-checkpoint", "browser-deadline-checkpoint"];
17
+ /** Small bounded DB-only pass; no Temporal execution for plan maintenance. */
18
+ export declare const SUBSCRIPTION_PLAN_MAINTENANCE_PERIOD_MS = 60000;
19
+ export declare const INTERNAL_MAINTENANCE_JOBS: readonly ["session-workflow-wake-dispatcher", "knowledge-indexing", "site-auth-maintenance", "sandbox-lease-reaper", "sandbox-idle-checkpoint", "browser-deadline-checkpoint", "subscription-plan-maintenance"];
18
20
  export type InternalMaintenanceJob = (typeof INTERNAL_MAINTENANCE_JOBS)[number];
19
21
  type WorkflowStarter = Pick<TemporalClient["workflow"], "start" | "signalWithStart">;
20
22
  type ScheduleDeleter = {
@@ -423,11 +423,25 @@ export declare function recordModelCreditsCharged(observability: Observability |
423
423
  * Provider ids come from the resolved provider registry; phase/outcome are closed
424
424
  * enums. This function never performs I/O outside the in-memory metrics registry.
425
425
  */
426
+ /**
427
+ * How a model request reached its provider, where the provider has more than
428
+ * one transport (Codex: a new or reused Responses WebSocket, or HTTP). Empty
429
+ * for providers with a single transport.
430
+ */
431
+ export type ModelRequestTransportLabel = "" | "websocket_new" | "websocket_reused" | "http";
432
+ /** The bounded metric label for how a Codex request was carried. */
433
+ export declare function codexRequestTransportLabel(transport: {
434
+ kind: "websocket";
435
+ connection: "new" | "reused";
436
+ } | {
437
+ kind: "http";
438
+ }): ModelRequestTransportLabel;
426
439
  export declare function recordModelRequestPhase(observability: Observability, input: {
427
440
  provider: string;
428
441
  phase: "headers" | "first_byte" | "terminal";
429
442
  outcome?: "completed" | "failed" | "timed_out";
430
443
  durationSeconds: number;
444
+ transport?: ModelRequestTransportLabel;
431
445
  }): void;
432
446
  export type TurnStartupPhase = "services_initialization" | "claim_catalog_read" | "claim_atomic" | "claim_session_read" | "claim_capability_settings" | "learning_policy_freeze" | "attachment_authority_projection" | "claim_and_policy" | "turn_start_settlement" | "credential_selection" | "runtime_preparation" | "session_mcp_settings" | "sandbox_establish" | "file_resolution" | "tool_context_preparation" | "tool_preparation" | "tool_server_construction" | "tool_required_connect" | "tool_optional_connect" | "tool_attempt_catalog_build" | "tool_attempt_catalog_persist" | "tool_workspace_gateway_catalog_build" | "post_tool_preparation" | "agent_construction" | "post_agent_preparation" | "file_materialization" | "history_preparation" | "history_system_update_load" | "history_current_attachment_resolution" | "history_durable_history_load" | "history_sandbox_envelope_load" | "history_canonical_projection" | "history_provider_projection" | "history_attachment_ref_projection" | "history_screenshot_materialization" | "history_model_attachment_projection" | "history_runtime_input_assembly" | "history_artifact_candidate_scan" | "history_generated_image_materialization" | "history_position_load" | "owned_sandbox_setup" | "runtime_stream_initialization" | "model_request_preparation" | "model_sdk_serialization" | "model_prepare_sandbox_agent_preparation" | "model_prepare_sandbox_agent_manifest_inventory" | "model_prepare_sandbox_session_manifest_inventory" | "model_prepare_sandbox_manifest_apply" | "model_prepare_sandbox_entry_materialization" | "model_prepare_sandbox_running_check" | "model_prepare_sandbox_start" | "model_prepare_sandbox_client_create" | "model_prepare_sandbox_client_resume" | "model_prepare_sandbox_client_delete" | "model_prepare_sandbox_client_state_serialize" | "model_prepare_sandbox_client_reuse_check" | "model_prepare_sandbox_workspace_mutation_admission" | "model_prepare_sandbox_workspace_mutation_provider" | "model_prepare_sandbox_workspace_mutation_settlement" | "model_prepare_sandbox_first_routed_resolution_other" | "model_prepare_sandbox_first_routed_mutation_admission" | "model_prepare_sandbox_first_routed_provider_operation" | "model_prepare_sandbox_first_routed_mutation_settlement" | "model_prepare_sandbox_first_routed_other" | "model_prepare_sandbox_snapshot_wait" | "model_prepare_runner_before_first_sandbox_operation" | "model_prepare_sdk_after_first_sandbox_operation" | "model_prepare_runner_before_mcp_tools" | "model_prepare_mcp_tools_snapshot" | "model_prepare_mcp_tools_before_input_filter" | "model_prepare_mcp_tools_before_repository_skill_discovery" | "model_prepare_repository_skill_discovery" | "model_prepare_repository_skill_discovery_before_input_filter" | "model_prepare_input_filter_base" | "model_prepare_input_filter_genesis" | "model_prepare_input_filter_host" | "model_prepare_input_filter_tool_output" | "model_prepare_input_filter_modality" | "model_prepare_input_filter_context" | "model_prepare_responses_input_conversion" | "model_prepare_responses_request_build" | "model_credential_resolution" | "model_wire_normalization" | "model_request_audit" | "stream_bootstrap";
433
447
  export type TurnStartupOutcome = "completed" | "failed";
@@ -36,10 +36,10 @@ import {
36
36
  sandboxLeaseTelemetryKey,
37
37
  terminateProviderBox,
38
38
  verifyDockerDrainCaptureFence
39
- } from "./chunk-RSI63RZG.js";
40
- import "./chunk-5DF4V5RD.js";
39
+ } from "./chunk-PG66GHGH.js";
40
+ import "./chunk-PFCSGZGA.js";
41
41
  import "./chunk-24GP3BX5.js";
42
- import "./chunk-5NNS4327.js";
42
+ import "./chunk-BX3KRGDM.js";
43
43
  import "./chunk-W2QSM5HR.js";
44
44
  import "./chunk-PZ5AY32C.js";
45
45
  export {
@@ -81,4 +81,4 @@ export {
81
81
  terminateProviderBox,
82
82
  verifyDockerDrainCaptureFence
83
83
  };
84
- //# sourceMappingURL=sandbox-lease-2IV3DNXR.js.map
84
+ //# sourceMappingURL=sandbox-lease-XBZWILZ3.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/worker-bundle",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Opengeni worker entry and reusable embedded lifecycle, shipped with a release-coherent pre-bundled Temporal workflow artifact.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -56,31 +56,31 @@
56
56
  "@1password/sdk": "0.5.0",
57
57
  "@keeper-security/secrets-manager-core": "17.6.0",
58
58
  "@llamaindex/liteparse": "2.14.2",
59
- "@opengeni/agent-proto": "3.3.0",
60
- "@opengeni/capabilities": "3.3.0",
61
- "@opengeni/codemode": "3.3.0",
62
- "@opengeni/codex": "3.3.0",
63
- "@opengeni/config": "3.3.0",
64
- "@opengeni/contracts": "3.3.0",
65
- "@opengeni/core": "3.3.0",
66
- "@opengeni/db": "3.3.0",
67
- "@opengeni/documents": "3.3.0",
68
- "@opengeni/events": "3.3.0",
69
- "@opengeni/github": "3.3.0",
70
- "@opengeni/interaction": "3.3.0",
71
- "@opengeni/jev": "3.3.0",
72
- "@opengeni/network": "3.3.0",
73
- "@opengeni/observability": "3.3.0",
74
- "@opengeni/runtime": "3.3.0",
75
- "@opengeni/sdk": "3.3.0",
76
- "@opengeni/storage": "3.3.0",
77
- "@opengeni/subscriptions": "3.3.0",
78
- "@opengeni/tool-gateway": "3.3.0",
79
- "@opengeni/vaults": "3.3.0",
80
- "@opengeni/vaults-keeper": "3.3.0",
81
- "@opengeni/vaults-onepassword": "3.3.0",
82
- "@opengeni/vaults-protonpass": "3.3.0",
83
- "@opengeni/xai-subscription": "3.3.0",
59
+ "@opengeni/agent-proto": "3.4.0",
60
+ "@opengeni/capabilities": "3.4.0",
61
+ "@opengeni/codemode": "3.4.0",
62
+ "@opengeni/codex": "3.4.0",
63
+ "@opengeni/config": "3.4.0",
64
+ "@opengeni/contracts": "3.4.0",
65
+ "@opengeni/core": "3.4.0",
66
+ "@opengeni/db": "3.4.0",
67
+ "@opengeni/documents": "3.4.0",
68
+ "@opengeni/events": "3.4.0",
69
+ "@opengeni/github": "3.4.0",
70
+ "@opengeni/interaction": "3.4.0",
71
+ "@opengeni/jev": "3.4.0",
72
+ "@opengeni/network": "3.4.0",
73
+ "@opengeni/observability": "3.4.0",
74
+ "@opengeni/runtime": "3.4.0",
75
+ "@opengeni/sdk": "3.4.0",
76
+ "@opengeni/storage": "3.4.0",
77
+ "@opengeni/subscriptions": "3.4.0",
78
+ "@opengeni/tool-gateway": "3.4.0",
79
+ "@opengeni/vaults": "3.4.0",
80
+ "@opengeni/vaults-keeper": "3.4.0",
81
+ "@opengeni/vaults-onepassword": "3.4.0",
82
+ "@opengeni/vaults-protonpass": "3.4.0",
83
+ "@opengeni/xai-subscription": "3.4.0",
84
84
  "@temporalio/activity": "^1.17.0",
85
85
  "@temporalio/client": "^1.17.0",
86
86
  "@temporalio/worker": "^1.17.0",
@@ -61,9 +61,11 @@ import type {
61
61
  RunAgentTurnResult,
62
62
  } from "../types";
63
63
  import {
64
+ codexRequestTransportLabel,
64
65
  makeMachineOpObserver,
65
66
  modelRequestLifecycleMetricsFor,
66
67
  recordModelRequestPhase,
68
+ type ModelRequestTransportLabel,
67
69
  recordCompanyBrainContributions,
68
70
  recordTurnStartupPhase,
69
71
  measureTurnStartupPhase,
@@ -805,6 +807,7 @@ export function createRunAgentTurnActivity(services: () => Promise<ActivityServi
805
807
  resolvedToken = token;
806
808
  return token;
807
809
  };
810
+ const codexRequestTransports = new Map<string, ModelRequestTransportLabel>();
808
811
  const creditGuard = createCodexCreditGuard({
809
812
  ...(coreUsageReader ? { fetchUsage: coreUsageReader } : {}),
810
813
  canSpendCredits: async () => {
@@ -924,8 +927,20 @@ export function createRunAgentTurnActivity(services: () => Promise<ActivityServi
924
927
  ? "terminal"
925
928
  : null;
926
929
  if (!phase) return;
930
+ // The transport is known once headers arrive; later
931
+ // phases of the same request carry the same label.
932
+ const transportKey = `${event.requestId}:${event.transportAttempt}`;
933
+ if (event.transport) {
934
+ codexRequestTransports.set(
935
+ transportKey,
936
+ codexRequestTransportLabel(event.transport),
937
+ );
938
+ }
939
+ const transport = codexRequestTransports.get(transportKey);
940
+ if (phase === "terminal") codexRequestTransports.delete(transportKey);
927
941
  recordModelRequestPhase(observability, {
928
942
  provider: "codex-subscription",
943
+ ...(transport ? { transport } : {}),
929
944
  phase,
930
945
  ...(event.phase === "completed"
931
946
  ? { outcome: "completed" as const }
@@ -45,6 +45,9 @@ export function createSharedActivityServices(
45
45
  : createDb(settings.databaseUrl, {
46
46
  ...(searchPath ? { searchPath } : {}),
47
47
  rlsStrategy: settings.rlsStrategy,
48
+ ...(settings.databasePreparedStatements === undefined
49
+ ? {}
50
+ : { preparedStatements: settings.databasePreparedStatements }),
48
51
  });
49
52
  const controlPlaneAuth = resolveNatsControlPlaneAuth(settings);
50
53
  const db = dependencies.db ?? dbClient!.db;
@@ -162,6 +162,9 @@ export async function createProductionEditableArtifactMaterializerService(
162
162
  const dbClient = createDb(options.databaseUrl, {
163
163
  ...(searchPath ? { searchPath } : {}),
164
164
  ...(options.settings.rlsStrategy ? { rlsStrategy: options.settings.rlsStrategy } : {}),
165
+ ...(options.settings.databasePreparedStatements === undefined
166
+ ? {}
167
+ : { preparedStatements: options.settings.databasePreparedStatements }),
165
168
  max: Math.max(2, concurrency + 1),
166
169
  });
167
170
  let created = false;
@@ -43,6 +43,8 @@ export type EditableArtifactOutboxWorkerOptions = Readonly<{
43
43
  dispatcherDatabaseUrl: string;
44
44
  databaseSearchPath?: string;
45
45
  databasePoolSize?: number;
46
+ /** Unset → decided from the URL; see `CreateDbOptions.preparedStatements`. */
47
+ databasePreparedStatements?: boolean;
46
48
  natsUrl: string;
47
49
  natsAuth: EditableArtifactHintNatsAuth;
48
50
  owner?: string;
@@ -121,6 +123,9 @@ export async function createEditableArtifactOutboxWorker(
121
123
  const database = createDb(dispatcherDatabaseUrl, {
122
124
  max: databasePoolSize,
123
125
  ...(options.databaseSearchPath ? { searchPath: options.databaseSearchPath } : {}),
126
+ ...(options.databasePreparedStatements === undefined
127
+ ? {}
128
+ : { preparedStatements: options.databasePreparedStatements }),
124
129
  });
125
130
  let broker: ConfirmedNatsEditableArtifactHintBroker;
126
131
  try {
@@ -94,6 +94,9 @@ export async function createProductionEditableArtifactOutboxService(
94
94
  ...(options.databasePoolSize === undefined
95
95
  ? {}
96
96
  : { databasePoolSize: options.databasePoolSize }),
97
+ ...(options.settings.databasePreparedStatements === undefined
98
+ ? {}
99
+ : { databasePreparedStatements: options.settings.databasePreparedStatements }),
97
100
  natsUrl: options.natsUrl,
98
101
  natsAuth: options.natsAuth,
99
102
  owner: options.owner,
package/src/index.ts CHANGED
@@ -1078,9 +1078,14 @@ export async function startWorker() {
1078
1078
  const onRetry = (event: Parameters<typeof logStartupDependencyRetry>[1]) =>
1079
1079
  logStartupDependencyRetry(observability, event);
1080
1080
  const searchPath = dbSearchPath(settings);
1081
+ const preparedStatements =
1082
+ settings.databasePreparedStatements === undefined
1083
+ ? {}
1084
+ : { preparedStatements: settings.databasePreparedStatements };
1081
1085
  const dbClient = createDb(settings.databaseUrl, {
1082
1086
  ...(searchPath ? { searchPath } : {}),
1083
1087
  rlsStrategy: settings.rlsStrategy,
1088
+ ...preparedStatements,
1084
1089
  });
1085
1090
  // Readiness must prove PostgreSQL independently of activity demand. Sharing
1086
1091
  // the default application pool makes the probe wait behind live turns when
@@ -1090,6 +1095,7 @@ export async function startWorker() {
1090
1095
  const readinessDbClient = createDb(settings.databaseUrl, {
1091
1096
  ...(searchPath ? { searchPath } : {}),
1092
1097
  rlsStrategy: settings.rlsStrategy,
1098
+ ...preparedStatements,
1093
1099
  max: 1,
1094
1100
  });
1095
1101
  const databasePosture = {
@@ -10,11 +10,13 @@ import {
10
10
  automaticSessionTitleFanoutDue,
11
11
  browserDeadlineCheckpointDue,
12
12
  knowledgeIndexDue,
13
+ maintainSubscriptionPlans,
13
14
  sandboxIdleCheckpointDue,
14
15
  sandboxLeaseReaperDue,
15
16
  sandboxMaintenanceDue,
16
17
  sessionWorkflowWakesDue,
17
18
  siteAuthMaintenanceDue,
19
+ subscriptionPlanMaintenanceDue,
18
20
  workspacePauseTimerDue,
19
21
  type Database,
20
22
  } from "@opengeni/db";
@@ -53,6 +55,8 @@ export const SITE_AUTH_MAINTENANCE_WORKFLOW_ID = "opengeni-site-auth-maintenance
53
55
  export const SITE_AUTH_MAINTENANCE_PERIOD_MS = 60 * 1_000;
54
56
  /** The Schedule earlier releases used to drive the sandbox lease reaper. */
55
57
  export const SANDBOX_REAPER_SCHEDULE_ID = "opengeni-sandbox-lease-reaper";
58
+ /** Small bounded DB-only pass; no Temporal execution for plan maintenance. */
59
+ export const SUBSCRIPTION_PLAN_MAINTENANCE_PERIOD_MS = 60_000;
56
60
 
57
61
  export const INTERNAL_MAINTENANCE_JOBS = [
58
62
  "session-workflow-wake-dispatcher",
@@ -61,6 +65,7 @@ export const INTERNAL_MAINTENANCE_JOBS = [
61
65
  "sandbox-lease-reaper",
62
66
  "sandbox-idle-checkpoint",
63
67
  "browser-deadline-checkpoint",
68
+ "subscription-plan-maintenance",
64
69
  ] as const;
65
70
  export type InternalMaintenanceJob = (typeof INTERNAL_MAINTENANCE_JOBS)[number];
66
71
 
@@ -139,6 +144,25 @@ export async function internalMaintenanceCadences(input: {
139
144
  const jobs = new Set(input.jobs ?? INTERNAL_MAINTENANCE_JOBS);
140
145
  const taskQueue = settings.temporalTaskQueue;
141
146
  const cadences: MaintenanceCadence[] = [];
147
+ if (settings.subscriptionPlansEnabled && jobs.has("subscription-plan-maintenance")) {
148
+ cadences.push({
149
+ job: "subscription-plan-maintenance",
150
+ periodMs: SUBSCRIPTION_PLAN_MAINTENANCE_PERIOD_MS,
151
+ hasWork: async () => await subscriptionPlanMaintenanceDue(db),
152
+ start: async () => {
153
+ const result = await maintainSubscriptionPlans(db, {
154
+ onError: (error, accountId) =>
155
+ observability.warn("Subscription plan maintenance account failed", {
156
+ accountId,
157
+ error: error instanceof Error ? error.message : String(error),
158
+ }),
159
+ });
160
+ if (result.failedAccounts > 0)
161
+ throw new Error(`${result.failedAccounts} subscription plan maintenance accounts failed`);
162
+ return "started";
163
+ },
164
+ });
165
+ }
142
166
  if (jobs.has("session-workflow-wake-dispatcher")) {
143
167
  const { repairMissedSessionWorkflowWakes } = await import("./activities/parent-wake");
144
168
  cadences.push({
@@ -2194,6 +2194,21 @@ const MODEL_REQUEST_PHASE_BUCKETS = [
2194
2194
  * Provider ids come from the resolved provider registry; phase/outcome are closed
2195
2195
  * enums. This function never performs I/O outside the in-memory metrics registry.
2196
2196
  */
2197
+ /**
2198
+ * How a model request reached its provider, where the provider has more than
2199
+ * one transport (Codex: a new or reused Responses WebSocket, or HTTP). Empty
2200
+ * for providers with a single transport.
2201
+ */
2202
+ export type ModelRequestTransportLabel = "" | "websocket_new" | "websocket_reused" | "http";
2203
+
2204
+ /** The bounded metric label for how a Codex request was carried. */
2205
+ export function codexRequestTransportLabel(
2206
+ transport: { kind: "websocket"; connection: "new" | "reused" } | { kind: "http" },
2207
+ ): ModelRequestTransportLabel {
2208
+ if (transport.kind === "http") return "http";
2209
+ return transport.connection === "reused" ? "websocket_reused" : "websocket_new";
2210
+ }
2211
+
2197
2212
  export function recordModelRequestPhase(
2198
2213
  observability: Observability,
2199
2214
  input: {
@@ -2201,19 +2216,21 @@ export function recordModelRequestPhase(
2201
2216
  phase: "headers" | "first_byte" | "terminal";
2202
2217
  outcome?: "completed" | "failed" | "timed_out";
2203
2218
  durationSeconds: number;
2219
+ transport?: ModelRequestTransportLabel;
2204
2220
  },
2205
2221
  ): void {
2206
2222
  const outcome = input.outcome ?? "";
2223
+ const transport = input.transport ?? "";
2207
2224
  observability.incrementCounter({
2208
2225
  name: "opengeni_model_request_phases_total",
2209
- help: "Provider model-request lifecycle phases by bounded phase and outcome.",
2210
- labels: { provider: input.provider, phase: input.phase, outcome },
2226
+ help: "Provider model-request lifecycle phases by bounded phase, outcome and transport.",
2227
+ labels: { provider: input.provider, phase: input.phase, outcome, transport },
2211
2228
  });
2212
2229
  observability.observeHistogram({
2213
2230
  name: "opengeni_model_request_phase_duration_seconds",
2214
2231
  help: "Monotonic seconds from provider dispatch to a model-request lifecycle phase.",
2215
2232
  buckets: MODEL_REQUEST_PHASE_BUCKETS,
2216
- labels: { provider: input.provider, phase: input.phase },
2233
+ labels: { provider: input.provider, phase: input.phase, transport },
2217
2234
  value: Math.max(0, input.durationSeconds),
2218
2235
  });
2219
2236
  }
@@ -1038,6 +1038,7 @@ export function wrapTurnBoxWithRouting(
1038
1038
  connectionInstanceId: command.connectionInstanceId,
1039
1039
  opId: command.opId,
1040
1040
  command: command.command,
1041
+ ...(command.abandoned ? { abandoned: true } : {}),
1041
1042
  });
1042
1043
  return { commandId: adopted.id };
1043
1044
  },
@@ -1337,6 +1338,7 @@ export function wrapLazyTurnBoxWithRouting(
1337
1338
  connectionInstanceId: command.connectionInstanceId,
1338
1339
  opId: command.opId,
1339
1340
  command: command.command,
1341
+ ...(command.abandoned ? { abandoned: true } : {}),
1340
1342
  });
1341
1343
  return { commandId: adopted.id };
1342
1344
  },
@@ -1750,6 +1752,7 @@ export async function establishSelfhostedTurnSession(
1750
1752
  connectionInstanceId: command.connectionInstanceId,
1751
1753
  opId: command.opId,
1752
1754
  command: command.command,
1755
+ ...(command.abandoned ? { abandoned: true } : {}),
1753
1756
  });
1754
1757
  return { commandId: adopted.id };
1755
1758
  },