@opengeni/api-router 2.5.0 → 2.6.4-canary.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 (70) hide show
  1. package/dist/app.d.ts +2 -1
  2. package/dist/app.js +3 -1
  3. package/dist/auth/managed-auth-attempt-context.d.ts +5 -1
  4. package/dist/auth/managed-auth.d.ts +24 -1
  5. package/dist/{chunk-QESX7HDK.js → chunk-UOI7KAP3.js} +3240 -791
  6. package/dist/chunk-UOI7KAP3.js.map +1 -0
  7. package/dist/http/sse.d.ts +9 -0
  8. package/dist/index.js +117 -5
  9. package/dist/index.js.map +1 -1
  10. package/dist/interaction-metrics.d.ts +2 -0
  11. package/dist/mcp/company-brain-governed-writes.d.ts +1 -1
  12. package/dist/mcp/company-profile-agent-admin.d.ts +6 -6
  13. package/dist/mcp/remember.d.ts +2 -2
  14. package/dist/mcp/scheduled-task-view.d.ts +3 -3
  15. package/dist/mcp/server.d.ts +1 -0
  16. package/dist/mcp/session-view.d.ts +1 -0
  17. package/dist/mcp/session-wait.d.ts +19 -0
  18. package/dist/model-catalog.d.ts +5 -31
  19. package/dist/routes/api-keys.d.ts +2 -0
  20. package/dist/routes/browser-sessions.d.ts +1 -0
  21. package/dist/routes/computer-sessions.d.ts +12 -0
  22. package/dist/routes/managed-auth-session-sets.d.ts +7 -0
  23. package/dist/routes/workspaces.d.ts +1 -1
  24. package/dist/sandbox/metrics-ingestion.d.ts +16 -0
  25. package/dist/workspace-delete-observability.d.ts +10 -0
  26. package/package.json +19 -19
  27. package/src/app.ts +206 -29
  28. package/src/auth/managed-auth-attempt-context.ts +40 -3
  29. package/src/auth/managed-auth-session-adapter.ts +1 -0
  30. package/src/auth/managed-auth.ts +164 -4
  31. package/src/http/sse.ts +279 -45
  32. package/src/index.ts +13 -1
  33. package/src/integrations/oauth-client.ts +8 -1
  34. package/src/integrations/provider-oauth.ts +12 -2
  35. package/src/integrations/slack-interactions.ts +77 -37
  36. package/src/interaction-metrics.ts +30 -0
  37. package/src/mcp/company-brain-governed-writes.ts +38 -23
  38. package/src/mcp/company-profile-agent-admin.ts +7 -7
  39. package/src/mcp/remember.ts +19 -8
  40. package/src/mcp/server.ts +328 -27
  41. package/src/mcp/session-wait.ts +56 -8
  42. package/src/model-catalog.ts +45 -337
  43. package/src/routes/api-integrations.ts +2 -2
  44. package/src/routes/api-keys.ts +149 -7
  45. package/src/routes/automations.ts +186 -19
  46. package/src/routes/browser-sessions.ts +10 -2
  47. package/src/routes/capabilities.ts +3 -3
  48. package/src/routes/codex.ts +483 -74
  49. package/src/routes/company-profile.ts +64 -0
  50. package/src/routes/computer-sessions.ts +103 -1
  51. package/src/routes/connections.ts +271 -16
  52. package/src/routes/github.ts +0 -8
  53. package/src/routes/integration-facets.ts +8 -5
  54. package/src/routes/interaction-resources.ts +7 -1
  55. package/src/routes/managed-auth-session-sets.ts +199 -2
  56. package/src/routes/organization-memberships.ts +28 -8
  57. package/src/routes/packs.ts +5 -5
  58. package/src/routes/plugins.ts +2 -2
  59. package/src/routes/pr-review.ts +80 -4
  60. package/src/routes/scheduled-tasks.ts +47 -11
  61. package/src/routes/sessions.ts +75 -53
  62. package/src/routes/skills.ts +3 -3
  63. package/src/routes/supergrok.ts +3 -2
  64. package/src/routes/workspaces.ts +665 -56
  65. package/src/sandbox/channel-a.ts +10 -4
  66. package/src/sandbox/machines.ts +13 -6
  67. package/src/sandbox/metrics-ingestion.ts +157 -3
  68. package/src/sandbox/viewer.ts +20 -1
  69. package/src/workspace-delete-observability.ts +75 -0
  70. package/dist/chunk-QESX7HDK.js.map +0 -1
@@ -5,6 +5,8 @@ import type { Observability } from "@opengeni/observability";
5
5
  export declare const SSE_QUEUED_FRAME_MAX_COUNT = 1;
6
6
  export declare const SSE_WRITE_STALL_TIMEOUT_MS = 30000;
7
7
  export declare const SSE_HEARTBEAT_INTERVAL_MS = 15000;
8
+ export declare const HTTP1_BROWSER_SSE_BATCH_MAX_BYTES: number;
9
+ export declare const HTTP1_BROWSER_SSE_BATCH_CONTENT_TYPE = "application/vnd.opengeni.sse-batch";
8
10
  export type SseDeliveryBoundObservation = {
9
11
  reason: "desired_size_non_positive" | "stall_timeout" | "frame_too_large";
10
12
  desiredSize: number | null;
@@ -12,6 +14,7 @@ export type SseDeliveryBoundObservation = {
12
14
  queuedBytes: number;
13
15
  };
14
16
  export type ByteBoundedSseStreamOptions = {
17
+ connectionLifetimeMs?: number | undefined;
15
18
  maxQueuedBytes?: number;
16
19
  stallTimeoutMs?: number;
17
20
  onStop?: () => void;
@@ -76,6 +79,11 @@ export declare function sseWorkspaceLiveStream(db: Database, bus: EventBus, acco
76
79
  */
77
80
  export declare function sseWorkspaceInteractionRevisionStream(db: Database, accountId: string, workspaceId: string, after: number, signal: AbortSignal, options?: WorkspaceInteractionSseOptions): Promise<Response>;
78
81
  export type SseDeliveryOptions = {
82
+ connectionLifetimeMs?: number | undefined;
83
+ /** Return a known-length batch instead of a chunked response. HTTP/1 only. */
84
+ finiteResponseMaxBytes?: number | undefined;
85
+ /** Browser transport classification for a finite response. */
86
+ finiteResponseMediaType?: "event-stream" | "http1-browser-batch" | undefined;
79
87
  maxQueuedBytes?: number;
80
88
  stallTimeoutMs?: number;
81
89
  heartbeatIntervalMs?: number;
@@ -87,4 +95,5 @@ export type SseDeliveryOptions = {
87
95
  /** Exact selected actor emitted on the stream response for cross-tab fencing. */
88
96
  actorEpoch?: string | undefined;
89
97
  };
98
+ export declare function browserSseDeliveryOptions(transport: string | undefined): Pick<SseDeliveryOptions, "connectionLifetimeMs" | "finiteResponseMaxBytes" | "finiteResponseMediaType">;
90
99
  export type SessionSseDeliveryOptions = SseDeliveryOptions;
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  createOpenGeniSlackBotInteractionClient,
7
7
  startSlackInteractionPump,
8
8
  startTemporalScheduleCleanupPump
9
- } from "./chunk-QESX7HDK.js";
9
+ } from "./chunk-UOI7KAP3.js";
10
10
 
11
11
  // src/index.ts
12
12
  import {
@@ -32,7 +32,10 @@ import {
32
32
  } from "@opengeni/observability";
33
33
  import { createObjectStorage } from "@opengeni/storage";
34
34
  import { isArtifactRuntimeConfigured } from "@opengeni/artifact-tool/runtime/development";
35
- import { SESSION_WORKFLOW_WAKE_DISPATCHER_SCHEDULE_ID } from "@opengeni/core";
35
+ import {
36
+ resolveCatalogSettings,
37
+ SESSION_WORKFLOW_WAKE_DISPATCHER_SCHEDULE_ID
38
+ } from "@opengeni/core";
36
39
  import {
37
40
  Connection,
38
41
  Client as TemporalClient,
@@ -233,6 +236,94 @@ import {
233
236
  } from "@opengeni/agent-proto";
234
237
  var AGENT_EVENTS_SUBJECT = "agent.*.*.connection.*.events";
235
238
  var AGENT_HELLO_SUBJECT = "agent.*.*.connection.*.hello";
239
+ function payloadIsHeartbeat(payload) {
240
+ try {
241
+ return AgentEvent.decode(payload).event?.$case === "heartbeat";
242
+ } catch {
243
+ return false;
244
+ }
245
+ }
246
+ function createAgentEventIngestionScheduler(handler, options = {}) {
247
+ const maxConcurrentSubjects = options.maxConcurrentSubjects ?? 32;
248
+ if (!Number.isSafeInteger(maxConcurrentSubjects) || maxConcurrentSubjects <= 0) {
249
+ throw new RangeError("maxConcurrentSubjects must be a positive safe integer");
250
+ }
251
+ const states = /* @__PURE__ */ new Map();
252
+ const readySubjects = [];
253
+ const idleWaiters = /* @__PURE__ */ new Set();
254
+ let accepting = true;
255
+ let activeSubjects = 0;
256
+ const resolveIdleWaiters = () => {
257
+ if (states.size !== 0) return;
258
+ for (const resolve of idleWaiters) resolve();
259
+ idleWaiters.clear();
260
+ };
261
+ async function drain(subject, state) {
262
+ while (true) {
263
+ const event = state.pending.shift();
264
+ if (!event) break;
265
+ try {
266
+ await handler(event.payload, event.subject);
267
+ } catch {
268
+ }
269
+ }
270
+ activeSubjects -= 1;
271
+ state.scheduled = false;
272
+ if (state.pending.length > 0) {
273
+ schedule(subject, state);
274
+ } else {
275
+ if (states.get(subject) === state) states.delete(subject);
276
+ resolveIdleWaiters();
277
+ }
278
+ pump();
279
+ }
280
+ function pump() {
281
+ while (activeSubjects < maxConcurrentSubjects) {
282
+ const next = readySubjects.shift();
283
+ if (!next) return;
284
+ if (states.get(next.subject) !== next.state || !next.state.scheduled) continue;
285
+ activeSubjects += 1;
286
+ void drain(next.subject, next.state);
287
+ }
288
+ }
289
+ function schedule(subject, state) {
290
+ if (state.scheduled) return;
291
+ state.scheduled = true;
292
+ readySubjects.push({ subject, state });
293
+ pump();
294
+ }
295
+ return {
296
+ enqueue(payload, subject) {
297
+ if (!accepting) return;
298
+ const heartbeat = payloadIsHeartbeat(payload);
299
+ let state = states.get(subject);
300
+ if (!state) {
301
+ state = { scheduled: false, pending: [] };
302
+ states.set(subject, state);
303
+ }
304
+ const queued = { payload, subject, heartbeat };
305
+ const lastIndex = state.pending.length - 1;
306
+ if (heartbeat && lastIndex >= 0 && state.pending[lastIndex].heartbeat) {
307
+ state.pending[lastIndex] = queued;
308
+ options.onHeartbeatCoalesced?.();
309
+ } else {
310
+ state.pending.push(queued);
311
+ }
312
+ schedule(subject, state);
313
+ },
314
+ async whenIdle() {
315
+ if (states.size === 0) return;
316
+ await new Promise((resolve) => idleWaiters.add(resolve));
317
+ },
318
+ close() {
319
+ accepting = false;
320
+ for (const state of states.values()) {
321
+ state.pending.length = 0;
322
+ }
323
+ resolveIdleWaiters();
324
+ }
325
+ };
326
+ }
236
327
  function parseAgentSubject(subject, tail) {
237
328
  const parts = subject.split(".");
238
329
  if (parts.length !== 6 || parts[0] !== "agent" || parts[3] !== "connection" || !parts[4] || parts[5] !== tail) {
@@ -545,10 +636,22 @@ async function handleAgentEventPayload(db, observability, payload, subject, bus)
545
636
  }
546
637
  }
547
638
  function startMetricsIngestion(deps) {
548
- return deps.bus.subscribeAgentEvents(
549
- AGENT_EVENTS_SUBJECT,
550
- (payload, subject) => handleAgentEventPayload(deps.db, deps.observability, payload, subject, deps.bus)
639
+ const scheduler = createAgentEventIngestionScheduler(
640
+ (payload, subject) => handleAgentEventPayload(deps.db, deps.observability, payload, subject, deps.bus),
641
+ {
642
+ onHeartbeatCoalesced: () => deps.observability?.incrementCounter({
643
+ name: "opengeni_machine_heartbeat_coalesced_total",
644
+ help: "Connected Machine heartbeats collapsed while an exact runner event queue was busy."
645
+ })
646
+ }
551
647
  );
648
+ const unsubscribe = deps.bus.subscribeAgentEvents(AGENT_EVENTS_SUBJECT, (payload, subject) => {
649
+ scheduler.enqueue(payload, subject);
650
+ });
651
+ return () => {
652
+ unsubscribe();
653
+ scheduler.close();
654
+ };
552
655
  }
553
656
  function helloReportsDisplay(hello) {
554
657
  const caps = hello.capabilities;
@@ -2805,6 +2908,15 @@ async function startApi(options = {}) {
2805
2908
  () => assertRuntimeDatabasePosture(dbClient.db, databasePosture),
2806
2909
  { ...retryOptions, onRetry }
2807
2910
  );
2911
+ const resolvedCatalog = await retryStartupDependency(
2912
+ "model catalog",
2913
+ () => resolveCatalogSettings(dbClient.db, settings),
2914
+ { ...retryOptions, onRetry }
2915
+ );
2916
+ observability.info("OpenGeni model catalog resolved", {
2917
+ catalogSource: resolvedCatalog.source,
2918
+ catalogVersion: resolvedCatalog.version
2919
+ });
2808
2920
  bus = await retryStartupDependency(
2809
2921
  "NATS",
2810
2922
  () => createNatsEventBus(