@opengeni/api-router 2.10.0-canary.2 → 2.10.0-canary.4
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-BVX5ASFY.js → chunk-NWSVDE7O.js} +70 -21
- package/dist/{chunk-BVX5ASFY.js.map → chunk-NWSVDE7O.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp/scheduled-task-view.d.ts +3 -3
- package/package.json +19 -19
- package/src/app.ts +4 -0
- package/src/routes/codex.ts +1 -1
- package/src/routes/video-generation.ts +2 -1
- package/src/routes/workspace-artifacts.ts +17 -3
- package/src/routes/workspace-learning.ts +5 -4
- package/src/routes/workspaces.ts +47 -10
package/dist/index.js
CHANGED
|
@@ -82,8 +82,8 @@ export declare function scheduledTaskMcpSummary(task: ScheduledTask): {
|
|
|
82
82
|
runMode: "existing_session" | "new_session_per_run" | "reusable_session";
|
|
83
83
|
overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
|
|
84
84
|
action: {
|
|
85
|
-
readonly sourceId?: never;
|
|
86
85
|
kind: "agent_turn";
|
|
86
|
+
sourceId?: never;
|
|
87
87
|
sourceGeneration?: never;
|
|
88
88
|
sourceLifecycleGeneration?: never;
|
|
89
89
|
destination?: never;
|
|
@@ -205,8 +205,8 @@ export declare function boundScheduledTaskDetailMcp(task: ScheduledTask): {
|
|
|
205
205
|
runMode: "existing_session" | "new_session_per_run" | "reusable_session";
|
|
206
206
|
overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
|
|
207
207
|
action: {
|
|
208
|
-
readonly sourceId?: never;
|
|
209
208
|
kind: "agent_turn";
|
|
209
|
+
sourceId?: never;
|
|
210
210
|
sourceGeneration?: never;
|
|
211
211
|
sourceLifecycleGeneration?: never;
|
|
212
212
|
destination?: never;
|
|
@@ -389,8 +389,8 @@ export declare function boundScheduledTaskMcpPage(input: {
|
|
|
389
389
|
runMode: "existing_session" | "new_session_per_run" | "reusable_session";
|
|
390
390
|
overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
|
|
391
391
|
action: {
|
|
392
|
-
readonly sourceId?: never;
|
|
393
392
|
kind: "agent_turn";
|
|
393
|
+
sourceId?: never;
|
|
394
394
|
sourceGeneration?: never;
|
|
395
395
|
sourceLifecycleGeneration?: never;
|
|
396
396
|
destination?: never;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/api-router",
|
|
3
|
-
"version": "2.10.0-canary.
|
|
3
|
+
"version": "2.10.0-canary.4",
|
|
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,24 +43,24 @@
|
|
|
43
43
|
"@hono/zod-validator": "^0.7.6",
|
|
44
44
|
"@llamaindex/liteparse": "2.14.2",
|
|
45
45
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
46
|
-
"@opengeni/agent-proto": "^0.5.1-canary.
|
|
47
|
-
"@opengeni/artifact-tool": "^0.3.19-canary.
|
|
48
|
-
"@opengeni/capabilities": "^0.3.2-canary.
|
|
49
|
-
"@opengeni/codemode": "^0.4.27-canary.
|
|
50
|
-
"@opengeni/codex": "^0.2.21-canary.
|
|
51
|
-
"@opengeni/config": "^1.0.0-canary.
|
|
52
|
-
"@opengeni/contracts": "^2.13.0-canary.
|
|
53
|
-
"@opengeni/core": "^2.7.5-canary.
|
|
54
|
-
"@opengeni/db": "^4.0.0-canary.
|
|
55
|
-
"@opengeni/documents": "^0.8.19-canary.
|
|
56
|
-
"@opengeni/events": "^0.4.17-canary.
|
|
57
|
-
"@opengeni/github": "^0.7.3-canary.
|
|
58
|
-
"@opengeni/network": "^0.3.0-canary.
|
|
59
|
-
"@opengeni/observability": "^0.8.19-canary.
|
|
60
|
-
"@opengeni/runtime": "^2.3.0-canary.
|
|
61
|
-
"@opengeni/storage": "^0.2.120-canary.
|
|
62
|
-
"@opengeni/tool-gateway": "^0.1.0-canary.
|
|
63
|
-
"@opengeni/xai-subscription": "^0.1.3-canary.
|
|
46
|
+
"@opengeni/agent-proto": "^0.5.1-canary.13",
|
|
47
|
+
"@opengeni/artifact-tool": "^0.3.19-canary.4",
|
|
48
|
+
"@opengeni/capabilities": "^0.3.2-canary.4",
|
|
49
|
+
"@opengeni/codemode": "^0.4.27-canary.4",
|
|
50
|
+
"@opengeni/codex": "^0.2.21-canary.4",
|
|
51
|
+
"@opengeni/config": "^1.0.0-canary.4",
|
|
52
|
+
"@opengeni/contracts": "^2.13.0-canary.4",
|
|
53
|
+
"@opengeni/core": "^2.7.5-canary.4",
|
|
54
|
+
"@opengeni/db": "^4.0.0-canary.4",
|
|
55
|
+
"@opengeni/documents": "^0.8.19-canary.4",
|
|
56
|
+
"@opengeni/events": "^0.4.17-canary.4",
|
|
57
|
+
"@opengeni/github": "^0.7.3-canary.4",
|
|
58
|
+
"@opengeni/network": "^0.3.0-canary.4",
|
|
59
|
+
"@opengeni/observability": "^0.8.19-canary.4",
|
|
60
|
+
"@opengeni/runtime": "^2.3.0-canary.4",
|
|
61
|
+
"@opengeni/storage": "^0.2.120-canary.4",
|
|
62
|
+
"@opengeni/tool-gateway": "^0.1.0-canary.4",
|
|
63
|
+
"@opengeni/xai-subscription": "^0.1.3-canary.4",
|
|
64
64
|
"@temporalio/client": "^1.17.0",
|
|
65
65
|
"better-auth": "^1.6.14",
|
|
66
66
|
"hono": "^4.12.18",
|
package/src/app.ts
CHANGED
|
@@ -1974,6 +1974,10 @@ const routeLabelPatterns: Array<{
|
|
|
1974
1974
|
pattern: /^\/v1\/workspaces\/[^/]+\/inference-control$/,
|
|
1975
1975
|
label: "/v1/workspaces/:workspaceId/inference-control",
|
|
1976
1976
|
},
|
|
1977
|
+
{
|
|
1978
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/pause-timer$/,
|
|
1979
|
+
label: "/v1/workspaces/:workspaceId/pause-timer",
|
|
1980
|
+
},
|
|
1977
1981
|
{
|
|
1978
1982
|
pattern:
|
|
1979
1983
|
/^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/fs\/(list|list-batch|read|write|delete|move|mkdir)$/,
|
package/src/routes/codex.ts
CHANGED
|
@@ -1214,7 +1214,7 @@ export function registerCodexRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
1214
1214
|
accountId: grant.accountId,
|
|
1215
1215
|
workspaceId,
|
|
1216
1216
|
subjectId: grant.subjectId,
|
|
1217
|
-
mode:
|
|
1217
|
+
mode: "workspace",
|
|
1218
1218
|
effectiveSourceBeforeMutation: sourceBeforeConnect.effectiveSource,
|
|
1219
1219
|
});
|
|
1220
1220
|
const rotation = await getCodexRotationSettings(tx, workspaceId);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "@opengeni/db";
|
|
15
15
|
import {
|
|
16
16
|
requireAccessGrant,
|
|
17
|
+
requireWorkspaceSettingsGrant,
|
|
17
18
|
VIDEO_GENERATION_MODEL_CATALOG,
|
|
18
19
|
videoGenerationModelSupportsFundingSource,
|
|
19
20
|
videoGenerationCapabilitiesForPolicy,
|
|
@@ -58,7 +59,7 @@ export function registerVideoGenerationRoutes(app: Hono, deps: ApiRouteDeps): vo
|
|
|
58
59
|
|
|
59
60
|
app.put("/v1/workspaces/:workspaceId/video-generation/policy", async (c) => {
|
|
60
61
|
const workspaceId = c.req.param("workspaceId");
|
|
61
|
-
const grant = await
|
|
62
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
62
63
|
const payload = UpdateVideoGenerationPolicyRequest.parse(await c.req.json());
|
|
63
64
|
const [connection, supergrokConfigured] = await Promise.all([
|
|
64
65
|
getWorkspaceVercelAiGatewayConnectionMetadata(deps.db, workspaceId),
|
|
@@ -181,7 +181,9 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
181
181
|
const workspaceId = context.req.param("workspaceId");
|
|
182
182
|
await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
|
|
183
183
|
if (!deps.objectStorage)
|
|
184
|
-
throw new HTTPException(503, {
|
|
184
|
+
throw new HTTPException(503, {
|
|
185
|
+
message: "Object storage is not configured",
|
|
186
|
+
});
|
|
185
187
|
const ref = await getWorkspaceArtifactContentRef(
|
|
186
188
|
deps.db,
|
|
187
189
|
workspaceId,
|
|
@@ -193,13 +195,20 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
193
195
|
|
|
194
196
|
app.get(base, async (context) => {
|
|
195
197
|
const workspaceId = context.req.param("workspaceId");
|
|
196
|
-
await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
|
|
198
|
+
const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
|
|
197
199
|
const query = WorkspaceArtifactListQuery.safeParse({
|
|
198
200
|
limit: context.req.query("limit"),
|
|
199
201
|
cursor: context.req.query("cursor"),
|
|
200
202
|
status: context.req.query("status"),
|
|
203
|
+
sourceSessionId: context.req.query("sourceSessionId"),
|
|
201
204
|
});
|
|
202
205
|
if (!query.success) throw new HTTPException(422, { message: "Invalid artifact list query" });
|
|
206
|
+
if (
|
|
207
|
+
query.data.sourceSessionId &&
|
|
208
|
+
!(await canReadProvenanceSession(deps, grant, query.data.sourceSessionId))
|
|
209
|
+
) {
|
|
210
|
+
throw new HTTPException(404, { message: "Session not found" });
|
|
211
|
+
}
|
|
203
212
|
try {
|
|
204
213
|
return context.json(
|
|
205
214
|
WorkspaceArtifactListResponse.parse(
|
|
@@ -208,6 +217,9 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
208
217
|
limit: query.data.limit,
|
|
209
218
|
...(query.data.cursor ? { cursor: query.data.cursor } : {}),
|
|
210
219
|
...(query.data.status ? { status: query.data.status } : {}),
|
|
220
|
+
...(query.data.sourceSessionId
|
|
221
|
+
? { sourceSessionId: query.data.sourceSessionId }
|
|
222
|
+
: {}),
|
|
211
223
|
}),
|
|
212
224
|
),
|
|
213
225
|
),
|
|
@@ -281,7 +293,9 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
281
293
|
const workspaceId = context.req.param("workspaceId");
|
|
282
294
|
await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
|
|
283
295
|
if (!deps.objectStorage)
|
|
284
|
-
throw new HTTPException(503, {
|
|
296
|
+
throw new HTTPException(503, {
|
|
297
|
+
message: "Object storage is not configured",
|
|
298
|
+
});
|
|
285
299
|
const ref = await getWorkspaceArtifactContentRef(
|
|
286
300
|
deps.db,
|
|
287
301
|
workspaceId,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
publishGovernedLearningEventToSlack,
|
|
14
14
|
requireAccessGrant,
|
|
15
|
+
requireWorkspaceSettingsGrant,
|
|
15
16
|
type ApiRouteDeps,
|
|
16
17
|
} from "@opengeni/core";
|
|
17
18
|
import {
|
|
@@ -122,7 +123,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
122
123
|
|
|
123
124
|
app.post(`${base}/revisions`, async (context) => {
|
|
124
125
|
const workspaceId = context.req.param("workspaceId");
|
|
125
|
-
const grant = await
|
|
126
|
+
const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
|
|
126
127
|
const request = await parseBody(context, CreateWorkspaceLearningPolicyRevisionRequest);
|
|
127
128
|
try {
|
|
128
129
|
return context.json(
|
|
@@ -149,7 +150,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
149
150
|
const workspaceId = context.req.param("workspaceId");
|
|
150
151
|
const revisionId = z.string().uuid().safeParse(context.req.param("revisionId"));
|
|
151
152
|
if (!revisionId.success) throw new HTTPException(422, { message: "Invalid revision id" });
|
|
152
|
-
const grant = await
|
|
153
|
+
const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
|
|
153
154
|
const request = await parseBody(context, ActivateWorkspaceLearningPolicyRevisionRequest);
|
|
154
155
|
try {
|
|
155
156
|
return context.json(
|
|
@@ -174,7 +175,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
174
175
|
|
|
175
176
|
app.post(`${base}/rollback`, async (context) => {
|
|
176
177
|
const workspaceId = context.req.param("workspaceId");
|
|
177
|
-
const grant = await
|
|
178
|
+
const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
|
|
178
179
|
const request = await parseBody(context, RollbackWorkspaceLearningPolicyRevisionRequest);
|
|
179
180
|
try {
|
|
180
181
|
return context.json(
|
|
@@ -206,7 +207,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
|
|
|
206
207
|
if (!activationReceiptId.success) {
|
|
207
208
|
throw new HTTPException(422, { message: "Invalid activation receipt id" });
|
|
208
209
|
}
|
|
209
|
-
const grant = await
|
|
210
|
+
const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
|
|
210
211
|
const request = await parseBody(context, UndoGovernedLearningActivationHttpRequest);
|
|
211
212
|
try {
|
|
212
213
|
const undo = await undoGovernedLearningActivation(deps.db, {
|
package/src/routes/workspaces.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SessionControlConflictError, WorkspacePauseTimerInputError } from "@opengeni/db";
|
|
2
|
+
import { WorkspacePauseTimerRequest } from "@opengeni/contracts";
|
|
1
3
|
import { createHash } from "node:crypto";
|
|
2
4
|
import {
|
|
3
5
|
AddWorkspaceMemberRequest,
|
|
@@ -86,6 +88,7 @@ import {
|
|
|
86
88
|
hasPermission,
|
|
87
89
|
requireAccessContext,
|
|
88
90
|
requireAccessGrant,
|
|
91
|
+
requireWorkspaceSettingsGrant,
|
|
89
92
|
requireFreshAccessGrant,
|
|
90
93
|
resolveWorkspaceCatalogSettings,
|
|
91
94
|
} from "@opengeni/core";
|
|
@@ -95,6 +98,7 @@ import {
|
|
|
95
98
|
assertWorkspaceMemberRemovable,
|
|
96
99
|
assertWorkspaceMemberUpdateAllowed,
|
|
97
100
|
controlHumanWorkspace,
|
|
101
|
+
controlHumanWorkspaceTimer,
|
|
98
102
|
} from "@opengeni/core";
|
|
99
103
|
import { boundedLimit } from "../http/common";
|
|
100
104
|
import { ApiHttpError } from "../http/api-error";
|
|
@@ -367,7 +371,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
367
371
|
// deep-merges (top-level) a settings patch, preserving unknown/future keys.
|
|
368
372
|
app.patch("/v1/workspaces/:workspaceId/settings", async (c) => {
|
|
369
373
|
const workspaceId = c.req.param("workspaceId");
|
|
370
|
-
await
|
|
374
|
+
await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
371
375
|
const parsed = UpdateWorkspaceSettingsRequest.safeParse(await c.req.json());
|
|
372
376
|
if (!parsed.success) {
|
|
373
377
|
throw new HTTPException(400, {
|
|
@@ -476,7 +480,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
476
480
|
|
|
477
481
|
app.post("/v1/workspaces/:workspaceId/gateway-custom-models", async (c) => {
|
|
478
482
|
const workspaceId = c.req.param("workspaceId");
|
|
479
|
-
const grant = await
|
|
483
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
480
484
|
const parsed = CreateWorkspaceGatewayCustomModelRequest.safeParse(
|
|
481
485
|
await c.req.json().catch(() => null),
|
|
482
486
|
);
|
|
@@ -552,7 +556,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
552
556
|
|
|
553
557
|
app.delete("/v1/workspaces/:workspaceId/gateway-custom-models/:customModelId", async (c) => {
|
|
554
558
|
const workspaceId = c.req.param("workspaceId");
|
|
555
|
-
const grant = await
|
|
559
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
556
560
|
const customModelId = c.req.param("customModelId");
|
|
557
561
|
if (
|
|
558
562
|
!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
|
|
@@ -613,7 +617,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
613
617
|
|
|
614
618
|
app.post("/v1/workspaces/:workspaceId/openrouter-custom-models", async (c) => {
|
|
615
619
|
const workspaceId = c.req.param("workspaceId");
|
|
616
|
-
const grant = await
|
|
620
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
617
621
|
const parsed = CreateWorkspaceOpenRouterCustomModelRequest.safeParse(
|
|
618
622
|
await c.req.json().catch(() => null),
|
|
619
623
|
);
|
|
@@ -691,7 +695,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
691
695
|
|
|
692
696
|
app.delete("/v1/workspaces/:workspaceId/openrouter-custom-models/:customModelId", async (c) => {
|
|
693
697
|
const workspaceId = c.req.param("workspaceId");
|
|
694
|
-
const grant = await
|
|
698
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
695
699
|
const customModelId = c.req.param("customModelId");
|
|
696
700
|
if (
|
|
697
701
|
!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
|
|
@@ -804,12 +808,12 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
804
808
|
});
|
|
805
809
|
|
|
806
810
|
// Full replace (PUT, not merge): null/omitted = unrestricted for that
|
|
807
|
-
// dimension; an empty array is a valid explicit total block.
|
|
808
|
-
//
|
|
809
|
-
//
|
|
811
|
+
// dimension; an empty array is a valid explicit total block. Settings access
|
|
812
|
+
// admits workspace administrators and the verified Personal owner, without
|
|
813
|
+
// widening membership or API-key delegation authority.
|
|
810
814
|
app.put("/v1/workspaces/:workspaceId/model-policy", async (c) => {
|
|
811
815
|
const workspaceId = c.req.param("workspaceId");
|
|
812
|
-
const grant = await
|
|
816
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
813
817
|
const payload = UpdateWorkspaceModelPolicyRequest.parse(await c.req.json());
|
|
814
818
|
const catalog = await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
|
|
815
819
|
accountId: grant.accountId,
|
|
@@ -824,9 +828,42 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
824
828
|
return c.json(policy);
|
|
825
829
|
});
|
|
826
830
|
|
|
831
|
+
app.post("/v1/workspaces/:workspaceId/pause-timer", async (c) => {
|
|
832
|
+
const workspaceId = c.req.param("workspaceId");
|
|
833
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
834
|
+
if (workspaceControlUtf8Bytes(grant.subjectId) > WORKSPACE_CONTROL_ACTOR_MAX_BYTES) {
|
|
835
|
+
throw new HTTPException(400, { message: "workspace-control actor is too large" });
|
|
836
|
+
}
|
|
837
|
+
const parsed = WorkspacePauseTimerRequest.safeParse(await c.req.json().catch(() => null));
|
|
838
|
+
if (!parsed.success) throw new HTTPException(400, { message: "Invalid pause timer" });
|
|
839
|
+
try {
|
|
840
|
+
await controlHumanWorkspaceTimer(
|
|
841
|
+
{
|
|
842
|
+
db: deps.db,
|
|
843
|
+
bus: deps.bus,
|
|
844
|
+
workflowClient: deps.workflowClient,
|
|
845
|
+
...(deps.schedulePromptPostCommit
|
|
846
|
+
? { schedulePromptPostCommit: deps.schedulePromptPostCommit }
|
|
847
|
+
: {}),
|
|
848
|
+
},
|
|
849
|
+
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
850
|
+
parsed.data,
|
|
851
|
+
);
|
|
852
|
+
} catch (error) {
|
|
853
|
+
if (error instanceof SessionControlConflictError)
|
|
854
|
+
throw new HTTPException(409, {
|
|
855
|
+
message: "Workspace changed. Reopen the timer and try again.",
|
|
856
|
+
});
|
|
857
|
+
if (error instanceof WorkspacePauseTimerInputError)
|
|
858
|
+
throw new HTTPException(400, { message: error.message });
|
|
859
|
+
throw error;
|
|
860
|
+
}
|
|
861
|
+
return c.json({ ok: true });
|
|
862
|
+
});
|
|
863
|
+
|
|
827
864
|
app.post("/v1/workspaces/:workspaceId/inference-control", async (c) => {
|
|
828
865
|
const workspaceId = c.req.param("workspaceId");
|
|
829
|
-
const grant = await
|
|
866
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
830
867
|
if (workspaceControlUtf8Bytes(grant.subjectId) > WORKSPACE_CONTROL_ACTOR_MAX_BYTES) {
|
|
831
868
|
throw new HTTPException(400, {
|
|
832
869
|
message: "workspace-control actor is too large",
|