@opengeni/api-router 0.2.2 → 0.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.
- package/dist/app.js +1 -1
- package/dist/{chunk-XSYUDIX3.js → chunk-I2EDWHVF.js} +82 -26
- package/dist/chunk-I2EDWHVF.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +10 -10
- package/src/mcp/server.ts +14 -1
- package/src/routes/sessions.ts +83 -31
- package/src/sandbox/viewer.ts +23 -0
- package/dist/chunk-XSYUDIX3.js.map +0 -1
package/dist/app.js
CHANGED
|
@@ -267,6 +267,7 @@ import { requireLimit as requireLimit8 } from "@opengeni/core";
|
|
|
267
267
|
// src/mcp/server.ts
|
|
268
268
|
import {
|
|
269
269
|
CreateScheduledTaskRequest,
|
|
270
|
+
SessionMcpCredentialUpdateInput,
|
|
270
271
|
WorkspaceEnvironmentVariableName,
|
|
271
272
|
UpdateScheduledTaskRequest
|
|
272
273
|
} from "@opengeni/contracts";
|
|
@@ -928,9 +929,17 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, json) {
|
|
|
928
929
|
description: "Spawn a new agent session (a worker) with an initial message and optional goal, resources (e.g. repositories from github_repositories_list), tools, and workspace environment attachment. Environment attachment happens at creation only \u2014 it cannot be added to a running session \u2014 and requires the environments:use permission. When targetSandboxId names a machine, workingDir sets the working directory (cwd) the spawned session runs under on that machine.",
|
|
929
930
|
inputSchema: {
|
|
930
931
|
initialMessage: z4.string().min(1),
|
|
932
|
+
// Per-session agent persona/system instructions for the spawned worker
|
|
933
|
+
// (a per-agent-type prompt). Delivered system-level, composed AFTER the
|
|
934
|
+
// workspace persona; never shown in the worker's timeline. Trimmed,
|
|
935
|
+
// non-empty, max 32768 chars (re-validated by the contracts schema).
|
|
936
|
+
instructions: z4.string().min(1).max(32768).optional(),
|
|
931
937
|
goal: z4.unknown().optional(),
|
|
932
938
|
resources: z4.array(z4.unknown()).optional(),
|
|
933
939
|
tools: z4.array(z4.unknown()).optional(),
|
|
940
|
+
// Per-session third-party MCP servers. Credential header values are
|
|
941
|
+
// accepted only at create and never appear in responses/events.
|
|
942
|
+
mcpServers: z4.array(z4.unknown()).optional(),
|
|
934
943
|
environmentId: z4.string().uuid().optional(),
|
|
935
944
|
model: z4.string().min(1).optional(),
|
|
936
945
|
reasoningEffort: z4.string().optional(),
|
|
@@ -989,12 +998,16 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, json) {
|
|
|
989
998
|
description: "Post a user message into an existing session; the session queues a turn and resumes if idle.",
|
|
990
999
|
inputSchema: {
|
|
991
1000
|
sessionId: z4.string().uuid(),
|
|
992
|
-
text: z4.string().min(1)
|
|
1001
|
+
text: z4.string().min(1),
|
|
1002
|
+
// Header-value rotation only. URL/name/tool settings are immutable
|
|
1003
|
+
// after create; core enforces mcp_servers:attach on this field.
|
|
1004
|
+
mcpCredentialUpdates: z4.array(z4.unknown()).optional()
|
|
993
1005
|
}
|
|
994
|
-
}, async ({ sessionId, text }) => {
|
|
1006
|
+
}, async ({ sessionId, text, mcpCredentialUpdates }) => {
|
|
995
1007
|
const { accepted, turn } = await acceptSessionUserMessage(deps, grant, grant.workspaceId, sessionId, {
|
|
996
1008
|
text,
|
|
997
|
-
toolsProvided: false
|
|
1009
|
+
toolsProvided: false,
|
|
1010
|
+
mcpCredentialUpdates: (mcpCredentialUpdates ?? []).map((update) => SessionMcpCredentialUpdateInput.parse(update))
|
|
998
1011
|
});
|
|
999
1012
|
return json({ event: accepted, turnId: turn.id });
|
|
1000
1013
|
});
|
|
@@ -4257,7 +4270,7 @@ import {
|
|
|
4257
4270
|
updatePtySessionActivity,
|
|
4258
4271
|
updateQueuedSessionTurn
|
|
4259
4272
|
} from "@opengeni/db";
|
|
4260
|
-
import { appendAndPublishEvents as appendAndPublishEvents4 } from "@opengeni/events";
|
|
4273
|
+
import { appendAndPublishEvents as appendAndPublishEvents4, coalesceSessionEventDeltas } from "@opengeni/events";
|
|
4261
4274
|
|
|
4262
4275
|
// src/sandbox/channel-a.ts
|
|
4263
4276
|
import { applyGitAuthPointerEnvironment, hasGitHubRepositorySelection, stableSandboxEnvironmentForRun } from "@opengeni/config";
|
|
@@ -4579,6 +4592,12 @@ function viewerHeartbeatIntervalMs(settings) {
|
|
|
4579
4592
|
async function dropEstablishedHandle2(established) {
|
|
4580
4593
|
void established;
|
|
4581
4594
|
}
|
|
4595
|
+
function resolveActiveDesktopTransport(selfhostedActive, interactive) {
|
|
4596
|
+
if (selfhostedActive) {
|
|
4597
|
+
return { transport: "relay-frames", client: "frames", mode: "read-only" };
|
|
4598
|
+
}
|
|
4599
|
+
return { transport: "vnc-ws", client: "novnc", mode: interactive ? "interactive" : "read-only" };
|
|
4600
|
+
}
|
|
4582
4601
|
async function mintDesktopStream(services, input) {
|
|
4583
4602
|
const { db, settings, bus } = services;
|
|
4584
4603
|
const { accountId, workspaceId, session } = input;
|
|
@@ -4883,7 +4902,7 @@ function viewerIdAsUuid(rawViewerId) {
|
|
|
4883
4902
|
}
|
|
4884
4903
|
|
|
4885
4904
|
// src/routes/sessions.ts
|
|
4886
|
-
import { settingsWithEnabledCapabilityMcpServers } from "@opengeni/core";
|
|
4905
|
+
import { settingsWithEnabledCapabilityMcpServers, settingsWithSessionMcpServerMetadata } from "@opengeni/core";
|
|
4887
4906
|
import {
|
|
4888
4907
|
normalizeResources,
|
|
4889
4908
|
validateFileResources,
|
|
@@ -5138,9 +5157,16 @@ function registerSessionRoutes(app, deps) {
|
|
|
5138
5157
|
await requireAccessGrant12(c, deps, workspaceId, "sessions:read");
|
|
5139
5158
|
const sessionId = c.req.param("sessionId");
|
|
5140
5159
|
await assertSessionExists(db, workspaceId, sessionId);
|
|
5141
|
-
const after =
|
|
5142
|
-
const
|
|
5143
|
-
|
|
5160
|
+
const after = eventSequence(c.req.query("after"), 0);
|
|
5161
|
+
const before = optionalEventSequence(c.req.query("before"));
|
|
5162
|
+
const compact = compactEvents(c.req.query("compact"));
|
|
5163
|
+
const limit = eventListLimit(c.req.query("limit"), compact ? 5e3 : 2e3);
|
|
5164
|
+
const events = await listSessionEvents3(db, workspaceId, sessionId, {
|
|
5165
|
+
after,
|
|
5166
|
+
...before !== void 0 ? { before } : {},
|
|
5167
|
+
limit
|
|
5168
|
+
});
|
|
5169
|
+
return c.json(compact ? coalesceSessionEventDeltas(events) : events);
|
|
5144
5170
|
});
|
|
5145
5171
|
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId/events/stream", async (c) => {
|
|
5146
5172
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -5166,14 +5192,17 @@ function registerSessionRoutes(app, deps) {
|
|
|
5166
5192
|
const existing = await requireQueuedTurnForApi(db, workspaceId, sessionId, turnId);
|
|
5167
5193
|
const payload = UpdateSessionTurnRequest.parse(await c.req.json());
|
|
5168
5194
|
assertConfiguredModel(settings, payload.model);
|
|
5169
|
-
const
|
|
5195
|
+
const session = await requireSession2(db, workspaceId, sessionId);
|
|
5196
|
+
const runtimeSettings = settingsWithSessionMcpServerMetadata(
|
|
5197
|
+
await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings),
|
|
5198
|
+
session.mcpServers
|
|
5199
|
+
);
|
|
5170
5200
|
const resources = payload.resources !== void 0 ? normalizeResources(payload.resources) : existing.resources;
|
|
5171
5201
|
const tools = payload.tools !== void 0 ? validateToolRefs(payload.tools, runtimeSettings) : existing.tools;
|
|
5172
5202
|
if (resources.some((resource) => resource.kind === "file") && !objectStorage) {
|
|
5173
5203
|
throw new HTTPException15(503, { message: "object storage is not configured" });
|
|
5174
5204
|
}
|
|
5175
5205
|
await validateFileResources(db, workspaceId, resources);
|
|
5176
|
-
const session = await requireSession2(db, workspaceId, sessionId);
|
|
5177
5206
|
await validateGitHubRepositorySelection(db, workspaceId, [...session.resources, ...resources]);
|
|
5178
5207
|
const turn = await updateQueuedSessionTurn(db, workspaceId, turnId, {
|
|
5179
5208
|
...payload.prompt !== void 0 ? { prompt: payload.prompt.trim() } : {},
|
|
@@ -5234,6 +5263,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
5234
5263
|
toolsProvided: userMessagePayloadHasOwnProperty(rawEvent, "tools"),
|
|
5235
5264
|
model: event.payload.model ?? null,
|
|
5236
5265
|
reasoningEffort: event.payload.reasoningEffort ?? null,
|
|
5266
|
+
mcpCredentialUpdates: event.payload.mcpCredentialUpdates ?? [],
|
|
5237
5267
|
...event.clientEventId ? { clientEventId: event.clientEventId } : {}
|
|
5238
5268
|
});
|
|
5239
5269
|
return c.json(accepted2, 202);
|
|
@@ -5361,19 +5391,13 @@ function registerSessionRoutes(app, deps) {
|
|
|
5361
5391
|
} : {}
|
|
5362
5392
|
});
|
|
5363
5393
|
let responseCapabilities = capabilities;
|
|
5364
|
-
if (
|
|
5365
|
-
const activeSandbox = await getSandbox2(db, workspaceId, session.activeSandboxId);
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
transport: "relay-frames",
|
|
5372
|
-
client: "frames",
|
|
5373
|
-
mode: "read-only"
|
|
5374
|
-
}
|
|
5375
|
-
};
|
|
5376
|
-
}
|
|
5394
|
+
if (capabilities.DesktopStream.transport !== null) {
|
|
5395
|
+
const activeSandbox = session.activeSandboxId ? await getSandbox2(db, workspaceId, session.activeSandboxId) : null;
|
|
5396
|
+
const wire = resolveActiveDesktopTransport(activeSandbox?.kind === "selfhosted", settings.sandboxDesktopInteractive !== false);
|
|
5397
|
+
responseCapabilities = {
|
|
5398
|
+
...capabilities,
|
|
5399
|
+
DesktopStream: { ...capabilities.DesktopStream, ...wire }
|
|
5400
|
+
};
|
|
5377
5401
|
}
|
|
5378
5402
|
return c.json(responseCapabilities);
|
|
5379
5403
|
});
|
|
@@ -5497,8 +5521,13 @@ function registerSessionRoutes(app, deps) {
|
|
|
5497
5521
|
streamToken: stream?.token ?? null,
|
|
5498
5522
|
streamExpiresAt: stream?.expiresAt ?? null,
|
|
5499
5523
|
resolution: stream?.resolution ?? null,
|
|
5500
|
-
|
|
5501
|
-
|
|
5524
|
+
// Transport MUST match where the pixels were minted: a selfhosted-active box
|
|
5525
|
+
// serves the RELAY framebuffer (relay-frames/frames), a Modal box serves noVNC
|
|
5526
|
+
// (vnc-ws/novnc). Hardcoding vnc-ws here handed a machine's relay URL to the
|
|
5527
|
+
// noVNC renderer (and vice-versa on the swap-away case) → "closed before it
|
|
5528
|
+
// opened". Key off the SAME selfhostedActive the mint routed on.
|
|
5529
|
+
transport: stream ? selfhostedActive ? "relay-frames" : "vnc-ws" : null,
|
|
5530
|
+
client: stream ? selfhostedActive ? "frames" : "novnc" : null,
|
|
5502
5531
|
// The REAL PTY terminal address (pty-ws), null when degraded.
|
|
5503
5532
|
terminalUrl: terminal?.url ?? null,
|
|
5504
5533
|
terminalToken: terminal?.token ?? null,
|
|
@@ -5727,6 +5756,33 @@ function registerSessionRoutes(app, deps) {
|
|
|
5727
5756
|
return c.body(null, 204);
|
|
5728
5757
|
});
|
|
5729
5758
|
}
|
|
5759
|
+
function eventListLimit(raw, max = 2e3) {
|
|
5760
|
+
const limit = Number(raw ?? 500);
|
|
5761
|
+
if (!Number.isFinite(limit)) {
|
|
5762
|
+
return 500;
|
|
5763
|
+
}
|
|
5764
|
+
return Math.min(max, Math.max(1, Math.floor(limit)));
|
|
5765
|
+
}
|
|
5766
|
+
function compactEvents(raw) {
|
|
5767
|
+
return raw === "1" || raw === "true";
|
|
5768
|
+
}
|
|
5769
|
+
function eventSequence(raw, fallback) {
|
|
5770
|
+
const sequence = Number(raw ?? fallback);
|
|
5771
|
+
if (!Number.isFinite(sequence)) {
|
|
5772
|
+
return fallback;
|
|
5773
|
+
}
|
|
5774
|
+
return Math.floor(sequence);
|
|
5775
|
+
}
|
|
5776
|
+
function optionalEventSequence(raw) {
|
|
5777
|
+
if (raw === void 0) {
|
|
5778
|
+
return void 0;
|
|
5779
|
+
}
|
|
5780
|
+
const sequence = Number(raw);
|
|
5781
|
+
if (!Number.isFinite(sequence)) {
|
|
5782
|
+
return void 0;
|
|
5783
|
+
}
|
|
5784
|
+
return Math.floor(sequence);
|
|
5785
|
+
}
|
|
5730
5786
|
function hasOwnProperty(value, key) {
|
|
5731
5787
|
return Boolean(value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, key));
|
|
5732
5788
|
}
|
|
@@ -6328,4 +6384,4 @@ export {
|
|
|
6328
6384
|
withDefaultEnabledCapabilityMcpTools,
|
|
6329
6385
|
workflowIdForSession3 as workflowIdForSession
|
|
6330
6386
|
};
|
|
6331
|
-
//# sourceMappingURL=chunk-
|
|
6387
|
+
//# sourceMappingURL=chunk-I2EDWHVF.js.map
|