@vellumai/assistant 0.11.10 → 0.11.11-staging.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/AGENTS.md +1 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +51 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/plan-credit.ts +66 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +51 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/plan-credit.ts +66 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/plan-credit.test.ts +51 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/plan-credit.ts +66 -0
- package/openapi.yaml +152 -55
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +60 -0
- package/src/__tests__/config-get-vision-flag.test.ts +36 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/copy-composer-tc-templates.test.ts +2 -2
- package/src/__tests__/guardian-action-service-scope.test.ts +53 -0
- package/src/__tests__/headless-browser-mode.test.ts +63 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +118 -27
- package/src/__tests__/host-app-control-proxy.test.ts +2 -2
- package/src/__tests__/host-app-control-routes.test.ts +41 -0
- package/src/__tests__/host-bash-routes.test.ts +30 -1
- package/src/__tests__/host-browser-routes.test.ts +34 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +29 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +29 -0
- package/src/__tests__/host-proxy-base.test.ts +1 -0
- package/src/__tests__/host-transfer-routes-targeted.test.ts +86 -0
- package/src/__tests__/llm-schema.test.ts +32 -0
- package/src/__tests__/mcp-config-secret-boundary.test.ts +2 -0
- package/src/__tests__/memory-config-file-parity.test.ts +18 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +15 -0
- package/src/__tests__/messaging-send-tool.test.ts +159 -13
- package/src/__tests__/messaging-shared.test.ts +19 -0
- package/src/__tests__/notification-events-source-context-probe.test.ts +211 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +40 -6
- package/src/__tests__/outlook-messaging-provider.test.ts +9 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +2 -2
- package/src/__tests__/schedule-routes.test.ts +30 -1
- package/src/__tests__/scheduler-result-notification.test.ts +209 -0
- package/src/__tests__/skills-install-extract.test.ts +26 -0
- package/src/__tests__/skills-install-staging.test.ts +11 -2
- package/src/api/constants/personality-sliders.test.ts +21 -0
- package/src/api/constants/personality-sliders.ts +64 -0
- package/src/api/index.ts +8 -0
- package/src/archive/ustar-size.test.ts +32 -0
- package/src/archive/ustar-size.ts +23 -0
- package/src/background-wake/next-wake.test.ts +13 -0
- package/src/background-wake/next-wake.ts +4 -2
- package/src/calls/voice-session-bridge.ts +26 -0
- package/src/cli/__tests__/catalog-search-help.test.ts +1 -0
- package/src/cli/commands/__tests__/plugins-search.test.ts +81 -0
- package/src/cli/commands/config.help.ts +3 -1
- package/src/cli/commands/memory/worker.ts +1 -1
- package/src/cli/commands/platform/__tests__/credits-format.test.ts +94 -5
- package/src/cli/commands/platform/__tests__/credits.test.ts +10 -0
- package/src/cli/commands/platform/credits-format.ts +57 -0
- package/src/cli/commands/platform/index.help.ts +19 -3
- package/src/cli/commands/plugins.help.ts +4 -1
- package/src/cli/commands/plugins.ts +2 -1
- package/src/cli/lib/bundled-marketplace.json +1 -1
- package/src/cli/lib/install-from-platform.ts +8 -10
- package/src/config/bundled-skills/messaging/SKILL.md +2 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -4
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +85 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +6 -0
- package/src/config/bundled-skills/schedule/SKILL.md +9 -1
- package/src/config/bundled-skills/screen-annotation/SKILL.md +87 -20
- package/src/config/bundled-skills/screen-annotation/TOOLS.json +21 -5
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +67 -0
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/input-modalities.test.ts +71 -0
- package/src/config/input-modalities.ts +95 -0
- package/src/config/schemas/heartbeat.ts +3 -3
- package/src/config/schemas/llm.ts +13 -3
- package/src/config/schemas/memory-storage.test.ts +39 -0
- package/src/config/schemas/memory-storage.ts +21 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/daemon/__tests__/embedding-reconcile.test.ts +77 -0
- package/src/daemon/__tests__/lifecycle-embedding-reconcile.test.ts +3 -0
- package/src/daemon/conversation-error.ts +20 -7
- package/src/daemon/embedding-reconcile.ts +64 -1
- package/src/daemon/handlers/config-embeddings.ts +31 -0
- package/src/daemon/host-app-control-proxy.ts +2 -0
- package/src/daemon/host-bash-proxy.ts +1 -0
- package/src/daemon/host-cu-proxy.ts +6 -6
- package/src/daemon/host-file-proxy.ts +6 -6
- package/src/daemon/host-proxy-base.ts +10 -9
- package/src/daemon/host-transfer-proxy.ts +21 -24
- package/src/daemon/mcp-reload-service.ts +6 -0
- package/src/daemon/providers-setup.ts +5 -26
- package/src/heartbeat/heartbeat-service.ts +72 -13
- package/src/live-voice/__tests__/live-voice-photo.test.ts +72 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +81 -0
- package/src/live-voice/live-voice-photo.ts +68 -4
- package/src/live-voice/live-voice-session.ts +36 -2
- package/src/live-voice/protocol.ts +98 -1
- package/src/mcp/__tests__/reload-signal-emission.test.ts +54 -0
- package/src/mcp/__tests__/reload-signal.test.ts +57 -0
- package/src/mcp/__tests__/startup.test.ts +150 -0
- package/src/mcp/reload-signal.ts +50 -0
- package/src/mcp/startup.ts +101 -0
- package/src/messaging/providers/outlook/adapter.ts +2 -13
- package/src/messaging/providers/outlook/client.ts +13 -1
- package/src/messaging/providers/outlook/types.ts +3 -0
- package/src/notifications/__tests__/decision-engine.test.ts +79 -6
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +27 -0
- package/src/notifications/__tests__/schedule-result-producer.test.ts +397 -0
- package/src/notifications/copy-composer.ts +33 -11
- package/src/notifications/decision-engine.ts +48 -11
- package/src/notifications/events-store.ts +68 -2
- package/src/notifications/home-feed-side-effect.ts +15 -3
- package/src/notifications/schedule-result-producer.ts +275 -0
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/seed-providers.ts +3 -2
- package/src/persistence/conversation-crud.ts +38 -0
- package/src/persistence/embeddings/embedding-backend.test.ts +162 -0
- package/src/persistence/embeddings/embedding-backend.ts +148 -11
- package/src/persistence/embeddings/embedding-openai.test.ts +113 -0
- package/src/persistence/embeddings/embedding-openai.ts +55 -4
- package/src/persistence/embeddings/embedding-types.test.ts +24 -0
- package/src/persistence/embeddings/embedding-types.ts +25 -1
- package/src/persistence/job-utils.ts +6 -2
- package/src/plugin-api/index.ts +2 -1
- package/src/plugin-api/vision-support.test.ts +81 -0
- package/src/plugin-api/vision-support.ts +57 -10
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +8 -0
- package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +1 -0
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +11 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +20 -0
- package/src/plugins/defaults/memory/src/memory-worker-routes.ts +3 -1
- package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +1 -0
- package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +1 -0
- package/src/plugins/defaults/memory/v3/__tests__/section-dense-store.test.ts +82 -0
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +9 -27
- package/src/providers/__tests__/provider-secret-catalog.test.ts +4 -0
- package/src/providers/__tests__/xml-tool-call-salvage.test.ts +172 -0
- package/src/providers/anthropic/client.ts +9 -4
- package/src/providers/inline-audio-support.test.ts +34 -0
- package/src/providers/inline-audio-support.ts +27 -0
- package/src/providers/model-catalog.ts +22 -2
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +50 -0
- package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +51 -0
- package/src/providers/openai/__tests__/chat-completions-provider-xml-salvage.test.ts +291 -0
- package/src/providers/openai/api-error-normalization.ts +18 -3
- package/src/providers/openai/chat-completions-provider.ts +113 -13
- package/src/providers/openai/responses-provider.ts +10 -8
- package/src/providers/provider-secret-catalog.ts +11 -1
- package/src/providers/vellum/client.ts +14 -1
- package/src/providers/vellum/personality-directions.test.ts +163 -0
- package/src/providers/vellum/personality-directions.ts +120 -0
- package/src/providers/xml-tool-call-salvage.ts +212 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +42 -4
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -6
- package/src/runtime/auth/__tests__/route-policy.test.ts +65 -0
- package/src/runtime/auth/same-actor.ts +29 -5
- package/src/runtime/background-job-runner.ts +38 -29
- package/src/runtime/guardian-action-service.ts +20 -1
- package/src/runtime/migrations/vbundle-validator.ts +3 -3
- package/src/runtime/pending-interactions.ts +4 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +24 -0
- package/src/runtime/routes/__tests__/platform-credits-routes.test.ts +99 -5
- package/src/runtime/routes/conversation-query-routes.ts +53 -11
- package/src/runtime/routes/document-comments-routes.ts +8 -2
- package/src/runtime/routes/guardian-action-routes.ts +7 -0
- package/src/runtime/routes/heartbeat-routes.ts +41 -53
- package/src/runtime/routes/host-app-control-routes.ts +10 -36
- package/src/runtime/routes/host-bash-routes.ts +11 -45
- package/src/runtime/routes/host-browser-routes.ts +24 -0
- package/src/runtime/routes/host-cu-routes.ts +11 -45
- package/src/runtime/routes/host-file-routes.ts +11 -44
- package/src/runtime/routes/host-proxy-result-binding.ts +57 -0
- package/src/runtime/routes/host-transfer-routes.ts +33 -25
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/integrations/a2a.ts +12 -3
- package/src/runtime/routes/integrations/vercel.ts +13 -3
- package/src/runtime/routes/platform-routes.ts +121 -24
- package/src/runtime/routes/schedule-routes.ts +15 -1
- package/src/schedule/__tests__/schedule-timezone.test.ts +21 -3
- package/src/schedule/__tests__/worker-mcp-tools.test.ts +88 -0
- package/src/schedule/schedule-timezone.ts +25 -0
- package/src/schedule/scheduler.ts +19 -0
- package/src/schedule/worker.ts +119 -2
- package/src/skills/catalog-install.ts +40 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +3 -0
- package/src/tools/browser/browser-execution.ts +117 -53
- package/src/tools/browser/browser-status-constants.ts +6 -6
- package/src/tools/capability-offer.test.ts +87 -0
- package/src/tools/capability-offer.ts +93 -0
- package/src/tools/terminal/__tests__/safe-env.test.ts +17 -0
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/util/provider-error-patterns.ts +34 -0
- package/src/watcher/__tests__/engine.test.ts +5 -2
- package/src/watcher/engine.ts +7 -4
- package/src/runtime/routes/__tests__/sight-frame-routes.test.ts +0 -487
- package/src/runtime/routes/sight-frame-routes.ts +0 -136
|
@@ -20,6 +20,7 @@ import { listHeartbeatRuns } from "../../heartbeat/heartbeat-run-store.js";
|
|
|
20
20
|
import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
21
21
|
import { getConversation } from "../../persistence/conversation-crud.js";
|
|
22
22
|
import { getUsageCostForConversationWindow } from "../../persistence/llm-usage-store.js";
|
|
23
|
+
import { resolveScheduleTimezone } from "../../schedule/schedule-timezone.js";
|
|
23
24
|
import { readTextFileSync } from "../../util/fs.js";
|
|
24
25
|
import { getLogger } from "../../util/logger.js";
|
|
25
26
|
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
@@ -36,6 +37,41 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
|
36
37
|
|
|
37
38
|
const log = getLogger("heartbeat-routes");
|
|
38
39
|
|
|
40
|
+
const HeartbeatConfigResponseSchema = z.object({
|
|
41
|
+
enabled: z.boolean(),
|
|
42
|
+
intervalMs: z.number(),
|
|
43
|
+
activeHoursStart: z.number().nullable(),
|
|
44
|
+
activeHoursEnd: z.number().nullable(),
|
|
45
|
+
cronExpression: z.string().nullable(),
|
|
46
|
+
timezone: z.string().nullable(),
|
|
47
|
+
effectiveTimezone: z
|
|
48
|
+
.string()
|
|
49
|
+
.nullable()
|
|
50
|
+
.describe(
|
|
51
|
+
"Timezone used for cron and active-hours evaluation after resolving heartbeat.timezone, then the user's configured or detected zone",
|
|
52
|
+
),
|
|
53
|
+
nextRunAt: z.number().nullable(),
|
|
54
|
+
lastRunAt: z.number().nullable(),
|
|
55
|
+
success: z.boolean(),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
function heartbeatConfigResponse() {
|
|
59
|
+
const heartbeat = getConfig().heartbeat;
|
|
60
|
+
const svc = HeartbeatService.getInstance();
|
|
61
|
+
return {
|
|
62
|
+
enabled: heartbeat.enabled,
|
|
63
|
+
intervalMs: heartbeat.intervalMs,
|
|
64
|
+
activeHoursStart: heartbeat.activeHoursStart ?? null,
|
|
65
|
+
activeHoursEnd: heartbeat.activeHoursEnd ?? null,
|
|
66
|
+
cronExpression: heartbeat.cronExpression ?? null,
|
|
67
|
+
timezone: heartbeat.timezone ?? null,
|
|
68
|
+
effectiveTimezone: resolveScheduleTimezone(heartbeat.timezone),
|
|
69
|
+
nextRunAt: svc?.nextRunAt ?? null,
|
|
70
|
+
lastRunAt: svc?.lastRunAt ?? null,
|
|
71
|
+
success: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
39
75
|
// ---------------------------------------------------------------------------
|
|
40
76
|
// Handlers (transport-agnostic)
|
|
41
77
|
// ---------------------------------------------------------------------------
|
|
@@ -196,32 +232,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
196
232
|
summary: "Get heartbeat config",
|
|
197
233
|
description: "Return the current heartbeat schedule configuration.",
|
|
198
234
|
tags: ["heartbeat"],
|
|
199
|
-
responseBody:
|
|
200
|
-
|
|
201
|
-
intervalMs: z.number(),
|
|
202
|
-
activeHoursStart: z.number().nullable(),
|
|
203
|
-
activeHoursEnd: z.number().nullable(),
|
|
204
|
-
cronExpression: z.string().nullable(),
|
|
205
|
-
timezone: z.string().nullable(),
|
|
206
|
-
nextRunAt: z.number().nullable(),
|
|
207
|
-
lastRunAt: z.number().nullable(),
|
|
208
|
-
success: z.boolean(),
|
|
209
|
-
}),
|
|
210
|
-
handler: async (_args: RouteHandlerArgs) => {
|
|
211
|
-
const config = getConfig().heartbeat;
|
|
212
|
-
const svc = HeartbeatService.getInstance();
|
|
213
|
-
return {
|
|
214
|
-
enabled: config.enabled,
|
|
215
|
-
intervalMs: config.intervalMs,
|
|
216
|
-
activeHoursStart: config.activeHoursStart ?? null,
|
|
217
|
-
activeHoursEnd: config.activeHoursEnd ?? null,
|
|
218
|
-
cronExpression: config.cronExpression ?? null,
|
|
219
|
-
timezone: config.timezone ?? null,
|
|
220
|
-
nextRunAt: svc?.nextRunAt ?? null,
|
|
221
|
-
lastRunAt: svc?.lastRunAt ?? null,
|
|
222
|
-
success: true,
|
|
223
|
-
};
|
|
224
|
-
},
|
|
235
|
+
responseBody: HeartbeatConfigResponseSchema,
|
|
236
|
+
handler: async (_args: RouteHandlerArgs) => heartbeatConfigResponse(),
|
|
225
237
|
},
|
|
226
238
|
{
|
|
227
239
|
operationId: "updateHeartbeatConfig",
|
|
@@ -258,19 +270,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
258
270
|
.string()
|
|
259
271
|
.nullable()
|
|
260
272
|
.optional()
|
|
261
|
-
.describe("Timezone for cron evaluation"),
|
|
262
|
-
}),
|
|
263
|
-
responseBody: z.object({
|
|
264
|
-
enabled: z.boolean(),
|
|
265
|
-
intervalMs: z.number(),
|
|
266
|
-
activeHoursStart: z.number().nullable(),
|
|
267
|
-
activeHoursEnd: z.number().nullable(),
|
|
268
|
-
cronExpression: z.string().nullable(),
|
|
269
|
-
timezone: z.string().nullable(),
|
|
270
|
-
nextRunAt: z.number().nullable(),
|
|
271
|
-
lastRunAt: z.number().nullable(),
|
|
272
|
-
success: z.boolean(),
|
|
273
|
+
.describe("Timezone for cron and active-hours evaluation"),
|
|
273
274
|
}),
|
|
275
|
+
responseBody: HeartbeatConfigResponseSchema,
|
|
274
276
|
handler: async ({ body = {} }: RouteHandlerArgs) => {
|
|
275
277
|
// Build a patch containing only the fields the caller actually set.
|
|
276
278
|
// Writing back the full Zod-defaulted heartbeat object would bake
|
|
@@ -316,24 +318,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
316
318
|
throw new InternalError("Failed to save config");
|
|
317
319
|
}
|
|
318
320
|
|
|
319
|
-
// Read effective values back through the schema-defaulting loader so
|
|
320
|
-
// callers that only set a subset of fields still see the resolved
|
|
321
|
-
// (post-default) shape in the response.
|
|
322
|
-
const heartbeat = getConfig().heartbeat;
|
|
323
321
|
const svc = HeartbeatService.getInstance();
|
|
324
322
|
svc?.reconfigure();
|
|
325
323
|
|
|
326
|
-
return
|
|
327
|
-
enabled: heartbeat.enabled,
|
|
328
|
-
intervalMs: heartbeat.intervalMs,
|
|
329
|
-
activeHoursStart: heartbeat.activeHoursStart ?? null,
|
|
330
|
-
activeHoursEnd: heartbeat.activeHoursEnd ?? null,
|
|
331
|
-
cronExpression: heartbeat.cronExpression ?? null,
|
|
332
|
-
timezone: heartbeat.timezone ?? null,
|
|
333
|
-
nextRunAt: svc?.nextRunAt ?? null,
|
|
334
|
-
lastRunAt: svc?.lastRunAt ?? null,
|
|
335
|
-
success: true,
|
|
336
|
-
};
|
|
324
|
+
return heartbeatConfigResponse();
|
|
337
325
|
},
|
|
338
326
|
},
|
|
339
327
|
{
|
|
@@ -19,15 +19,10 @@ import type {
|
|
|
19
19
|
HostAppControlResultPayload,
|
|
20
20
|
HostAppControlState,
|
|
21
21
|
} from "../../daemon/message-types/host-app-control.js";
|
|
22
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
23
22
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
24
|
-
import {
|
|
25
|
-
enforceSameActorOrThrow,
|
|
26
|
-
SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
27
|
-
} from "../auth/same-actor.js";
|
|
28
|
-
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
23
|
+
import { SAME_ACTOR_FORBIDDEN_DESCRIPTION } from "../auth/same-actor.js";
|
|
29
24
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
30
|
-
import {
|
|
25
|
+
import { assertHostProxyResultBinding } from "./host-proxy-result-binding.js";
|
|
31
26
|
import { parseBody } from "./parse-body.js";
|
|
32
27
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
33
28
|
|
|
@@ -93,35 +88,14 @@ async function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
|
|
|
93
88
|
return { accepted: true };
|
|
94
89
|
}
|
|
95
90
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
throw new BadRequestError(
|
|
105
|
-
"x-vellum-client-id header is missing for a targeted host app-control request.",
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
if (submittingClientId !== peeked.targetClientId) {
|
|
109
|
-
throw new ForbiddenError(
|
|
110
|
-
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
const submittingActorPrincipalId =
|
|
114
|
-
await resolveActorPrincipalIdForLocalGuardian(
|
|
115
|
-
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
116
|
-
);
|
|
117
|
-
enforceSameActorOrThrow({
|
|
118
|
-
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
119
|
-
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
120
|
-
targetClientId: peeked.targetClientId,
|
|
121
|
-
op: "host_app_control",
|
|
122
|
-
hubForMissingTarget: assistantEventHub,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
91
|
+
await assertHostProxyResultBinding({
|
|
92
|
+
headers,
|
|
93
|
+
targetClientId: peeked.targetClientId,
|
|
94
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
95
|
+
op: "host_app_control",
|
|
96
|
+
missingClientIdMessage:
|
|
97
|
+
"x-vellum-client-id header is missing for a targeted host app-control request.",
|
|
98
|
+
});
|
|
125
99
|
|
|
126
100
|
const interaction = pendingInteractions.resolve(requestId, "answered")!;
|
|
127
101
|
const conversation = findConversation(interaction.conversationId);
|
|
@@ -7,20 +7,11 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
|
|
10
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
11
10
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
12
|
-
import {
|
|
13
|
-
enforceSameActorOrThrow,
|
|
14
|
-
SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
15
|
-
} from "../auth/same-actor.js";
|
|
16
|
-
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
11
|
+
import { SAME_ACTOR_FORBIDDEN_DESCRIPTION } from "../auth/same-actor.js";
|
|
17
12
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
ConflictError,
|
|
21
|
-
ForbiddenError,
|
|
22
|
-
NotFoundError,
|
|
23
|
-
} from "./errors.js";
|
|
13
|
+
import { ConflictError, NotFoundError } from "./errors.js";
|
|
14
|
+
import { assertHostProxyResultBinding } from "./host-proxy-result-binding.js";
|
|
24
15
|
import { parseBody } from "./parse-body.js";
|
|
25
16
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
26
17
|
|
|
@@ -59,13 +50,6 @@ async function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
|
|
|
59
50
|
body,
|
|
60
51
|
);
|
|
61
52
|
|
|
62
|
-
const submittingClientId =
|
|
63
|
-
headers?.["x-vellum-client-id"]?.trim() || undefined;
|
|
64
|
-
const submittingActorPrincipalId =
|
|
65
|
-
await resolveActorPrincipalIdForLocalGuardian(
|
|
66
|
-
headers?.["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
67
|
-
);
|
|
68
|
-
|
|
69
53
|
const peeked = pendingInteractions.get(requestId);
|
|
70
54
|
if (!peeked) {
|
|
71
55
|
throw new NotFoundError("No pending interaction found for this requestId");
|
|
@@ -77,32 +61,14 @@ async function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
|
|
|
77
61
|
);
|
|
78
62
|
}
|
|
79
63
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
throw new ForbiddenError(
|
|
89
|
-
`Client "${submittingClientId}" is not the target for this request (expected "${targetClientId}"). The targeted client must submit the result.`,
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Defense-in-depth on top of the client-id header binding above: the
|
|
94
|
-
// submitting actor's principal must match the actor principal stored
|
|
95
|
-
// for the target client at SSE subscription time. This prevents a
|
|
96
|
-
// cross-user submission even when the attacker can guess or spoof the
|
|
97
|
-
// target's client ID.
|
|
98
|
-
enforceSameActorOrThrow({
|
|
99
|
-
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
100
|
-
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
101
|
-
targetClientId,
|
|
102
|
-
op: "host_bash",
|
|
103
|
-
hubForMissingTarget: assistantEventHub,
|
|
104
|
-
});
|
|
105
|
-
}
|
|
64
|
+
await assertHostProxyResultBinding({
|
|
65
|
+
headers,
|
|
66
|
+
targetClientId: peeked.targetClientId,
|
|
67
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
68
|
+
op: "host_bash",
|
|
69
|
+
missingClientIdMessage:
|
|
70
|
+
"x-vellum-client-id header is required for targeted host bash requests",
|
|
71
|
+
});
|
|
106
72
|
|
|
107
73
|
HostBashProxy.instance.resolveResult(requestId, {
|
|
108
74
|
stdout: stdout ?? "",
|
|
@@ -149,6 +149,30 @@ export async function resolveHostBrowserResultByRequestId(
|
|
|
149
149
|
message: err instanceof Error ? err.message : "Same-actor check failed",
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
|
+
} else if (peeked.targetActorPrincipalId) {
|
|
153
|
+
const headerMap = headers ?? {};
|
|
154
|
+
const submittingClientId =
|
|
155
|
+
headerMap["x-vellum-client-id"]?.trim() || undefined;
|
|
156
|
+
const submittingActorPrincipalId =
|
|
157
|
+
await resolveActorPrincipalIdForLocalGuardian(
|
|
158
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
159
|
+
);
|
|
160
|
+
try {
|
|
161
|
+
enforceSameActorOrThrow({
|
|
162
|
+
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
163
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
164
|
+
targetClientId: submittingClientId ?? "",
|
|
165
|
+
op: "host_browser",
|
|
166
|
+
hubForMissingTarget: assistantEventHub,
|
|
167
|
+
});
|
|
168
|
+
} catch (err) {
|
|
169
|
+
return {
|
|
170
|
+
ok: false,
|
|
171
|
+
code: "FORBIDDEN",
|
|
172
|
+
status: 403,
|
|
173
|
+
message: err instanceof Error ? err.message : "Same-actor check failed",
|
|
174
|
+
};
|
|
175
|
+
}
|
|
152
176
|
}
|
|
153
177
|
|
|
154
178
|
const normalizedContent = typeof content === "string" ? content : "";
|
|
@@ -7,20 +7,11 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
10
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
11
10
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
12
|
-
import {
|
|
13
|
-
enforceSameActorOrThrow,
|
|
14
|
-
SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
15
|
-
} from "../auth/same-actor.js";
|
|
16
|
-
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
11
|
+
import { SAME_ACTOR_FORBIDDEN_DESCRIPTION } from "../auth/same-actor.js";
|
|
17
12
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
ConflictError,
|
|
21
|
-
ForbiddenError,
|
|
22
|
-
NotFoundError,
|
|
23
|
-
} from "./errors.js";
|
|
13
|
+
import { ConflictError, NotFoundError } from "./errors.js";
|
|
14
|
+
import { assertHostProxyResultBinding } from "./host-proxy-result-binding.js";
|
|
24
15
|
import { parseBody } from "./parse-body.js";
|
|
25
16
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
26
17
|
|
|
@@ -78,39 +69,14 @@ async function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
|
|
|
78
69
|
);
|
|
79
70
|
}
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
if (submittingClientId !== peeked.targetClientId) {
|
|
92
|
-
throw new ForbiddenError(
|
|
93
|
-
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Defense-in-depth: require the submitting actor's principal id to match
|
|
98
|
-
// the actor principal id captured when the target client opened its SSE
|
|
99
|
-
// stream. This prevents a different authenticated user with knowledge of
|
|
100
|
-
// both the requestId and target clientId from submitting a result on
|
|
101
|
-
// behalf of the targeted client.
|
|
102
|
-
const submittingActorPrincipalId =
|
|
103
|
-
await resolveActorPrincipalIdForLocalGuardian(
|
|
104
|
-
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
105
|
-
);
|
|
106
|
-
enforceSameActorOrThrow({
|
|
107
|
-
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
108
|
-
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
109
|
-
targetClientId: peeked.targetClientId,
|
|
110
|
-
op: "host_cu",
|
|
111
|
-
hubForMissingTarget: assistantEventHub,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
72
|
+
await assertHostProxyResultBinding({
|
|
73
|
+
headers: headers as Record<string, string | undefined> | undefined,
|
|
74
|
+
targetClientId: peeked.targetClientId,
|
|
75
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
76
|
+
op: "host_cu",
|
|
77
|
+
missingClientIdMessage:
|
|
78
|
+
"x-vellum-client-id header is missing for a targeted host CU request.",
|
|
79
|
+
});
|
|
114
80
|
|
|
115
81
|
// Conversation-agnostic observation (see `runtime/host-observe.ts`): the
|
|
116
82
|
// request was raised outside any turn, so there is no conversation and no CU
|
|
@@ -7,20 +7,11 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
10
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
11
10
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
12
|
-
import {
|
|
13
|
-
enforceSameActorOrThrow,
|
|
14
|
-
SAME_ACTOR_FORBIDDEN_DESCRIPTION,
|
|
15
|
-
} from "../auth/same-actor.js";
|
|
16
|
-
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
11
|
+
import { SAME_ACTOR_FORBIDDEN_DESCRIPTION } from "../auth/same-actor.js";
|
|
17
12
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
ConflictError,
|
|
21
|
-
ForbiddenError,
|
|
22
|
-
NotFoundError,
|
|
23
|
-
} from "./errors.js";
|
|
13
|
+
import { ConflictError, NotFoundError } from "./errors.js";
|
|
14
|
+
import { assertHostProxyResultBinding } from "./host-proxy-result-binding.js";
|
|
24
15
|
import { parseBody } from "./parse-body.js";
|
|
25
16
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
26
17
|
|
|
@@ -69,38 +60,14 @@ async function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
|
|
|
69
60
|
);
|
|
70
61
|
}
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
if (submittingClientId !== peeked.targetClientId) {
|
|
83
|
-
throw new ForbiddenError(
|
|
84
|
-
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Defense-in-depth: also require the submitting actor's principal id to
|
|
89
|
-
// match the actor that opened the target client's SSE stream. This blocks
|
|
90
|
-
// cross-user submissions even if a different user somehow obtains the
|
|
91
|
-
// target client id.
|
|
92
|
-
const submittingActorPrincipalId =
|
|
93
|
-
await resolveActorPrincipalIdForLocalGuardian(
|
|
94
|
-
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
95
|
-
);
|
|
96
|
-
enforceSameActorOrThrow({
|
|
97
|
-
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
98
|
-
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
99
|
-
targetClientId: peeked.targetClientId,
|
|
100
|
-
op: "host_file",
|
|
101
|
-
hubForMissingTarget: assistantEventHub,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
63
|
+
await assertHostProxyResultBinding({
|
|
64
|
+
headers: headers as Record<string, string | undefined> | undefined,
|
|
65
|
+
targetClientId: peeked.targetClientId,
|
|
66
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
67
|
+
op: "host_file",
|
|
68
|
+
missingClientIdMessage:
|
|
69
|
+
"x-vellum-client-id header is missing for a targeted host file request.",
|
|
70
|
+
});
|
|
104
71
|
|
|
105
72
|
HostFileProxy.instance.resolve(requestId, {
|
|
106
73
|
content: content ?? "",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared binding checks for host-proxy result (and transfer content) routes.
|
|
3
|
+
*
|
|
4
|
+
* Targeted requests still require the submitting client id to match the
|
|
5
|
+
* pending `targetClientId`. When a request was dispatched untargeted, the
|
|
6
|
+
* pending interaction may still carry `targetActorPrincipalId` (the turn's
|
|
7
|
+
* source actor). In that case the same-actor check still runs so a different
|
|
8
|
+
* principal cannot forge stdout/stderr/exitCode for someone else's command.
|
|
9
|
+
*
|
|
10
|
+
* Identity-less local flows (neither target client nor source actor recorded)
|
|
11
|
+
* keep the open path.
|
|
12
|
+
*/
|
|
13
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
14
|
+
import {
|
|
15
|
+
enforceSameActorOrThrow,
|
|
16
|
+
type SameActorOp,
|
|
17
|
+
} from "../auth/same-actor.js";
|
|
18
|
+
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
19
|
+
import { BadRequestError, ForbiddenError } from "./errors.js";
|
|
20
|
+
|
|
21
|
+
export async function assertHostProxyResultBinding(args: {
|
|
22
|
+
headers?: Record<string, string | undefined>;
|
|
23
|
+
targetClientId?: string;
|
|
24
|
+
targetActorPrincipalId?: string;
|
|
25
|
+
op: SameActorOp;
|
|
26
|
+
missingClientIdMessage: string;
|
|
27
|
+
}): Promise<void> {
|
|
28
|
+
const submittingClientId =
|
|
29
|
+
args.headers?.["x-vellum-client-id"]?.trim() || undefined;
|
|
30
|
+
const submittingActorPrincipalId =
|
|
31
|
+
await resolveActorPrincipalIdForLocalGuardian(
|
|
32
|
+
args.headers?.["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (args.targetClientId) {
|
|
36
|
+
if (!submittingClientId) {
|
|
37
|
+
throw new BadRequestError(args.missingClientIdMessage);
|
|
38
|
+
}
|
|
39
|
+
if (submittingClientId !== args.targetClientId) {
|
|
40
|
+
throw new ForbiddenError(
|
|
41
|
+
`Client "${submittingClientId}" is not the target for this request (expected "${args.targetClientId}"). The targeted client must submit the result.`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!args.targetClientId && !args.targetActorPrincipalId) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
enforceSameActorOrThrow({
|
|
51
|
+
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
52
|
+
targetActorPrincipalId: args.targetActorPrincipalId,
|
|
53
|
+
targetClientId: args.targetClientId ?? submittingClientId ?? "",
|
|
54
|
+
op: args.op,
|
|
55
|
+
hubForMissingTarget: assistantEventHub,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
ForbiddenError,
|
|
23
23
|
NotFoundError,
|
|
24
24
|
} from "./errors.js";
|
|
25
|
+
import { assertHostProxyResultBinding } from "./host-proxy-result-binding.js";
|
|
25
26
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -86,6 +87,18 @@ async function handleTransferContentGet({
|
|
|
86
87
|
op: "host_transfer",
|
|
87
88
|
hubForMissingTarget: assistantEventHub,
|
|
88
89
|
});
|
|
90
|
+
} else {
|
|
91
|
+
const targetActorPrincipalId =
|
|
92
|
+
match.proxy.getTargetActorPrincipalIdForTransfer(transferId);
|
|
93
|
+
if (targetActorPrincipalId) {
|
|
94
|
+
await assertHostProxyResultBinding({
|
|
95
|
+
headers: headers as Record<string, string | undefined>,
|
|
96
|
+
targetActorPrincipalId,
|
|
97
|
+
op: "host_transfer",
|
|
98
|
+
missingClientIdMessage:
|
|
99
|
+
"x-vellum-client-id header required for targeted transfer",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
89
102
|
}
|
|
90
103
|
|
|
91
104
|
const content = match.proxy.getTransferContent(transferId);
|
|
@@ -172,6 +185,18 @@ async function handleTransferContentPut({
|
|
|
172
185
|
op: "host_transfer",
|
|
173
186
|
hubForMissingTarget: assistantEventHub,
|
|
174
187
|
});
|
|
188
|
+
} else {
|
|
189
|
+
const targetActorPrincipalId =
|
|
190
|
+
match.proxy.getTargetActorPrincipalIdForTransfer(transferId);
|
|
191
|
+
if (targetActorPrincipalId) {
|
|
192
|
+
await assertHostProxyResultBinding({
|
|
193
|
+
headers: headers as Record<string, string | undefined>,
|
|
194
|
+
targetActorPrincipalId,
|
|
195
|
+
op: "host_transfer",
|
|
196
|
+
missingClientIdMessage:
|
|
197
|
+
"x-vellum-client-id header required for targeted transfer",
|
|
198
|
+
});
|
|
199
|
+
}
|
|
175
200
|
}
|
|
176
201
|
|
|
177
202
|
const data = rawBody ? Buffer.from(rawBody) : Buffer.alloc(0);
|
|
@@ -221,31 +246,14 @@ async function handleTransferResult({ body, headers }: RouteHandlerArgs) {
|
|
|
221
246
|
);
|
|
222
247
|
}
|
|
223
248
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
if (submittingClientId !== peeked.targetClientId) {
|
|
234
|
-
throw new ForbiddenError(
|
|
235
|
-
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}").`,
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
enforceSameActorOrThrow({
|
|
240
|
-
sourceActorPrincipalId: await resolveActorPrincipalIdForLocalGuardian(
|
|
241
|
-
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
242
|
-
),
|
|
243
|
-
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
244
|
-
targetClientId: peeked.targetClientId,
|
|
245
|
-
op: "host_transfer",
|
|
246
|
-
hubForMissingTarget: assistantEventHub,
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
+
await assertHostProxyResultBinding({
|
|
250
|
+
headers: headers as Record<string, string | undefined> | undefined,
|
|
251
|
+
targetClientId: peeked.targetClientId,
|
|
252
|
+
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
253
|
+
op: "host_transfer",
|
|
254
|
+
missingClientIdMessage:
|
|
255
|
+
"x-vellum-client-id header is missing for a targeted host transfer request.",
|
|
256
|
+
});
|
|
249
257
|
|
|
250
258
|
HostTransferProxy.instance.resolveTransferResult(requestId, {
|
|
251
259
|
isError: isError ?? false,
|
|
@@ -140,7 +140,6 @@ import { ROUTES as SCHEDULE_WORKER_ROUTES } from "./schedule-worker-routes.js";
|
|
|
140
140
|
import { ROUTES as SECRET_ROUTES } from "./secret-routes.js";
|
|
141
141
|
import { ROUTES as SEQUENCE_ROUTES } from "./sequence-routes.js";
|
|
142
142
|
import { ROUTES as SETTINGS_ROUTES } from "./settings-routes.js";
|
|
143
|
-
import { ROUTES as SIGHT_FRAME_ROUTES } from "./sight-frame-routes.js";
|
|
144
143
|
import { ROUTES as SKILL_ROUTES } from "./skills-routes.js";
|
|
145
144
|
import { ROUTES as SLACK_CHANNEL_RESOLVE_ROUTES } from "./slack-channel-routes.js";
|
|
146
145
|
import { ROUTES as SOUNDS_CONFIG_ROUTES } from "./sounds-config-routes.js";
|
|
@@ -290,7 +289,6 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
290
289
|
...SANITY_ROUTES,
|
|
291
290
|
...SECRET_ROUTES,
|
|
292
291
|
...SETTINGS_ROUTES,
|
|
293
|
-
...SIGHT_FRAME_ROUTES,
|
|
294
292
|
...SOUNDS_CONFIG_ROUTES,
|
|
295
293
|
...SKILL_ROUTES,
|
|
296
294
|
...A2A_ROUTES,
|
|
@@ -230,7 +230,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
230
230
|
operationId: "integrations_a2a_config_get",
|
|
231
231
|
endpoint: "integrations/a2a/config",
|
|
232
232
|
method: "GET",
|
|
233
|
-
policy:
|
|
233
|
+
policy: {
|
|
234
|
+
requiredScopes: ["settings.read"],
|
|
235
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
236
|
+
},
|
|
234
237
|
summary: "Get A2A config",
|
|
235
238
|
description: "Check current A2A channel configuration status.",
|
|
236
239
|
tags: ["integrations"],
|
|
@@ -241,7 +244,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
241
244
|
operationId: "integrations_a2a_config_post",
|
|
242
245
|
endpoint: "integrations/a2a/config",
|
|
243
246
|
method: "POST",
|
|
244
|
-
policy:
|
|
247
|
+
policy: {
|
|
248
|
+
requiredScopes: ["settings.write"],
|
|
249
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
250
|
+
},
|
|
245
251
|
summary: "Enable A2A channel",
|
|
246
252
|
description: "Enable the A2A channel for inter-assistant communication.",
|
|
247
253
|
tags: ["integrations"],
|
|
@@ -252,7 +258,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
252
258
|
operationId: "integrations_a2a_config_delete",
|
|
253
259
|
endpoint: "integrations/a2a/config",
|
|
254
260
|
method: "DELETE",
|
|
255
|
-
policy:
|
|
261
|
+
policy: {
|
|
262
|
+
requiredScopes: ["settings.write"],
|
|
263
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
264
|
+
},
|
|
256
265
|
summary: "Disable A2A channel",
|
|
257
266
|
description: "Disable the A2A channel.",
|
|
258
267
|
tags: ["integrations"],
|