@agent-native/core 0.214.0 → 0.216.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/action.js +54 -1
- package/dist/agent/actions/disconnect-chatgpt-subscription.js +5 -0
- package/dist/agent/actions/get-agentkit-capabilities.js +3 -3
- package/dist/agent/actions/manage-builder-connection.js +5 -0
- package/dist/agent/actions/manage-provider-key-policy.js +5 -0
- package/dist/agent/actions/manage-provider-models.js +5 -0
- package/dist/agent/actions/manage-service-providers.js +5 -0
- package/dist/agent/actions/select-chatgpt-subscription-account.js +5 -0
- package/dist/agent/context-xray/actions/context-evict.js +5 -0
- package/dist/agent/context-xray/actions/context-pin.js +5 -0
- package/dist/agent/context-xray/actions/context-report.js +5 -0
- package/dist/agent/context-xray/actions/context-restore.js +5 -0
- package/dist/agent/execution-fence.d.ts +1 -0
- package/dist/agent/execution-fence.js +5 -0
- package/dist/agent/production-agent.d.ts +35 -2
- package/dist/agent/production-agent.js +629 -32
- package/dist/agent/run-manager.d.ts +2 -0
- package/dist/agent/run-manager.js +397 -115
- package/dist/agent/run-slot-lock.d.ts +2 -0
- package/dist/agent/run-slot-lock.js +6 -0
- package/dist/agent/run-store.d.ts +5 -0
- package/dist/agent/run-store.js +423 -156
- package/dist/agent/thread-data-builder.js +27 -5
- package/dist/agent/types.d.ts +6 -12
- package/dist/agentkit/capabilities.d.ts +1 -1
- package/dist/application-state/store.d.ts +5 -0
- package/dist/application-state/store.js +26 -0
- package/dist/chat-threads/schema-migrations.js +17 -0
- package/dist/chat-threads/store.d.ts +21 -1
- package/dist/chat-threads/store.js +223 -41
- package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
- package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
- package/dist/cli/templates-meta.js +14 -0
- package/dist/client/analytics.js +167 -17
- package/dist/client/chat/agentkit-agent-native.js +79 -3
- package/dist/client/chat/agentkit-protocol.js +80 -42
- package/dist/client/chat/runtime.d.ts +5 -1
- package/dist/client/chat/runtime.js +46 -3
- package/dist/client/consent.d.ts +36 -0
- package/dist/client/consent.js +283 -0
- package/dist/client/review/use-review.d.ts +2 -0
- package/dist/client/review/use-review.js +28 -1
- package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
- package/dist/client/sharing/useResourceAccessGate.js +9 -1
- package/dist/client/use-chat-thread-list.d.ts +2 -0
- package/dist/client/use-chat-thread-list.js +12 -2
- package/dist/client/use-chat-threads.d.ts +1 -0
- package/dist/client/use-chat-threads.js +2 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +5 -5
- package/dist/connections/catalog.js +22 -3
- package/dist/data-widgets/index.d.ts +36 -2
- package/dist/data-widgets/index.js +94 -6
- package/dist/db/migrations.js +4 -1
- package/dist/db/schema-snapshot.generated.js +8 -1
- package/dist/feature-flags/actions/set-feature-flag.js +5 -0
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +12 -0
- package/dist/feature-flags/store.js +79 -7
- package/dist/file-upload/actions/manage-file-storage.js +5 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.js +5 -0
- package/dist/history/actions/create-resource-version.js +5 -0
- package/dist/history/actions/restore-resource-version.js +5 -0
- package/dist/ingestion/index.d.ts +1 -1
- package/dist/ingestion/index.js +1 -1
- package/dist/ingestion/pptx.d.ts +11 -0
- package/dist/ingestion/pptx.js +81 -1
- package/dist/integrations/actions/manage-messaging-channel.js +5 -0
- package/dist/jobs/scheduler.js +17 -1
- package/dist/labs/actions/set-lab.js +5 -0
- package/dist/localization/actions/set-localization-preference.js +5 -0
- package/dist/observability/actions/save-observability-instruction-update.js +5 -0
- package/dist/observability/actions/save-observability-review-summary.js +5 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +18 -18
- package/dist/provider-api/actions/provider-api.d.ts +14 -14
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +9 -2
- package/dist/review/actions/consume-review-feedback.js +5 -0
- package/dist/review/actions/create-review-comment.js +5 -0
- package/dist/review/actions/delete-review-comment.js +5 -0
- package/dist/review/actions/react-to-review-comment.js +5 -0
- package/dist/review/actions/reply-review-comment.js +5 -0
- package/dist/review/actions/resolve-review-thread.js +5 -0
- package/dist/review/actions/send-review-thread-to-agent.js +5 -0
- package/dist/review/actions/set-review-status.js +5 -0
- package/dist/review/actions/set-review-thread-muted.js +5 -0
- package/dist/review/actions/set-review-thread-unread.js +5 -0
- package/dist/review/actions/set-review-threads-unread.js +5 -0
- package/dist/review/actions/update-review-comment-anchor.js +5 -0
- package/dist/review/actions/update-review-comment.js +5 -0
- package/dist/review/suggestions/actions.js +60 -21
- package/dist/review/suggestions/store.d.ts +2 -0
- package/dist/review/suggestions/store.js +28 -0
- package/dist/secrets/actions/delete-api-key.js +5 -0
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat/context-tools.js +63 -2
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.js +242 -54
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +2 -2
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/application-state-maintenance.d.ts +2 -0
- package/dist/server/application-state-maintenance.js +2 -0
- package/dist/server/attribution.d.ts +14 -0
- package/dist/server/attribution.js +62 -2
- package/dist/server/auth.js +7 -0
- package/dist/server/consent-route.d.ts +41 -0
- package/dist/server/consent-route.js +102 -0
- package/dist/server/first-touch-route.d.ts +39 -0
- package/dist/server/first-touch-route.js +115 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
- package/dist/server/queued-submission-inbox-drain.js +12 -0
- package/dist/server/request-origin.d.ts +6 -0
- package/dist/server/request-origin.js +12 -0
- package/dist/settings/org-settings.d.ts +2 -1
- package/dist/settings/org-settings.js +4 -1
- package/dist/settings/store.d.ts +8 -0
- package/dist/settings/store.js +14 -5
- package/dist/shared/consent.d.ts +31 -0
- package/dist/shared/consent.js +145 -0
- package/dist/shared/first-touch-persistence.d.ts +31 -0
- package/dist/shared/first-touch-persistence.js +53 -0
- package/dist/sharing/actions/set-resource-visibility.js +5 -0
- package/dist/sharing/actions/share-resource.js +5 -0
- package/dist/sharing/actions/unshare-resource.js +5 -0
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
- package/dist/triggers/actions/manage-automation.d.ts +1 -1
- package/dist/usage/actions/get-usage-metrics.js +27 -4
- package/dist/usage/actions/manage-usage-alert.js +5 -0
- package/dist/vite/client.js +8 -6
- package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
- package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
- package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
- package/docs/content/actions-access-control.mdx +8 -8
- package/docs/content/actions-defining.mdx +9 -8
- package/docs/content/template-design-developers.mdx +9 -9
- package/docs/content/template-design-features.mdx +1 -3
- package/docs/content/turn-into-app.mdx +4 -0
- package/package.json +4 -3
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
|
@@ -27,6 +27,11 @@ export default defineAction({
|
|
|
27
27
|
? "Cleared file storage credentials"
|
|
28
28
|
: "Saved file storage settings",
|
|
29
29
|
}),
|
|
30
|
+
mcpAnnotations: {
|
|
31
|
+
readOnlyHint: false,
|
|
32
|
+
destructiveHint: true,
|
|
33
|
+
openWorldHint: false,
|
|
34
|
+
},
|
|
30
35
|
run: async ({ operation, ...values }, ctx) => operation === "clear"
|
|
31
36
|
? clearFileStorage(ctx)
|
|
32
37
|
: { removedKeys: [], status: await saveFileStorage(ctx, values) },
|
|
@@ -442,6 +442,11 @@ export default defineAction({
|
|
|
442
442
|
.refine((args) => args.cleanup ? !!args.idempotencyKey : !!args.data || !!args.url, {
|
|
443
443
|
message: "Either a data/url upload or an idempotencyKey cleanup is required.",
|
|
444
444
|
}),
|
|
445
|
+
mcpAnnotations: {
|
|
446
|
+
readOnlyHint: false,
|
|
447
|
+
destructiveHint: true,
|
|
448
|
+
openWorldHint: true,
|
|
449
|
+
},
|
|
445
450
|
run: async (args) => {
|
|
446
451
|
const idempotencyKey = args.idempotencyKey?.trim();
|
|
447
452
|
if (args.cleanup && idempotencyKey) {
|
|
@@ -13,6 +13,11 @@ const schema = z.object({
|
|
|
13
13
|
export default defineAction({
|
|
14
14
|
description: "Create a reusable version-history snapshot for a resource.",
|
|
15
15
|
schema,
|
|
16
|
+
mcpAnnotations: {
|
|
17
|
+
readOnlyHint: false,
|
|
18
|
+
destructiveHint: false,
|
|
19
|
+
openWorldHint: false,
|
|
20
|
+
},
|
|
16
21
|
run: async (args, ctx) => {
|
|
17
22
|
const actionCtx = ctx;
|
|
18
23
|
const access = await assertVersionedResourceAccess(args.resourceType, args.resourceId, actionCtx, "editor");
|
|
@@ -16,6 +16,11 @@ const schema = z
|
|
|
16
16
|
export default defineAction({
|
|
17
17
|
description: "Restore a resource from a reusable version-history snapshot.",
|
|
18
18
|
schema,
|
|
19
|
+
mcpAnnotations: {
|
|
20
|
+
readOnlyHint: false,
|
|
21
|
+
destructiveHint: true,
|
|
22
|
+
openWorldHint: false,
|
|
23
|
+
},
|
|
19
24
|
run: async (args, ctx) => {
|
|
20
25
|
const actionCtx = ctx;
|
|
21
26
|
const scope = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { acquireIngestionLease, assertInventoryComplete, consumeIngestionBudget, createIngestionBudgetState, createIngestionCheckpoint, ingestionBudgetStopReason, releaseIngestionLease, renewIngestionLease, type AcquireIngestionLeaseInput, type AcquireIngestionLeaseResult, type IngestionBudgetLimits, type IngestionBudgetState, type IngestionBudgetStopReason, type IngestionCheckpoint, type IngestionLease, type IngestionPhase, } from "./orchestration.js";
|
|
2
2
|
export { detectOfficeDocumentType, normalizeDocumentText, parseOfficeDocument, type OfficeDocumentAst, type OfficeDocumentParser, type OfficeDocumentPart, type OfficeDocumentType, type ParsedOfficeDocument, type ParseOfficeDocumentInput, } from "./office.js";
|
|
3
3
|
export { detectSpreadsheetDocumentType, isSpreadsheetDocument, parseSpreadsheetDocument, type ParsedSpreadsheetDocument, type ParsedSpreadsheetSheet, type ParseSpreadsheetDocumentInput, type SpreadsheetDocumentType, } from "./spreadsheet.js";
|
|
4
|
-
export { parsePptxPresentation, type ParsedPptxImage, type ParsedPptxElement, type ParsedPptxGrid, type ParsedPptxParagraph, type ParsedPptxPresentation, type ParsedPptxSlide, type ParsedPptxTextRun, } from "./pptx.js";
|
|
4
|
+
export { DEFAULT_PPTX_IMAGE_BYTE_LIMITS, PptxImageByteLimitError, parsePptxPresentation, type ParsedPptxImage, type ParsedPptxElement, type ParsedPptxGrid, type ParsedPptxParagraph, type ParsedPptxPresentation, type ParsedPptxSlide, type ParsedPptxTextRun, type PptxImageByteLimits, } from "./pptx.js";
|
|
5
5
|
export { extractDocxSections, parseDocxDocument, sanitizeInertDocumentHtml, type ParsedDocxDocument, type ParsedDocxSection, } from "./docx.js";
|
|
6
6
|
export { compositeFigmaColors, extractFigmaTopLevelFrames, figmaColorToHex, figmaContrastRatio, summarizeFigmaFrame, summarizeFigmaNode, type FigmaContextNode, type FigmaFrameSummary, type FigmaRgba, type SummarizeFigmaNodeResult, } from "./figma.js";
|
|
7
7
|
export { cssBlendMode, gradientAngleDegreesFromHandles, gradientGeometryFromTransform, gradientRayAngleDegreesFromHandles, handlePositionsFromArrayTransform, handlePositionsFromObjectTransform, invert2x3, mat2x3FromArray, remapLinearStopPosition, resolveGradientHandles, vectorLength, type BlendModeResult, type BlendVerdict, type GradientGeometry, type GradientHandles, type GradientKind, type Mat2x3Array, type Mat2x3Object, type Vec2, } from "./figma-paint-math.js";
|
package/dist/ingestion/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { acquireIngestionLease, assertInventoryComplete, consumeIngestionBudget, createIngestionBudgetState, createIngestionCheckpoint, ingestionBudgetStopReason, releaseIngestionLease, renewIngestionLease, } from "./orchestration.js";
|
|
2
2
|
export { detectOfficeDocumentType, normalizeDocumentText, parseOfficeDocument, } from "./office.js";
|
|
3
3
|
export { detectSpreadsheetDocumentType, isSpreadsheetDocument, parseSpreadsheetDocument, } from "./spreadsheet.js";
|
|
4
|
-
export { parsePptxPresentation, } from "./pptx.js";
|
|
4
|
+
export { DEFAULT_PPTX_IMAGE_BYTE_LIMITS, PptxImageByteLimitError, parsePptxPresentation, } from "./pptx.js";
|
|
5
5
|
export { extractDocxSections, parseDocxDocument, sanitizeInertDocumentHtml, } from "./docx.js";
|
|
6
6
|
export { compositeFigmaColors, extractFigmaTopLevelFrames, figmaColorToHex, figmaContrastRatio, summarizeFigmaFrame, summarizeFigmaNode, } from "./figma.js";
|
|
7
7
|
export { cssBlendMode, gradientAngleDegreesFromHandles, gradientGeometryFromTransform, gradientRayAngleDegreesFromHandles, handlePositionsFromArrayTransform, handlePositionsFromObjectTransform, invert2x3, mat2x3FromArray, remapLinearStopPosition, resolveGradientHandles, vectorLength, } from "./figma-paint-math.js";
|
package/dist/ingestion/pptx.d.ts
CHANGED
|
@@ -155,7 +155,18 @@ export interface ParsedPptxPresentation {
|
|
|
155
155
|
};
|
|
156
156
|
hiddenSlideCount?: number;
|
|
157
157
|
}
|
|
158
|
+
export interface PptxImageByteLimits {
|
|
159
|
+
maxImageBytes: number;
|
|
160
|
+
maxTotalImageBytes: number;
|
|
161
|
+
}
|
|
162
|
+
export declare const DEFAULT_PPTX_IMAGE_BYTE_LIMITS: Readonly<PptxImageByteLimits>;
|
|
163
|
+
export declare class PptxImageByteLimitError extends Error {
|
|
164
|
+
readonly limit: "per-image" | "aggregate";
|
|
165
|
+
readonly maxBytes: number;
|
|
166
|
+
constructor(limit: "per-image" | "aggregate", maxBytes: number);
|
|
167
|
+
}
|
|
158
168
|
export declare function parsePptxPresentation(fileBuffer: Uint8Array, options?: {
|
|
159
169
|
includeHiddenSlides?: boolean;
|
|
170
|
+
imageByteLimits?: Readonly<PptxImageByteLimits>;
|
|
160
171
|
}): Promise<ParsedPptxPresentation>;
|
|
161
172
|
export declare function parsePptxSlideMetadata(value: unknown): ParsedPptxSlideMetadata;
|
package/dist/ingestion/pptx.js
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
import { loadOptionalPeer } from "../shared/optional-peer.js";
|
|
2
|
+
export const DEFAULT_PPTX_IMAGE_BYTE_LIMITS = Object.freeze({
|
|
3
|
+
maxImageBytes: 10 * 1024 * 1024,
|
|
4
|
+
maxTotalImageBytes: 50 * 1024 * 1024,
|
|
5
|
+
});
|
|
6
|
+
export class PptxImageByteLimitError extends Error {
|
|
7
|
+
limit;
|
|
8
|
+
maxBytes;
|
|
9
|
+
constructor(limit, maxBytes) {
|
|
10
|
+
super(`PPTX image data exceeded its ${limit} byte limit.`);
|
|
11
|
+
this.name = "PptxImageByteLimitError";
|
|
12
|
+
this.limit = limit;
|
|
13
|
+
this.maxBytes = maxBytes;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function resolvePptxImageByteLimits(limits) {
|
|
17
|
+
const configured = limits ?? DEFAULT_PPTX_IMAGE_BYTE_LIMITS;
|
|
18
|
+
if (!Number.isSafeInteger(configured.maxImageBytes) ||
|
|
19
|
+
configured.maxImageBytes < 0 ||
|
|
20
|
+
!Number.isSafeInteger(configured.maxTotalImageBytes) ||
|
|
21
|
+
configured.maxTotalImageBytes < 0) {
|
|
22
|
+
throw new RangeError("PPTX image byte limits must be non-negative integers.");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
maxImageBytes: configured.maxImageBytes,
|
|
26
|
+
maxTotalImageBytes: configured.maxTotalImageBytes,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
2
29
|
export async function parsePptxPresentation(fileBuffer, options = {}) {
|
|
30
|
+
const imageByteLimits = resolvePptxImageByteLimits(options.imageByteLimits);
|
|
31
|
+
const imageBudget = { totalBytes: 0, limits: imageByteLimits };
|
|
3
32
|
const dependencies = await loadPptxDependencies();
|
|
4
33
|
const loadZip = dependencies.loadZip.bind(dependencies);
|
|
5
34
|
const parseXml = dependencies.parseXml.bind(dependencies);
|
|
@@ -127,6 +156,7 @@ export async function parsePptxPresentation(fileBuffer, options = {}) {
|
|
|
127
156
|
themeCache,
|
|
128
157
|
masterInfoCache,
|
|
129
158
|
templateContextCache,
|
|
159
|
+
imageBudget,
|
|
130
160
|
})) ?? fallbackContext;
|
|
131
161
|
const number = slideNumber(slidePath);
|
|
132
162
|
elements = await parseSlideElements({
|
|
@@ -143,6 +173,7 @@ export async function parsePptxPresentation(fileBuffer, options = {}) {
|
|
|
143
173
|
placeholderDefaults: slideMasterContext.placeholderDefaults,
|
|
144
174
|
slideNumber: slides.length + 1,
|
|
145
175
|
tableStyles,
|
|
176
|
+
imageBudget,
|
|
146
177
|
});
|
|
147
178
|
images.unshift(...slideMasterContext.layerImages);
|
|
148
179
|
elements.unshift(...substituteSlideNumber(slideMasterContext.layerElements, slides.length + 1));
|
|
@@ -372,6 +403,7 @@ async function buildSlideTemplateContext(args) {
|
|
|
372
403
|
slideHeightEmu: args.slideHeightEmu,
|
|
373
404
|
images: layerImages,
|
|
374
405
|
colorContext,
|
|
406
|
+
imageBudget: args.imageBudget,
|
|
375
407
|
})));
|
|
376
408
|
}
|
|
377
409
|
return {
|
|
@@ -410,6 +442,7 @@ async function parseTemplateLayerElements(args) {
|
|
|
410
442
|
images,
|
|
411
443
|
tablesDegraded,
|
|
412
444
|
colorContext: args.colorContext,
|
|
445
|
+
imageBudget: args.imageBudget,
|
|
413
446
|
context: { matrix: IDENTITY_MAT, rotation: 0 },
|
|
414
447
|
})));
|
|
415
448
|
}
|
|
@@ -562,6 +595,7 @@ async function parseSlideElements(args) {
|
|
|
562
595
|
y: 0,
|
|
563
596
|
width: args.slideWidthEmu ?? 0,
|
|
564
597
|
height: args.slideHeightEmu ?? 0,
|
|
598
|
+
imageBudget: args.imageBudget,
|
|
565
599
|
});
|
|
566
600
|
if (image) {
|
|
567
601
|
args.images.unshift(image.image);
|
|
@@ -671,6 +705,7 @@ async function parseShapeFragment(fragment, args) {
|
|
|
671
705
|
width: transform.width,
|
|
672
706
|
height: transform.height,
|
|
673
707
|
crop: parseImageCrop(node),
|
|
708
|
+
imageBudget: args.imageBudget,
|
|
674
709
|
});
|
|
675
710
|
if (!image)
|
|
676
711
|
return [];
|
|
@@ -1652,8 +1687,9 @@ async function loadPptxImage(args) {
|
|
|
1652
1687
|
if (!imageFile)
|
|
1653
1688
|
return null;
|
|
1654
1689
|
const name = imagePath.split("/").at(-1) ?? "image";
|
|
1690
|
+
const imageData = await readPptxImageWithinBudget(imageFile, args.imageBudget);
|
|
1655
1691
|
const image = {
|
|
1656
|
-
data: new Uint8Array(
|
|
1692
|
+
data: new Uint8Array(imageData),
|
|
1657
1693
|
mimeType: imageMimeType(name),
|
|
1658
1694
|
name,
|
|
1659
1695
|
aspectRatio: args.width && args.height ? args.width / args.height : undefined,
|
|
@@ -1679,6 +1715,50 @@ async function loadPptxImage(args) {
|
|
|
1679
1715
|
},
|
|
1680
1716
|
};
|
|
1681
1717
|
}
|
|
1718
|
+
async function readPptxImageWithinBudget(imageFile, budget) {
|
|
1719
|
+
const stream = imageFile.nodeStream("nodebuffer");
|
|
1720
|
+
return await new Promise((resolve, reject) => {
|
|
1721
|
+
const chunks = [];
|
|
1722
|
+
let imageBytes = 0;
|
|
1723
|
+
let settled = false;
|
|
1724
|
+
const fail = (error) => {
|
|
1725
|
+
if (settled)
|
|
1726
|
+
return;
|
|
1727
|
+
settled = true;
|
|
1728
|
+
stream.destroy();
|
|
1729
|
+
reject(error);
|
|
1730
|
+
};
|
|
1731
|
+
stream.on("data", (chunk) => {
|
|
1732
|
+
if (settled)
|
|
1733
|
+
return;
|
|
1734
|
+
const nextImageBytes = imageBytes + chunk.byteLength;
|
|
1735
|
+
if (nextImageBytes > budget.limits.maxImageBytes) {
|
|
1736
|
+
fail(new PptxImageByteLimitError("per-image", budget.limits.maxImageBytes));
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
if (budget.totalBytes + nextImageBytes >
|
|
1740
|
+
budget.limits.maxTotalImageBytes) {
|
|
1741
|
+
fail(new PptxImageByteLimitError("aggregate", budget.limits.maxTotalImageBytes));
|
|
1742
|
+
return;
|
|
1743
|
+
}
|
|
1744
|
+
imageBytes = nextImageBytes;
|
|
1745
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1746
|
+
});
|
|
1747
|
+
stream.on("error", (error) => {
|
|
1748
|
+
if (settled)
|
|
1749
|
+
return;
|
|
1750
|
+
settled = true;
|
|
1751
|
+
reject(error);
|
|
1752
|
+
});
|
|
1753
|
+
stream.on("end", () => {
|
|
1754
|
+
if (settled)
|
|
1755
|
+
return;
|
|
1756
|
+
settled = true;
|
|
1757
|
+
budget.totalBytes += imageBytes;
|
|
1758
|
+
resolve(Buffer.concat(chunks, imageBytes));
|
|
1759
|
+
});
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1682
1762
|
function flattenElementText(elements) {
|
|
1683
1763
|
const output = [];
|
|
1684
1764
|
const textElements = elements.filter((element) => element.kind === "text" && element.paragraphs);
|
|
@@ -44,6 +44,11 @@ export default defineAction({
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
}),
|
|
47
|
+
mcpAnnotations: {
|
|
48
|
+
readOnlyHint: false,
|
|
49
|
+
destructiveHint: true,
|
|
50
|
+
openWorldHint: true,
|
|
51
|
+
},
|
|
47
52
|
run: async ({ operation, platform, values }, ctx) => {
|
|
48
53
|
switch (operation) {
|
|
49
54
|
case "save-credentials":
|
package/dist/jobs/scheduler.js
CHANGED
|
@@ -9,6 +9,7 @@ import { backgroundRunCutOffReason, checkBackgroundAutomationCredentials, isBack
|
|
|
9
9
|
import { nextOccurrence, isValidCron, describeCron, effectiveTimezone, } from "./cron.js";
|
|
10
10
|
import { buildJobResourceContent, isRecoveredFactoryJob, jobBelongsToApp, parseJobResource, patchJobFrontmatterFields, recoveredFactoryOwnerOrgId, } from "./frontmatter.js";
|
|
11
11
|
import { dispatchRemoteAutomation, finishRemoteAutomationHistory, getRemoteAutomationStatus, } from "./remote-execution.js";
|
|
12
|
+
import { automationRunOwnership } from "./run-history-ownership.js";
|
|
12
13
|
import { automationRunClaimLeaseMs, claimAutomationRun, finishAutomationRun, getAutomationRun, listAutomationRuns, RUNS_RETAINED_PER_AUTOMATION, } from "./run-history.js";
|
|
13
14
|
import { acquireAutomationSchedulerLease, recordAutomationSchedulerHealth, releaseAutomationSchedulerLease, renewAutomationSchedulerLease, AUTOMATION_SCHEDULER_LEASE_RENEWAL_MS, AutomationSchedulerLeaseLostError, } from "./scheduler-health.js";
|
|
14
15
|
import { reapStaleWork } from "./stale-reaper.js";
|
|
@@ -273,7 +274,7 @@ async function processRecurringJobsWithLease(deps, leaseSignal, assertCanStart)
|
|
|
273
274
|
meta.nextRun = nextOccurrence(meta.schedule, now, meta.timezone).toISOString();
|
|
274
275
|
}
|
|
275
276
|
if (await updateResource(resource, meta, body)) {
|
|
276
|
-
await recoverStaleAutomationHistory(resource
|
|
277
|
+
await recoverStaleAutomationHistory(staleHistoryOwner(resource, meta), resource.path, now);
|
|
277
278
|
}
|
|
278
279
|
continue;
|
|
279
280
|
}
|
|
@@ -462,6 +463,21 @@ async function processRecurringJobsWithLease(deps, leaseSignal, assertCanStart)
|
|
|
462
463
|
});
|
|
463
464
|
}
|
|
464
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* The owner the runner recorded this automation's history under: a legacy
|
|
468
|
+
* shared resource has no organization in its owner, so the resolved execution
|
|
469
|
+
* identity decides (the organization for an org-bound run, the creator
|
|
470
|
+
* otherwise). Recovery must query that owner, not the resource owner.
|
|
471
|
+
*/
|
|
472
|
+
function staleHistoryOwner(resource, meta) {
|
|
473
|
+
const effectiveRunAs = meta.runAs ?? "creator";
|
|
474
|
+
const executionOwner = effectiveRunAs === "creator"
|
|
475
|
+
? meta.createdBy?.trim() || resource.owner
|
|
476
|
+
: resource.owner;
|
|
477
|
+
return automationRunOwnership(resource.owner, executionOwner, recoveredFactoryOwnerOrgId(meta, resource.path, resource.owner) ??
|
|
478
|
+
meta.orgId ??
|
|
479
|
+
null).owner;
|
|
480
|
+
}
|
|
465
481
|
async function recoverStaleAutomationHistory(owner, path, now) {
|
|
466
482
|
const automation = path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
467
483
|
const nowMs = now.getTime();
|
|
@@ -10,6 +10,11 @@ export default defineAction({
|
|
|
10
10
|
description: "Opt the current user into or out of one registered lab. Unset preferences inherit declared legacy flags or use the app-defined default; labs may expose new or unstable features.",
|
|
11
11
|
schema,
|
|
12
12
|
http: { method: "POST" },
|
|
13
|
+
mcpAnnotations: {
|
|
14
|
+
readOnlyHint: false,
|
|
15
|
+
destructiveHint: false,
|
|
16
|
+
openWorldHint: false,
|
|
17
|
+
},
|
|
13
18
|
run: async (args, ctx) => {
|
|
14
19
|
const email = ctx?.userEmail;
|
|
15
20
|
if (!email)
|
|
@@ -20,6 +20,11 @@ export default defineAction({
|
|
|
20
20
|
when: (_args, result) => normalizeActionChangeResult(result) !== null,
|
|
21
21
|
projectResult: (_args, result) => normalizeActionChangeResult(result),
|
|
22
22
|
},
|
|
23
|
+
mcpAnnotations: {
|
|
24
|
+
readOnlyHint: false,
|
|
25
|
+
destructiveHint: false,
|
|
26
|
+
openWorldHint: false,
|
|
27
|
+
},
|
|
23
28
|
run: async (args, ctx) => {
|
|
24
29
|
if (!ctx?.userEmail)
|
|
25
30
|
throw new Error("Not authenticated.");
|
|
@@ -13,6 +13,11 @@ const schema = z.object({
|
|
|
13
13
|
export default defineAction({
|
|
14
14
|
description: "Save a human-proposed instruction update for an agent output. The draft is explicit and never applied automatically.",
|
|
15
15
|
schema,
|
|
16
|
+
mcpAnnotations: {
|
|
17
|
+
readOnlyHint: false,
|
|
18
|
+
destructiveHint: false,
|
|
19
|
+
openWorldHint: false,
|
|
20
|
+
},
|
|
16
21
|
authorize: authorizeObservabilityOrgAdmin,
|
|
17
22
|
run: async (args, ctx) => {
|
|
18
23
|
const { userId, orgId } = getObservabilityOrgAdminAccess(ctx);
|
|
@@ -95,6 +95,11 @@ function artifactEvidenceMatches(source, appId, artifactId) {
|
|
|
95
95
|
}
|
|
96
96
|
export default defineAction({
|
|
97
97
|
description: "Persist a concise human-review summary for a run. Artifact IDs must exactly match IDs returned by get-observability-review-summary-source; do not create, guess, or infer IDs. Include only real design, slide-deck, or analytics artifacts.",
|
|
98
|
+
mcpAnnotations: {
|
|
99
|
+
readOnlyHint: false,
|
|
100
|
+
destructiveHint: true,
|
|
101
|
+
openWorldHint: false,
|
|
102
|
+
},
|
|
98
103
|
schema: z
|
|
99
104
|
.object({
|
|
100
105
|
runId: z
|
|
@@ -75,7 +75,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
|
|
78
|
+
id?: undefined;
|
|
79
|
+
deleted?: undefined;
|
|
80
|
+
provider?: undefined;
|
|
79
81
|
found?: undefined;
|
|
80
82
|
providers: {
|
|
81
83
|
id: string;
|
|
@@ -87,47 +89,45 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
87
89
|
updatedAt: number;
|
|
88
90
|
}[];
|
|
89
91
|
count: number;
|
|
90
|
-
provider?: undefined;
|
|
91
|
-
deleted?: undefined;
|
|
92
92
|
registered?: undefined;
|
|
93
|
-
id?: undefined;
|
|
94
93
|
label?: undefined;
|
|
95
|
-
} | {
|
|
96
94
|
message?: undefined;
|
|
97
|
-
|
|
95
|
+
} | {
|
|
96
|
+
id?: undefined;
|
|
97
|
+
deleted?: undefined;
|
|
98
98
|
count?: undefined;
|
|
99
|
+
providers?: undefined;
|
|
99
100
|
found: boolean;
|
|
100
101
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
101
|
-
deleted?: undefined;
|
|
102
102
|
registered?: undefined;
|
|
103
|
-
id?: undefined;
|
|
104
103
|
label?: undefined;
|
|
105
|
-
} | {
|
|
106
104
|
message?: undefined;
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
} | {
|
|
106
|
+
deleted?: undefined;
|
|
109
107
|
provider?: undefined;
|
|
108
|
+
count?: undefined;
|
|
109
|
+
providers?: undefined;
|
|
110
110
|
found: boolean;
|
|
111
111
|
id: string;
|
|
112
|
-
deleted?: undefined;
|
|
113
112
|
registered?: undefined;
|
|
114
113
|
label?: undefined;
|
|
115
|
-
} | {
|
|
116
114
|
message?: undefined;
|
|
115
|
+
} | {
|
|
116
|
+
provider?: undefined;
|
|
117
|
+
count?: undefined;
|
|
117
118
|
found?: undefined;
|
|
118
119
|
providers?: undefined;
|
|
119
|
-
count?: undefined;
|
|
120
|
-
provider?: undefined;
|
|
121
120
|
deleted: boolean;
|
|
122
121
|
id: string;
|
|
123
122
|
registered?: undefined;
|
|
124
123
|
label?: undefined;
|
|
124
|
+
message?: undefined;
|
|
125
125
|
} | {
|
|
126
|
+
deleted?: undefined;
|
|
127
|
+
provider?: undefined;
|
|
128
|
+
count?: undefined;
|
|
126
129
|
found?: undefined;
|
|
127
130
|
providers?: undefined;
|
|
128
|
-
count?: undefined;
|
|
129
|
-
provider?: undefined;
|
|
130
|
-
deleted?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -317,8 +317,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
317
317
|
scope?: "org" | "user" | undefined;
|
|
318
318
|
}, {
|
|
319
319
|
id?: undefined;
|
|
320
|
-
|
|
320
|
+
provider?: undefined;
|
|
321
|
+
message?: undefined;
|
|
321
322
|
deleted?: undefined;
|
|
323
|
+
found?: undefined;
|
|
322
324
|
providers: {
|
|
323
325
|
id: string;
|
|
324
326
|
label: string;
|
|
@@ -329,46 +331,44 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
329
331
|
updatedAt: number;
|
|
330
332
|
}[];
|
|
331
333
|
count: number;
|
|
332
|
-
provider?: undefined;
|
|
333
334
|
registered?: undefined;
|
|
334
335
|
label?: undefined;
|
|
335
|
-
message?: undefined;
|
|
336
336
|
} | {
|
|
337
337
|
id?: undefined;
|
|
338
|
+
count?: undefined;
|
|
339
|
+
message?: undefined;
|
|
338
340
|
deleted?: undefined;
|
|
339
341
|
providers?: undefined;
|
|
340
|
-
count?: undefined;
|
|
341
342
|
found: boolean;
|
|
342
343
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
343
344
|
registered?: undefined;
|
|
344
345
|
label?: undefined;
|
|
345
|
-
message?: undefined;
|
|
346
346
|
} | {
|
|
347
|
+
provider?: undefined;
|
|
348
|
+
count?: undefined;
|
|
349
|
+
message?: undefined;
|
|
347
350
|
deleted?: undefined;
|
|
348
351
|
providers?: undefined;
|
|
349
|
-
count?: undefined;
|
|
350
|
-
provider?: undefined;
|
|
351
352
|
found: boolean;
|
|
352
353
|
id: string;
|
|
353
354
|
registered?: undefined;
|
|
354
355
|
label?: undefined;
|
|
355
|
-
message?: undefined;
|
|
356
356
|
} | {
|
|
357
|
+
provider?: undefined;
|
|
358
|
+
count?: undefined;
|
|
359
|
+
message?: undefined;
|
|
357
360
|
found?: undefined;
|
|
358
361
|
providers?: undefined;
|
|
359
|
-
count?: undefined;
|
|
360
|
-
provider?: undefined;
|
|
361
362
|
deleted: boolean;
|
|
362
363
|
id: string;
|
|
363
364
|
registered?: undefined;
|
|
364
365
|
label?: undefined;
|
|
365
|
-
message?: undefined;
|
|
366
366
|
} | {
|
|
367
|
-
|
|
367
|
+
provider?: undefined;
|
|
368
|
+
count?: undefined;
|
|
368
369
|
deleted?: undefined;
|
|
370
|
+
found?: undefined;
|
|
369
371
|
providers?: undefined;
|
|
370
|
-
count?: undefined;
|
|
371
|
-
provider?: undefined;
|
|
372
372
|
registered: boolean;
|
|
373
373
|
id: string;
|
|
374
374
|
label: string;
|
|
@@ -73,6 +73,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
+
deleted?: undefined;
|
|
76
77
|
jobs: {
|
|
77
78
|
id: string;
|
|
78
79
|
name: string;
|
|
@@ -83,7 +84,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
83
84
|
updatedAt: string;
|
|
84
85
|
}[];
|
|
85
86
|
total: number;
|
|
86
|
-
deleted?: undefined;
|
|
87
87
|
jobId?: undefined;
|
|
88
88
|
} | {
|
|
89
89
|
jobs?: undefined;
|
|
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
91
91
|
deleted: boolean;
|
|
92
92
|
jobId: string;
|
|
93
93
|
} | {
|
|
94
|
+
deleted?: undefined;
|
|
94
95
|
jobs?: undefined;
|
|
95
96
|
total?: undefined;
|
|
96
|
-
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
|
@@ -787,7 +787,14 @@ const PROVIDER_CONFIGS = {
|
|
|
787
787
|
docsUrls: ["https://developers.google.com/drive/api/reference/rest/v3"],
|
|
788
788
|
specUrls: ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"],
|
|
789
789
|
allowedHostSuffixes: ["googleapis.com"],
|
|
790
|
-
templateUses: [
|
|
790
|
+
templateUses: [
|
|
791
|
+
"brain",
|
|
792
|
+
"content",
|
|
793
|
+
"slides",
|
|
794
|
+
"slides-2",
|
|
795
|
+
"dispatch",
|
|
796
|
+
"analytics",
|
|
797
|
+
],
|
|
791
798
|
examples: [
|
|
792
799
|
{ label: "List files", method: "GET", path: "/files" },
|
|
793
800
|
{ label: "Get file metadata", method: "GET", path: "/files/{fileId}" },
|
|
@@ -843,7 +850,7 @@ const PROVIDER_CONFIGS = {
|
|
|
843
850
|
],
|
|
844
851
|
specUrls: ["https://slides.googleapis.com/$discovery/rest?version=v1"],
|
|
845
852
|
allowedHostSuffixes: ["googleapis.com"],
|
|
846
|
-
templateUses: ["brain", "content", "slides", "dispatch"],
|
|
853
|
+
templateUses: ["brain", "content", "slides", "slides-2", "dispatch"],
|
|
847
854
|
examples: [
|
|
848
855
|
{
|
|
849
856
|
label: "Get presentation with slides and speaker notes",
|
|
@@ -10,6 +10,11 @@ const schema = z.object({
|
|
|
10
10
|
export default defineAction({
|
|
11
11
|
description: "Mark review feedback as consumed by the agent or reviewer workflow.",
|
|
12
12
|
schema,
|
|
13
|
+
mcpAnnotations: {
|
|
14
|
+
readOnlyHint: false,
|
|
15
|
+
destructiveHint: false,
|
|
16
|
+
openWorldHint: false,
|
|
17
|
+
},
|
|
13
18
|
run: async (args, ctx) => {
|
|
14
19
|
const actionCtx = ctx;
|
|
15
20
|
await assertReviewableResourceAccess(args.resourceType, args.resourceId, actionCtx, "editor");
|
|
@@ -40,6 +40,11 @@ const schema = z.object({
|
|
|
40
40
|
export default defineAction({
|
|
41
41
|
description: "Create an inline comment, annotation, or review thread for a resource. Body text supports inline Markdown without headings.",
|
|
42
42
|
schema,
|
|
43
|
+
mcpAnnotations: {
|
|
44
|
+
readOnlyHint: false,
|
|
45
|
+
destructiveHint: false,
|
|
46
|
+
openWorldHint: true,
|
|
47
|
+
},
|
|
43
48
|
run: async (args, ctx) => {
|
|
44
49
|
const actionCtx = ctx;
|
|
45
50
|
const access = await assertReviewableResourceAccess(args.resourceType, args.resourceId, actionCtx, "commenter");
|
|
@@ -12,6 +12,11 @@ const schema = z.object({
|
|
|
12
12
|
export default defineAction({
|
|
13
13
|
description: "Soft-delete a review comment.",
|
|
14
14
|
schema,
|
|
15
|
+
mcpAnnotations: {
|
|
16
|
+
readOnlyHint: false,
|
|
17
|
+
destructiveHint: true,
|
|
18
|
+
openWorldHint: false,
|
|
19
|
+
},
|
|
15
20
|
run: async (args, ctx) => {
|
|
16
21
|
const actionCtx = ctx;
|
|
17
22
|
const scope = {
|
|
@@ -11,6 +11,11 @@ export default defineAction({
|
|
|
11
11
|
reaction: z.string().trim().min(1).max(32),
|
|
12
12
|
active: z.boolean(),
|
|
13
13
|
}),
|
|
14
|
+
mcpAnnotations: {
|
|
15
|
+
readOnlyHint: false,
|
|
16
|
+
destructiveHint: false,
|
|
17
|
+
openWorldHint: false,
|
|
18
|
+
},
|
|
14
19
|
run: async (args, ctx) => {
|
|
15
20
|
await assertReviewableResourceAccess(args.resourceType, args.resourceId, ctx, "commenter");
|
|
16
21
|
const comment = await getReviewCommentById(args.commentId, {
|
|
@@ -29,6 +29,11 @@ const schema = z.object({
|
|
|
29
29
|
export default defineAction({
|
|
30
30
|
description: "Reply to an existing review comment thread with inline Markdown text without headings.",
|
|
31
31
|
schema,
|
|
32
|
+
mcpAnnotations: {
|
|
33
|
+
readOnlyHint: false,
|
|
34
|
+
destructiveHint: false,
|
|
35
|
+
openWorldHint: true,
|
|
36
|
+
},
|
|
32
37
|
run: async (args, ctx) => {
|
|
33
38
|
const actionCtx = ctx;
|
|
34
39
|
const scope = {
|
|
@@ -21,6 +21,11 @@ const schema = z
|
|
|
21
21
|
export default defineAction({
|
|
22
22
|
description: "Resolve or reopen an inline comment or review thread. Resolution notes support inline Markdown without headings and are only valid when resolving.",
|
|
23
23
|
schema,
|
|
24
|
+
mcpAnnotations: {
|
|
25
|
+
readOnlyHint: false,
|
|
26
|
+
destructiveHint: true,
|
|
27
|
+
openWorldHint: false,
|
|
28
|
+
},
|
|
24
29
|
run: async (args, ctx) => {
|
|
25
30
|
const status = args.status ?? "resolved";
|
|
26
31
|
const actionCtx = ctx;
|
|
@@ -10,6 +10,11 @@ const schema = z.object({
|
|
|
10
10
|
export default defineAction({
|
|
11
11
|
description: "Send one open review thread to the agent queue without routing other threads.",
|
|
12
12
|
schema,
|
|
13
|
+
mcpAnnotations: {
|
|
14
|
+
readOnlyHint: false,
|
|
15
|
+
destructiveHint: false,
|
|
16
|
+
openWorldHint: false,
|
|
17
|
+
},
|
|
13
18
|
run: async (args, ctx) => {
|
|
14
19
|
const actionCtx = ctx;
|
|
15
20
|
const access = await assertReviewableResourceAccess(args.resourceType, args.resourceId, actionCtx, "editor");
|
|
@@ -12,6 +12,11 @@ const schema = z.object({
|
|
|
12
12
|
export default defineAction({
|
|
13
13
|
description: "Set the review status for a reusable resource.",
|
|
14
14
|
schema,
|
|
15
|
+
mcpAnnotations: {
|
|
16
|
+
readOnlyHint: false,
|
|
17
|
+
destructiveHint: true,
|
|
18
|
+
openWorldHint: false,
|
|
19
|
+
},
|
|
15
20
|
run: async (args, ctx) => {
|
|
16
21
|
const actionCtx = ctx;
|
|
17
22
|
const access = await assertReviewableResourceAccess(args.resourceType, args.resourceId, actionCtx, "editor");
|