@opengeni/api-router 0.21.14 → 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.
- package/dist/app.d.ts +1 -0
- package/dist/app.js +1 -1
- package/dist/auth/managed-auth.d.ts +0 -30
- package/dist/{chunk-R5PDSH2A.js → chunk-T4T2PGU4.js} +3989 -1356
- package/dist/chunk-T4T2PGU4.js.map +1 -0
- package/dist/http/sse.d.ts +2 -0
- package/dist/index.js +29 -9
- package/dist/index.js.map +1 -1
- package/dist/integrations/oauth-client.d.ts +8 -0
- package/dist/integrations/slack-interactions.d.ts +7 -1
- package/dist/mcp/receipts.d.ts +28 -0
- package/dist/mcp/scheduled-task-view.d.ts +350 -0
- package/dist/mcp/toolspace.d.ts +9 -0
- package/dist/routes/transcription-recordings.d.ts +3 -0
- package/dist/sandbox/auth-callout.d.ts +2 -0
- package/dist/sandbox/channel-a.d.ts +5 -1
- package/dist/transcription/segmenter.d.ts +10 -0
- package/dist/transcription/service.d.ts +5 -0
- package/package.json +12 -12
- package/src/app.ts +39 -6
- package/src/auth/managed-auth.ts +0 -16
- package/src/http/sse.ts +101 -6
- package/src/index.ts +28 -3
- package/src/integrations/oauth-client.ts +36 -56
- package/src/integrations/slack-interactions.ts +123 -15
- package/src/mcp/documents.ts +42 -25
- package/src/mcp/receipts.ts +95 -0
- package/src/mcp/scheduled-task-view.ts +608 -0
- package/src/mcp/server.ts +812 -182
- package/src/mcp/toolspace.ts +75 -71
- package/src/observability.ts +3 -3
- package/src/routes/api-keys.ts +7 -1
- package/src/routes/codex.ts +7 -4
- package/src/routes/connections.ts +74 -3
- package/src/routes/enrollments.ts +54 -12
- package/src/routes/environments.ts +60 -11
- package/src/routes/files.ts +175 -65
- package/src/routes/install.ts +31 -1
- package/src/routes/machines.ts +1 -1
- package/src/routes/scheduled-tasks.ts +39 -14
- package/src/routes/sessions.ts +77 -12
- package/src/routes/transcription-recordings.ts +754 -0
- package/src/routes/transcriptions.ts +2 -0
- package/src/sandbox/auth-callout.ts +16 -4
- package/src/sandbox/channel-a.ts +124 -7
- package/src/sandbox/enrollment.ts +13 -3
- package/src/sandbox/machines.ts +1 -1
- package/src/sandbox/viewer.ts +29 -20
- package/src/transcription/providers/azure-openai.ts +4 -3
- package/src/transcription/providers/codex-subscription.ts +4 -1
- package/src/transcription/providers/openai.ts +7 -2
- package/src/transcription/segmenter.ts +260 -0
- package/src/transcription/service.ts +111 -10
- package/dist/chunk-R5PDSH2A.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 {};
|
package/dist/mcp/toolspace.d.ts
CHANGED
|
@@ -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
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TranscriptionSegmenter } from "@opengeni/core";
|
|
2
|
+
export declare class TranscriptionSegmenterError extends Error {
|
|
3
|
+
readonly code: "unavailable" | "invalid_audio" | "cancelled" | "too_large" | "unknown";
|
|
4
|
+
readonly retryable: boolean;
|
|
5
|
+
readonly name = "TranscriptionSegmenterError";
|
|
6
|
+
constructor(message: string, code: "unavailable" | "invalid_audio" | "cancelled" | "too_large" | "unknown", retryable: boolean);
|
|
7
|
+
}
|
|
8
|
+
export declare function createFfmpegTranscriptionSegmenter(input: {
|
|
9
|
+
ffmpegPath: string;
|
|
10
|
+
}): TranscriptionSegmenter;
|
|
@@ -7,4 +7,9 @@ export declare function createTranscriptionService(input: {
|
|
|
7
7
|
fetch?: typeof fetch;
|
|
8
8
|
codexFetch?: typeof fetch;
|
|
9
9
|
probeCodex?: (context?: TranscriptionAvailabilityContext) => boolean | Promise<boolean>;
|
|
10
|
+
/** Test seam for exercising timeout and late-completion behavior quickly. */
|
|
11
|
+
providerRequestTimeoutMilliseconds?: number;
|
|
12
|
+
/** Test seam for evaluating persisted absolute deadlines after delayed setup. */
|
|
13
|
+
now?: () => Date;
|
|
10
14
|
}): TranscriptionService;
|
|
15
|
+
export declare function remainingTranscriptionProviderRequestMilliseconds(providerDeadlineAt: Date, now: Date): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/api-router",
|
|
3
|
-
"version": "0.
|
|
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.
|
|
47
|
-
"@opengeni/config": "^0.
|
|
48
|
-
"@opengeni/contracts": "^0.
|
|
49
|
-
"@opengeni/core": "^0.
|
|
50
|
-
"@opengeni/db": "^0.
|
|
51
|
-
"@opengeni/documents": "^0.5.
|
|
52
|
-
"@opengeni/events": "^0.3.
|
|
53
|
-
"@opengeni/github": "^0.4.
|
|
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.
|
|
56
|
-
"@opengeni/runtime": "^0.18.
|
|
57
|
-
"@opengeni/storage": "^0.2.
|
|
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
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
OPENGENI_CORRELATION_HEADER,
|
|
14
14
|
resolveWorkspaceMemoryEnabled,
|
|
15
15
|
VOICE_INPUT_ACCEPTED_MIME_TYPES,
|
|
16
|
+
TRANSCRIPTION_RECORDING_PROVIDER_SEGMENT_SECONDS,
|
|
16
17
|
type AccessGrant,
|
|
17
18
|
type ErrorCode,
|
|
18
19
|
} from "@opengeni/contracts";
|
|
@@ -77,6 +78,7 @@ import { registerInsightsRoutes } from "./routes/insights";
|
|
|
77
78
|
import { registerTranscriptionRoutes } from "./routes/transcriptions";
|
|
78
79
|
import { projectClientModel } from "./model-catalog";
|
|
79
80
|
import { createTranscriptionService } from "./transcription/service";
|
|
81
|
+
import { createFfmpegTranscriptionSegmenter } from "./transcription/segmenter";
|
|
80
82
|
import { registerSlackInteractionRoutes } from "./integrations/slack-interactions";
|
|
81
83
|
|
|
82
84
|
export type {
|
|
@@ -103,8 +105,15 @@ export { replaySessionEvents, sseSessionStream, sseWorkspaceControlStream } from
|
|
|
103
105
|
export const API_MAX_REQUEST_BODY_BYTES = 8 * 1024 * 1024;
|
|
104
106
|
|
|
105
107
|
/** Effective Hono bodyLimit — API JSON ceiling or voice multipart + multipart overhead. */
|
|
106
|
-
export function apiRequestBodyLimitBytes(settings: {
|
|
107
|
-
|
|
108
|
+
export function apiRequestBodyLimitBytes(settings: {
|
|
109
|
+
voiceInputMaxSizeBytes: number;
|
|
110
|
+
voiceInputResumableMaxChunkSizeBytes?: number;
|
|
111
|
+
}): number {
|
|
112
|
+
return Math.max(
|
|
113
|
+
API_MAX_REQUEST_BODY_BYTES,
|
|
114
|
+
settings.voiceInputMaxSizeBytes + 64 * 1024,
|
|
115
|
+
(settings.voiceInputResumableMaxChunkSizeBytes ?? 0) + 64 * 1024,
|
|
116
|
+
);
|
|
108
117
|
}
|
|
109
118
|
const API_PUBLIC_ERROR_MESSAGE_MAX_BYTES = 512;
|
|
110
119
|
|
|
@@ -204,6 +213,12 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
204
213
|
...(deps.codexFetch ? { codexFetch: deps.codexFetch } : {}),
|
|
205
214
|
})
|
|
206
215
|
: deps.transcription;
|
|
216
|
+
const transcriptionSegmenter =
|
|
217
|
+
deps.transcriptionSegmenter === undefined
|
|
218
|
+
? createFfmpegTranscriptionSegmenter({
|
|
219
|
+
ffmpegPath: deps.settings.voiceInputFfmpegPath,
|
|
220
|
+
})
|
|
221
|
+
: deps.transcriptionSegmenter;
|
|
207
222
|
const routeDeps: ApiRouteDeps = {
|
|
208
223
|
...deps,
|
|
209
224
|
observability,
|
|
@@ -214,6 +229,7 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
214
229
|
documentIndexer,
|
|
215
230
|
getDocumentServices,
|
|
216
231
|
transcription,
|
|
232
|
+
transcriptionSegmenter,
|
|
217
233
|
...(sandboxClient ? { sandboxClient } : {}),
|
|
218
234
|
resumeBoxById,
|
|
219
235
|
};
|
|
@@ -291,7 +307,6 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
291
307
|
const start = performance.now();
|
|
292
308
|
const span = observability.startSpan(`HTTP ${c.req.method} ${route}`, {
|
|
293
309
|
"http.request.method": c.req.method,
|
|
294
|
-
"url.path": url.pathname,
|
|
295
310
|
"opengeni.route": route,
|
|
296
311
|
});
|
|
297
312
|
try {
|
|
@@ -350,7 +365,7 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
350
365
|
spanId: span.spanId,
|
|
351
366
|
correlationId,
|
|
352
367
|
errorCode,
|
|
353
|
-
errorClass:
|
|
368
|
+
errorClass: "HttpOperationError",
|
|
354
369
|
});
|
|
355
370
|
throw error;
|
|
356
371
|
}
|
|
@@ -440,6 +455,24 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
440
455
|
maxDurationSeconds: deps.settings.voiceInputMaxDurationSeconds,
|
|
441
456
|
maxSizeBytes: deps.settings.voiceInputMaxSizeBytes,
|
|
442
457
|
acceptedMimeTypes: [...VOICE_INPUT_ACCEPTED_MIME_TYPES],
|
|
458
|
+
...(deps.settings.voiceInputResumableEnabled &&
|
|
459
|
+
objectStorage &&
|
|
460
|
+
transcription &&
|
|
461
|
+
transcriptionSegmenter &&
|
|
462
|
+
(await transcription.available()) &&
|
|
463
|
+
(await transcriptionSegmenter.available())
|
|
464
|
+
? {
|
|
465
|
+
resumable: {
|
|
466
|
+
maxDurationSeconds: deps.settings.voiceInputResumableMaxDurationSeconds,
|
|
467
|
+
maxSizeBytes: deps.settings.voiceInputResumableMaxSizeBytes,
|
|
468
|
+
maxChunkSizeBytes: deps.settings.voiceInputResumableMaxChunkSizeBytes,
|
|
469
|
+
providerSegmentSeconds: Math.min(
|
|
470
|
+
TRANSCRIPTION_RECORDING_PROVIDER_SEGMENT_SECONDS,
|
|
471
|
+
deps.settings.voiceInputMaxDurationSeconds,
|
|
472
|
+
),
|
|
473
|
+
},
|
|
474
|
+
}
|
|
475
|
+
: {}),
|
|
443
476
|
},
|
|
444
477
|
productAccessMode: deps.settings.productAccessMode,
|
|
445
478
|
auth: clientAuthConfig(deps.settings),
|
|
@@ -803,12 +836,12 @@ async function runReadinessChecks<const Checks extends Readonly<Record<string, R
|
|
|
803
836
|
try {
|
|
804
837
|
await withTimeout(Promise.resolve().then(check), timeoutMs);
|
|
805
838
|
return [name, { ok: true }] as const;
|
|
806
|
-
} catch
|
|
839
|
+
} catch {
|
|
807
840
|
return [
|
|
808
841
|
name,
|
|
809
842
|
{
|
|
810
843
|
ok: false,
|
|
811
|
-
error:
|
|
844
|
+
error: "dependency_unavailable",
|
|
812
845
|
},
|
|
813
846
|
] as const;
|
|
814
847
|
}
|
package/src/auth/managed-auth.ts
CHANGED
|
@@ -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) {
|