205 lines
6.6 KiB
TypeScript
205 lines
6.6 KiB
TypeScript
export type CanvasAgentWritebackMode =
|
|
| "legacy_canvas_media"
|
|
| "operation_shadow"
|
|
| "operation_authoritative";
|
|
|
|
export type CanvasAgentFeatureFlags = {
|
|
operationProtocolEnabled: boolean;
|
|
writebackMode: CanvasAgentWritebackMode;
|
|
slotEnabled: boolean;
|
|
viewOperationEnabled: boolean;
|
|
annotationEditEnabled: boolean;
|
|
};
|
|
|
|
export type CanvasAgentFeatureSettings = CanvasAgentFeatureFlags;
|
|
|
|
export const defaultCanvasAgentFeatureSettings: CanvasAgentFeatureSettings = {
|
|
operationProtocolEnabled: true,
|
|
writebackMode: "operation_authoritative",
|
|
slotEnabled: true,
|
|
viewOperationEnabled: true,
|
|
annotationEditEnabled: true,
|
|
};
|
|
|
|
export function normalizeCanvasAgentFeatureSettings(
|
|
value: unknown,
|
|
fallback: CanvasAgentFeatureSettings = defaultCanvasAgentFeatureSettings
|
|
): CanvasAgentFeatureSettings {
|
|
const raw =
|
|
value && typeof value === "object" && !Array.isArray(value)
|
|
? (value as Partial<CanvasAgentFeatureSettings>)
|
|
: {};
|
|
|
|
return {
|
|
operationProtocolEnabled: normalizeCanvasAgentBoolean(
|
|
raw.operationProtocolEnabled,
|
|
fallback.operationProtocolEnabled
|
|
),
|
|
writebackMode: normalizeCanvasAgentWritebackMode(
|
|
raw.writebackMode,
|
|
fallback.writebackMode
|
|
),
|
|
slotEnabled: normalizeCanvasAgentBoolean(raw.slotEnabled, fallback.slotEnabled),
|
|
viewOperationEnabled: normalizeCanvasAgentBoolean(
|
|
raw.viewOperationEnabled,
|
|
fallback.viewOperationEnabled
|
|
),
|
|
annotationEditEnabled: normalizeCanvasAgentBoolean(
|
|
raw.annotationEditEnabled,
|
|
fallback.annotationEditEnabled
|
|
),
|
|
};
|
|
}
|
|
|
|
export const CANVAS_AGENT_OPERATION_PROTOCOL_ENABLED_KEY =
|
|
"canvas_agent_operation_protocol_enabled";
|
|
export const CANVAS_AGENT_WRITEBACK_MODE_KEY = "canvas_agent_writeback_mode";
|
|
export const CANVAS_AGENT_SLOT_ENABLED_KEY = "canvas_agent_slot_enabled";
|
|
export const CANVAS_AGENT_VIEW_OPERATION_ENABLED_KEY =
|
|
"canvas_agent_view_operation_enabled";
|
|
export const CANVAS_AGENT_ANNOTATION_EDIT_ENABLED_KEY =
|
|
"canvas_agent_annotation_edit_enabled";
|
|
|
|
export const CANVAS_AGENT_FEATURE_SETTING_KEYS = [
|
|
CANVAS_AGENT_OPERATION_PROTOCOL_ENABLED_KEY,
|
|
CANVAS_AGENT_WRITEBACK_MODE_KEY,
|
|
CANVAS_AGENT_SLOT_ENABLED_KEY,
|
|
CANVAS_AGENT_VIEW_OPERATION_ENABLED_KEY,
|
|
CANVAS_AGENT_ANNOTATION_EDIT_ENABLED_KEY,
|
|
] as const;
|
|
|
|
type EnvLike = Record<string, string | undefined>;
|
|
export type CanvasAgentFeatureSettingKey =
|
|
(typeof CANVAS_AGENT_FEATURE_SETTING_KEYS)[number];
|
|
export type CanvasAgentFeatureSettingsLike = Partial<
|
|
Record<CanvasAgentFeatureSettingKey, unknown>
|
|
>;
|
|
|
|
const WRITEBACK_MODES = new Set<CanvasAgentWritebackMode>([
|
|
"legacy_canvas_media",
|
|
"operation_shadow",
|
|
"operation_authoritative",
|
|
]);
|
|
|
|
export function normalizeCanvasAgentBoolean(
|
|
value: unknown,
|
|
fallback: boolean
|
|
) {
|
|
if (typeof value === "boolean") return value;
|
|
if (typeof value === "number" && Number.isFinite(value)) return value !== 0;
|
|
if (typeof value !== "string") return fallback;
|
|
const normalized = value.trim().toLowerCase();
|
|
if (!normalized) return fallback;
|
|
if (["1", "true", "yes", "on", "enabled"].includes(normalized)) return true;
|
|
if (["0", "false", "no", "off", "disabled"].includes(normalized)) return false;
|
|
return fallback;
|
|
}
|
|
|
|
export function normalizeCanvasAgentWritebackMode(
|
|
value: unknown,
|
|
fallback: CanvasAgentWritebackMode = "operation_authoritative"
|
|
): CanvasAgentWritebackMode {
|
|
const normalized = typeof value === "string" ? value.trim() : "";
|
|
return WRITEBACK_MODES.has(normalized as CanvasAgentWritebackMode)
|
|
? (normalized as CanvasAgentWritebackMode)
|
|
: fallback;
|
|
}
|
|
|
|
export function mergeCanvasAgentFeatureFlagsWithSettings(
|
|
flags: CanvasAgentFeatureFlags,
|
|
settings?: CanvasAgentFeatureSettingsLike | null
|
|
): CanvasAgentFeatureFlags {
|
|
if (!settings) return flags;
|
|
|
|
return {
|
|
operationProtocolEnabled: normalizeCanvasAgentBoolean(
|
|
settings[CANVAS_AGENT_OPERATION_PROTOCOL_ENABLED_KEY],
|
|
flags.operationProtocolEnabled
|
|
),
|
|
writebackMode: normalizeCanvasAgentWritebackMode(
|
|
settings[CANVAS_AGENT_WRITEBACK_MODE_KEY],
|
|
flags.writebackMode
|
|
),
|
|
slotEnabled: normalizeCanvasAgentBoolean(
|
|
settings[CANVAS_AGENT_SLOT_ENABLED_KEY],
|
|
flags.slotEnabled
|
|
),
|
|
viewOperationEnabled: normalizeCanvasAgentBoolean(
|
|
settings[CANVAS_AGENT_VIEW_OPERATION_ENABLED_KEY],
|
|
flags.viewOperationEnabled
|
|
),
|
|
annotationEditEnabled: normalizeCanvasAgentBoolean(
|
|
settings[CANVAS_AGENT_ANNOTATION_EDIT_ENABLED_KEY],
|
|
flags.annotationEditEnabled
|
|
),
|
|
};
|
|
}
|
|
|
|
export function getCanvasAgentFeatureFlags(
|
|
env: EnvLike = process.env,
|
|
settings?: CanvasAgentFeatureSettingsLike | null
|
|
): CanvasAgentFeatureFlags {
|
|
const envFlags: CanvasAgentFeatureFlags = {
|
|
operationProtocolEnabled: normalizeCanvasAgentBoolean(
|
|
env.CANVAS_AGENT_OPERATION_PROTOCOL_ENABLED,
|
|
true
|
|
),
|
|
writebackMode: normalizeCanvasAgentWritebackMode(
|
|
env.CANVAS_AGENT_WRITEBACK_MODE,
|
|
"operation_authoritative"
|
|
),
|
|
slotEnabled: normalizeCanvasAgentBoolean(
|
|
env.CANVAS_AGENT_SLOT_ENABLED,
|
|
true
|
|
),
|
|
viewOperationEnabled: normalizeCanvasAgentBoolean(
|
|
env.CANVAS_AGENT_VIEW_OPERATION_ENABLED,
|
|
true
|
|
),
|
|
annotationEditEnabled: normalizeCanvasAgentBoolean(
|
|
env.CANVAS_AGENT_ANNOTATION_EDIT_ENABLED,
|
|
true
|
|
),
|
|
};
|
|
return mergeCanvasAgentFeatureFlagsWithSettings(envFlags, settings);
|
|
}
|
|
|
|
export function canvasAgentFeatureFlagsToSettings(
|
|
flags: CanvasAgentFeatureFlags
|
|
): CanvasAgentFeatureSettings {
|
|
return {
|
|
operationProtocolEnabled: flags.operationProtocolEnabled,
|
|
writebackMode: flags.writebackMode,
|
|
slotEnabled: flags.slotEnabled,
|
|
viewOperationEnabled: flags.viewOperationEnabled,
|
|
annotationEditEnabled: flags.annotationEditEnabled,
|
|
};
|
|
}
|
|
|
|
export function canvasAgentFeatureSettingsToSystemSettings(
|
|
settings: CanvasAgentFeatureSettings
|
|
): CanvasAgentFeatureSettingsLike {
|
|
return {
|
|
[CANVAS_AGENT_OPERATION_PROTOCOL_ENABLED_KEY]:
|
|
settings.operationProtocolEnabled,
|
|
[CANVAS_AGENT_WRITEBACK_MODE_KEY]: settings.writebackMode,
|
|
[CANVAS_AGENT_SLOT_ENABLED_KEY]: settings.slotEnabled,
|
|
[CANVAS_AGENT_VIEW_OPERATION_ENABLED_KEY]: settings.viewOperationEnabled,
|
|
[CANVAS_AGENT_ANNOTATION_EDIT_ENABLED_KEY]:
|
|
settings.annotationEditEnabled,
|
|
};
|
|
}
|
|
|
|
export function canApplyCanvasAgentMutations(flags: CanvasAgentFeatureFlags) {
|
|
return (
|
|
flags.operationProtocolEnabled &&
|
|
flags.writebackMode === "operation_authoritative"
|
|
);
|
|
}
|
|
|
|
export function shouldStreamCanvasAgentShadowOperations(
|
|
flags: CanvasAgentFeatureFlags
|
|
) {
|
|
return flags.operationProtocolEnabled && flags.writebackMode === "operation_shadow";
|
|
}
|