@opengeni/api-router 0.22.2 → 0.23.1

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 (44) hide show
  1. package/dist/app.js +1 -1
  2. package/dist/auth/managed-auth.d.ts +0 -30
  3. package/dist/{chunk-HWXJW5C7.js → chunk-T4T2PGU4.js} +3036 -1362
  4. package/dist/chunk-T4T2PGU4.js.map +1 -0
  5. package/dist/http/sse.d.ts +2 -0
  6. package/dist/index.js +29 -9
  7. package/dist/index.js.map +1 -1
  8. package/dist/integrations/oauth-client.d.ts +8 -0
  9. package/dist/integrations/slack-interactions.d.ts +7 -1
  10. package/dist/mcp/receipts.d.ts +28 -0
  11. package/dist/mcp/scheduled-task-view.d.ts +350 -0
  12. package/dist/mcp/toolspace.d.ts +9 -0
  13. package/dist/sandbox/auth-callout.d.ts +2 -0
  14. package/dist/sandbox/channel-a.d.ts +5 -1
  15. package/package.json +12 -12
  16. package/src/app.ts +3 -4
  17. package/src/auth/managed-auth.ts +0 -16
  18. package/src/http/sse.ts +101 -6
  19. package/src/index.ts +28 -3
  20. package/src/integrations/oauth-client.ts +36 -56
  21. package/src/integrations/slack-interactions.ts +123 -15
  22. package/src/mcp/documents.ts +42 -25
  23. package/src/mcp/receipts.ts +95 -0
  24. package/src/mcp/scheduled-task-view.ts +608 -0
  25. package/src/mcp/server.ts +812 -182
  26. package/src/mcp/toolspace.ts +75 -71
  27. package/src/observability.ts +3 -3
  28. package/src/routes/api-keys.ts +7 -1
  29. package/src/routes/codex.ts +7 -4
  30. package/src/routes/connections.ts +74 -3
  31. package/src/routes/enrollments.ts +54 -12
  32. package/src/routes/environments.ts +60 -11
  33. package/src/routes/files.ts +175 -65
  34. package/src/routes/install.ts +31 -1
  35. package/src/routes/machines.ts +1 -1
  36. package/src/routes/scheduled-tasks.ts +39 -14
  37. package/src/routes/sessions.ts +77 -12
  38. package/src/routes/transcription-recordings.ts +65 -33
  39. package/src/sandbox/auth-callout.ts +16 -4
  40. package/src/sandbox/channel-a.ts +124 -7
  41. package/src/sandbox/enrollment.ts +13 -3
  42. package/src/sandbox/machines.ts +1 -1
  43. package/src/sandbox/viewer.ts +29 -20
  44. package/dist/chunk-HWXJW5C7.js.map +0 -1
@@ -0,0 +1,350 @@
1
+ import type { ScheduledTask, ScheduledTaskScheduleSpec } from "@opengeni/contracts";
2
+ export declare const SCHEDULED_TASK_MCP_MAX_BYTES: number;
3
+ export declare const SCHEDULED_TASK_NAME_MAX_BYTES = 512;
4
+ export declare const SCHEDULED_TASK_PROMPT_MAX_BYTES: number;
5
+ export declare const SCHEDULED_TASK_SCHEDULE_FIELD_MAX_BYTES = 256;
6
+ type Utf8Projection = {
7
+ value: string;
8
+ originalBytes: number;
9
+ deliveredBytes: number;
10
+ truncated: boolean;
11
+ };
12
+ export type ScheduledTaskUtf8ProjectionFact = Omit<Utf8Projection, "value">;
13
+ type ScheduledTaskScheduleProjection = {
14
+ schedule: Extract<ScheduledTaskScheduleSpec, {
15
+ type: "once";
16
+ }>;
17
+ projection: {
18
+ type: "once";
19
+ truncated: boolean;
20
+ fields: {
21
+ runAt: ScheduledTaskUtf8ProjectionFact;
22
+ timeZone: ScheduledTaskUtf8ProjectionFact;
23
+ };
24
+ };
25
+ } | {
26
+ schedule: Extract<ScheduledTaskScheduleSpec, {
27
+ type: "interval";
28
+ }>;
29
+ projection: {
30
+ type: "interval";
31
+ truncated: boolean;
32
+ fields: {
33
+ startAt: ScheduledTaskUtf8ProjectionFact | null;
34
+ endAt: ScheduledTaskUtf8ProjectionFact | null;
35
+ };
36
+ };
37
+ } | {
38
+ schedule: Extract<ScheduledTaskScheduleSpec, {
39
+ type: "calendar";
40
+ }>;
41
+ projection: {
42
+ type: "calendar";
43
+ truncated: boolean;
44
+ fields: {
45
+ timeZone: ScheduledTaskUtf8ProjectionFact;
46
+ };
47
+ };
48
+ };
49
+ export declare function projectScheduledTaskUtf8(value: string, maxBytes: number): Utf8Projection;
50
+ export declare function projectScheduledTaskSchedule(schedule: ScheduledTaskScheduleSpec): ScheduledTaskScheduleProjection;
51
+ export declare function scheduledTaskMcpSummary(task: ScheduledTask): {
52
+ id: string;
53
+ name: string;
54
+ status: "active" | "paused";
55
+ schedule: {
56
+ type: "once";
57
+ runAt: string;
58
+ timeZone: string;
59
+ } | {
60
+ type: "interval";
61
+ everySeconds: number;
62
+ startAt?: string | undefined;
63
+ endAt?: string | undefined;
64
+ } | {
65
+ type: "calendar";
66
+ timeZone: string;
67
+ hour: number;
68
+ minute: number;
69
+ daysOfWeek?: ("FRIDAY" | "MONDAY" | "SATURDAY" | "SUNDAY" | "THURSDAY" | "TUESDAY" | "WEDNESDAY")[] | undefined;
70
+ };
71
+ runMode: "existing_session" | "new_session_per_run" | "reusable_session";
72
+ overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
73
+ targetSessionId: string | null;
74
+ reusableSessionId: string | null;
75
+ variableSetId: string | null;
76
+ rigId: string | null;
77
+ createdAt: string;
78
+ updatedAt: string;
79
+ configuration: {
80
+ model: string | null;
81
+ reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
82
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
83
+ hasGoal: boolean;
84
+ promptBytes: number;
85
+ resourceCount: number;
86
+ toolCount: number;
87
+ metadataKeyCount: number;
88
+ taskMetadataKeyCount: number;
89
+ };
90
+ projection: {
91
+ bounded: boolean;
92
+ name: ScheduledTaskUtf8ProjectionFact;
93
+ schedule: {
94
+ type: "once";
95
+ truncated: boolean;
96
+ fields: {
97
+ runAt: ScheduledTaskUtf8ProjectionFact;
98
+ timeZone: ScheduledTaskUtf8ProjectionFact;
99
+ };
100
+ } | {
101
+ type: "interval";
102
+ truncated: boolean;
103
+ fields: {
104
+ startAt: ScheduledTaskUtf8ProjectionFact | null;
105
+ endAt: ScheduledTaskUtf8ProjectionFact | null;
106
+ };
107
+ } | {
108
+ type: "calendar";
109
+ truncated: boolean;
110
+ fields: {
111
+ timeZone: ScheduledTaskUtf8ProjectionFact;
112
+ };
113
+ };
114
+ model: ScheduledTaskUtf8ProjectionFact | null;
115
+ createdAt: ScheduledTaskUtf8ProjectionFact;
116
+ updatedAt: ScheduledTaskUtf8ProjectionFact;
117
+ bytes: number;
118
+ maxBytes: number;
119
+ };
120
+ };
121
+ export declare function boundScheduledTaskDetailMcp(task: ScheduledTask): {
122
+ id: string;
123
+ name: string;
124
+ status: "active" | "paused";
125
+ schedule: {
126
+ type: "once";
127
+ runAt: string;
128
+ timeZone: string;
129
+ } | {
130
+ type: "interval";
131
+ everySeconds: number;
132
+ startAt?: string | undefined;
133
+ endAt?: string | undefined;
134
+ } | {
135
+ type: "calendar";
136
+ timeZone: string;
137
+ hour: number;
138
+ minute: number;
139
+ daysOfWeek?: ("FRIDAY" | "MONDAY" | "SATURDAY" | "SUNDAY" | "THURSDAY" | "TUESDAY" | "WEDNESDAY")[] | undefined;
140
+ };
141
+ runMode: "existing_session" | "new_session_per_run" | "reusable_session";
142
+ overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
143
+ targetSessionId: string | null;
144
+ reusableSessionId: string | null;
145
+ variableSetId: string | null;
146
+ rigId: string | null;
147
+ createdAt: string;
148
+ updatedAt: string;
149
+ configuration: {
150
+ model: string | null;
151
+ reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
152
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
153
+ hasGoal: boolean;
154
+ promptBytes: number;
155
+ resourceCount: number;
156
+ toolCount: number;
157
+ metadataKeyCount: number;
158
+ taskMetadataKeyCount: number;
159
+ };
160
+ projection: {
161
+ bounded: boolean;
162
+ name: ScheduledTaskUtf8ProjectionFact;
163
+ schedule: {
164
+ type: "once";
165
+ truncated: boolean;
166
+ fields: {
167
+ runAt: ScheduledTaskUtf8ProjectionFact;
168
+ timeZone: ScheduledTaskUtf8ProjectionFact;
169
+ };
170
+ } | {
171
+ type: "interval";
172
+ truncated: boolean;
173
+ fields: {
174
+ startAt: ScheduledTaskUtf8ProjectionFact | null;
175
+ endAt: ScheduledTaskUtf8ProjectionFact | null;
176
+ };
177
+ } | {
178
+ type: "calendar";
179
+ truncated: boolean;
180
+ fields: {
181
+ timeZone: ScheduledTaskUtf8ProjectionFact;
182
+ };
183
+ };
184
+ model: ScheduledTaskUtf8ProjectionFact | null;
185
+ createdAt: ScheduledTaskUtf8ProjectionFact;
186
+ updatedAt: ScheduledTaskUtf8ProjectionFact;
187
+ bytes: number;
188
+ maxBytes: number;
189
+ };
190
+ entity: {
191
+ agentConfig: {
192
+ prompt: string;
193
+ resources: Record<string, unknown>[];
194
+ tools: Record<string, unknown>[];
195
+ metadataKeys: string[];
196
+ model: string | null;
197
+ reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
198
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
199
+ goal: {
200
+ text: string;
201
+ successCriteria: string | null;
202
+ maxAutoContinuations: number | null;
203
+ } | null;
204
+ };
205
+ taskMetadataKeys: string[];
206
+ };
207
+ detailProjection: {
208
+ bounded: boolean;
209
+ fullEntityAvailableViaRest: boolean;
210
+ reducedForBytes: boolean;
211
+ terminal: boolean;
212
+ prompt: ScheduledTaskUtf8ProjectionFact;
213
+ goalText: ScheduledTaskUtf8ProjectionFact | null;
214
+ goalSuccessCriteria: ScheduledTaskUtf8ProjectionFact | null;
215
+ resources: {
216
+ originalCount: number;
217
+ deliveredCount: number;
218
+ originalBytes: number;
219
+ truncatedIdentityFieldCount: number;
220
+ };
221
+ tools: {
222
+ originalCount: number;
223
+ deliveredCount: number;
224
+ originalBytes: number;
225
+ truncatedIdentityFieldCount: number;
226
+ };
227
+ metadata: {
228
+ originalKeyCount: number;
229
+ deliveredKeyCount: number;
230
+ originalBytes: number;
231
+ truncatedKeyCount: number;
232
+ valuesIncluded: boolean;
233
+ };
234
+ taskMetadata: {
235
+ originalKeyCount: number;
236
+ deliveredKeyCount: number;
237
+ originalBytes: number;
238
+ truncatedKeyCount: number;
239
+ valuesIncluded: boolean;
240
+ };
241
+ bytes: number;
242
+ maxBytes: number;
243
+ };
244
+ };
245
+ export declare function boundScheduledTaskMcpPage(input: {
246
+ tasks: ScheduledTask[];
247
+ limit: number;
248
+ offset: number;
249
+ sourceHasMore: boolean;
250
+ maxBytes?: number;
251
+ }): {
252
+ tasks: {
253
+ id: string;
254
+ name: string;
255
+ status: "active" | "paused";
256
+ schedule: {
257
+ type: "once";
258
+ runAt: string;
259
+ timeZone: string;
260
+ } | {
261
+ type: "interval";
262
+ everySeconds: number;
263
+ startAt?: string | undefined;
264
+ endAt?: string | undefined;
265
+ } | {
266
+ type: "calendar";
267
+ timeZone: string;
268
+ hour: number;
269
+ minute: number;
270
+ daysOfWeek?: ("FRIDAY" | "MONDAY" | "SATURDAY" | "SUNDAY" | "THURSDAY" | "TUESDAY" | "WEDNESDAY")[] | undefined;
271
+ };
272
+ runMode: "existing_session" | "new_session_per_run" | "reusable_session";
273
+ overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
274
+ targetSessionId: string | null;
275
+ reusableSessionId: string | null;
276
+ variableSetId: string | null;
277
+ rigId: string | null;
278
+ createdAt: string;
279
+ updatedAt: string;
280
+ configuration: {
281
+ model: string | null;
282
+ reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
283
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
284
+ hasGoal: boolean;
285
+ promptBytes: number;
286
+ resourceCount: number;
287
+ toolCount: number;
288
+ metadataKeyCount: number;
289
+ taskMetadataKeyCount: number;
290
+ };
291
+ projection: {
292
+ bounded: boolean;
293
+ name: ScheduledTaskUtf8ProjectionFact;
294
+ schedule: {
295
+ type: "once";
296
+ truncated: boolean;
297
+ fields: {
298
+ runAt: ScheduledTaskUtf8ProjectionFact;
299
+ timeZone: ScheduledTaskUtf8ProjectionFact;
300
+ };
301
+ } | {
302
+ type: "interval";
303
+ truncated: boolean;
304
+ fields: {
305
+ startAt: ScheduledTaskUtf8ProjectionFact | null;
306
+ endAt: ScheduledTaskUtf8ProjectionFact | null;
307
+ };
308
+ } | {
309
+ type: "calendar";
310
+ truncated: boolean;
311
+ fields: {
312
+ timeZone: ScheduledTaskUtf8ProjectionFact;
313
+ };
314
+ };
315
+ model: ScheduledTaskUtf8ProjectionFact | null;
316
+ createdAt: ScheduledTaskUtf8ProjectionFact;
317
+ updatedAt: ScheduledTaskUtf8ProjectionFact;
318
+ bytes: number;
319
+ maxBytes: number;
320
+ };
321
+ }[];
322
+ page: {
323
+ limit: number;
324
+ offset: number;
325
+ hasMore: boolean;
326
+ nextOffset: number | null;
327
+ };
328
+ projection: {
329
+ bounded: boolean;
330
+ rowsDroppedForBytes: boolean;
331
+ droppedRowCount: number;
332
+ droppedRows: {
333
+ id: string;
334
+ nextAction: {
335
+ tool: string;
336
+ arguments: {
337
+ id: string;
338
+ includeEntity: boolean;
339
+ };
340
+ };
341
+ }[];
342
+ sourceRowsConsumed: number;
343
+ rowsReturned: number;
344
+ terminal: boolean;
345
+ reason?: string;
346
+ bytes: number;
347
+ maxBytes: number;
348
+ };
349
+ };
350
+ export {};
@@ -49,6 +49,15 @@ export declare function prepareToolspaceMcpSurface(input: {
49
49
  deps: ApiRouteDeps;
50
50
  grant: AccessGrant;
51
51
  }): Promise<ToolspaceMcpSurface | null>;
52
+ export type ToolspacePublicErrorFields = {
53
+ errorClass: "ToolspaceOperationError";
54
+ errorCode: ToolspacePublicFailureCode;
55
+ status?: number;
56
+ origin: "toolspace";
57
+ };
58
+ type ToolspacePublicFailureCode = "toolspace_operation_failed" | "tool_list_too_large" | "tool_result_too_large";
59
+ /** Allowlisted projection for public telemetry; product data stays exact. */
60
+ export declare function toolspacePublicErrorFields(error: unknown, errorCode?: ToolspacePublicFailureCode): ToolspacePublicErrorFields;
52
61
  export declare function toolspaceCanProxyServerId(serverId: string): boolean;
53
62
  export declare function connectionBrokerFetch(baseFetch: FetchLike, input: {
54
63
  deps: ApiRouteDeps;
@@ -4,6 +4,8 @@ import { type ResponderConnection } from "@opengeni/events";
4
4
  import type { Observability } from "@opengeni/observability";
5
5
  /** The NATS subject nats-server publishes authorization requests on (ADR-26). */
6
6
  export declare const AUTH_CALLOUT_SUBJECT = "$SYS.REQ.USER.AUTH";
7
+ /** Keep live NATS credentials short-lived while never outliving the bearer. */
8
+ export declare const NATS_USER_JWT_TTL_SECONDS: number;
7
9
  export interface AuthCalloutDeps {
8
10
  db: Database;
9
11
  settings: Settings;
@@ -3,7 +3,7 @@ import type { Session } from "@opengeni/contracts";
3
3
  import { type Database, type LeaseSnapshot } from "@opengeni/db";
4
4
  import { type EventBus } from "@opengeni/events";
5
5
  import { type Observability } from "@opengeni/observability";
6
- import { SandboxChannelAService, type RoutingSandboxSession } from "@opengeni/runtime/sandbox";
6
+ import { SandboxChannelAService, type EstablishedSandboxSession, type RoutingSandboxSession } from "@opengeni/runtime/sandbox";
7
7
  export type ChannelAServices = {
8
8
  db: Database;
9
9
  settings: Settings;
@@ -24,6 +24,10 @@ export type ChannelAHandle = {
24
24
  routingSession: RoutingSandboxSession;
25
25
  requestId: string;
26
26
  };
27
+ /** Reuse the exact lease-fenced provider handle across API-direct surfaces.
28
+ * Stream capability negotiation and the first Files/Changes reads commonly run
29
+ * back-to-back; sharing this handle avoids paying the same Modal resume twice. */
30
+ export declare function establishCachedChannelAHandle(workspaceId: string, sessionId: string, lease: LeaseSnapshot, establish: () => Promise<EstablishedSandboxSession>): Promise<EstablishedSandboxSession>;
27
31
  /**
28
32
  * Run a Channel-A op against a live box, API-direct. Acquires an exact direct holder
29
33
  * (warming the box when cold), resumes by id, builds the service, runs `fn`, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/api-router",
3
- "version": "0.22.2",
3
+ "version": "0.23.1",
4
4
  "description": "OpenGeni HTTP surface: the Hono adapter/router (createApp), routes, MCP HTTP transport, and HTTP access adapters over @opengeni/core. An engine-distribution surface — its runtime closure includes engine-internal packages.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -43,18 +43,18 @@
43
43
  "@hono/zod-validator": "^0.7.6",
44
44
  "@modelcontextprotocol/sdk": "^1.29.0",
45
45
  "@opengeni/agent-proto": "^0.3.0",
46
- "@opengeni/codex": "^0.2.11",
47
- "@opengeni/config": "^0.11.0",
48
- "@opengeni/contracts": "^0.39.0",
49
- "@opengeni/core": "^0.21.2",
50
- "@opengeni/db": "^0.28.1",
51
- "@opengeni/documents": "^0.5.10",
52
- "@opengeni/events": "^0.3.80",
53
- "@opengeni/github": "^0.4.31",
46
+ "@opengeni/codex": "^0.2.13",
47
+ "@opengeni/config": "^0.12.1",
48
+ "@opengeni/contracts": "^0.40.0",
49
+ "@opengeni/core": "^0.21.10",
50
+ "@opengeni/db": "^0.28.9",
51
+ "@opengeni/documents": "^0.5.18",
52
+ "@opengeni/events": "^0.3.88",
53
+ "@opengeni/github": "^0.4.38",
54
54
  "@opengeni/network": "^0.2.0",
55
- "@opengeni/observability": "^0.5.0",
56
- "@opengeni/runtime": "^0.18.17",
57
- "@opengeni/storage": "^0.2.68",
55
+ "@opengeni/observability": "^0.5.6",
56
+ "@opengeni/runtime": "^0.18.24",
57
+ "@opengeni/storage": "^0.2.75",
58
58
  "@temporalio/client": "^1.17.0",
59
59
  "better-auth": "^1.6.14",
60
60
  "hono": "^4.12.18",
package/src/app.ts CHANGED
@@ -307,7 +307,6 @@ export function createAppComposition(deps: AppDependencies): {
307
307
  const start = performance.now();
308
308
  const span = observability.startSpan(`HTTP ${c.req.method} ${route}`, {
309
309
  "http.request.method": c.req.method,
310
- "url.path": url.pathname,
311
310
  "opengeni.route": route,
312
311
  });
313
312
  try {
@@ -366,7 +365,7 @@ export function createAppComposition(deps: AppDependencies): {
366
365
  spanId: span.spanId,
367
366
  correlationId,
368
367
  errorCode,
369
- errorClass: error instanceof Error ? error.name : "NonErrorThrown",
368
+ errorClass: "HttpOperationError",
370
369
  });
371
370
  throw error;
372
371
  }
@@ -837,12 +836,12 @@ async function runReadinessChecks<const Checks extends Readonly<Record<string, R
837
836
  try {
838
837
  await withTimeout(Promise.resolve().then(check), timeoutMs);
839
838
  return [name, { ok: true }] as const;
840
- } catch (error) {
839
+ } catch {
841
840
  return [
842
841
  name,
843
842
  {
844
843
  ok: false,
845
- error: error instanceof Error ? error.message : String(error),
844
+ error: "dependency_unavailable",
846
845
  },
847
846
  ] as const;
848
847
  }
@@ -151,22 +151,6 @@ export function createManagedAuth(settings: Settings, db: Database): ManagedAuth
151
151
  }) as ManagedAuth;
152
152
  }
153
153
 
154
- export async function managedSessionAccessContext(
155
- auth: ManagedAuth,
156
- db: Database,
157
- headers: Headers,
158
- ) {
159
- const session = await auth.api.getSession({ headers });
160
- if (!session?.user) {
161
- return null;
162
- }
163
- return await ensureManagedAccessForUser(db, {
164
- userId: session.user.id,
165
- email: session.user.email,
166
- name: session.user.name,
167
- });
168
- }
169
-
170
154
  function betterAuthBaseUrl(settings: Settings) {
171
155
  const allowedHosts = splitCsv(settings.betterAuthAllowedHosts);
172
156
  if (allowedHosts.length === 0) {