feat(core): Expose 104_canvas_aia_node_context flag with env override (no-changelog) (#35986)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Miguel Ángel Moreno
2026-08-11 10:10:05 +02:00
committed by GitHub
parent fd701761dc
commit 7b68f584a7
6 changed files with 77 additions and 2 deletions
+1
View File
@@ -334,6 +334,7 @@ export {
CONFIG_EVALUATIONS_ENABLED_VARIANT,
INSTANCE_AI_MCP_CONNECTIONS_FLAG,
INSTANCE_AI_MCP_CONNECTIONS_ENABLED_VARIANT,
CANVAS_NODE_CONTEXT_FLAG,
domainAccessActionSchema,
domainAccessMetaSchema,
webSearchMetaSchema,
@@ -1,10 +1,10 @@
import { z } from 'zod';
import type { McpRegistryServerIconResponse } from './mcp-registry.schema';
import { TimeZoneSchema } from './timezone.schema';
import { AgentJsonConfigSchema } from '../agents/agent-json-config.schema';
import { agentSkillSchema } from '../agents/agent-skill.schema';
import { Z } from '../zod-class';
import type { McpRegistryServerIconResponse } from './mcp-registry.schema';
import { TimeZoneSchema } from './timezone.schema';
// ---------------------------------------------------------------------------
// Credits
@@ -1790,6 +1790,9 @@ export const INSTANCE_AI_MCP_CONNECTIONS_FLAG = '089_instance_ai_mcp_connections
export const INSTANCE_AI_MCP_CONNECTIONS_ENABLED_VARIANT = 'variant';
/** Enables adding selected canvas nodes as chat context in the AI Assistant */
export const CANVAS_NODE_CONTEXT_FLAG = '104_canvas_aia_node_context';
/**
* Records a credential field that was rewritten (e.g. routed to the eval wire
* server) during evaluation. Populated for every AI root the server intercepts;
@@ -193,4 +193,13 @@ export class InstanceAiConfig {
*/
@Env('N8N_INSTANCE_AI_MCP_CONNECTIONS_ENABLED')
mcpConnectionsEnabled: boolean = false;
/**
* Force-enable canvas-selected-nodes chat context in Instance AI.
* Acts as an operator-level override of the PostHog rollout flag
* (`104_canvas_aia_node_context`). Cannot force-disable: setting this to
* `false` falls back to PostHog.
*/
@Env('N8N_INSTANCE_AI_NODE_CONTEXT_ENABLED')
canvasNodeContextEnabled: boolean = false;
}
+1
View File
@@ -359,6 +359,7 @@ describe('GlobalConfig', () => {
thinkingEnabled: true,
durableLog: true,
mcpConnectionsEnabled: false,
canvasNodeContextEnabled: false,
},
queue: {
health: {
@@ -226,6 +226,7 @@ describe('PostHog', () => {
globalConfig.evaluation.configEvalsEnabled = false;
globalConfig.evaluation.agentEvalsEnabled = false;
globalConfig.instanceAi.mcpConnectionsEnabled = false;
globalConfig.instanceAi.canvasNodeContextEnabled = false;
});
it('force-enables the eval-collections flag when N8N_EVAL_COLLECTIONS_ENABLED is set', async () => {
@@ -312,6 +313,57 @@ describe('PostHog', () => {
expect(flags).toEqual({ '101_agent_evals': true });
});
it('force-enables the canvas-node-context flag when N8N_INSTANCE_AI_NODE_CONTEXT_ENABLED is set', async () => {
(PostHog.prototype.evaluateFlags as Mock).mockResolvedValue(mockEvaluatedFlags({}));
globalConfig.instanceAi.canvasNodeContextEnabled = true;
const ph = new PostHogClient(instanceSettings, globalConfig);
await ph.init();
const flags = await ph.getFeatureFlags({ id: userId, createdAt });
expect(flags).toMatchObject({ '104_canvas_aia_node_context': true });
});
it('leaves the canvas-node-context flag untouched when the override is off', async () => {
(PostHog.prototype.evaluateFlags as Mock).mockResolvedValue(
mockEvaluatedFlags({ '104_canvas_aia_node_context': true }),
);
globalConfig.instanceAi.canvasNodeContextEnabled = false;
const ph = new PostHogClient(instanceSettings, globalConfig);
await ph.init();
const flags = await ph.getFeatureFlags({ id: userId, createdAt });
expect(flags).toEqual({ '104_canvas_aia_node_context': true });
});
it('applies all env overrides independently when several are set at once', async () => {
(PostHog.prototype.evaluateFlags as Mock).mockResolvedValue(mockEvaluatedFlags({}));
globalConfig.evaluation.collectionsEnabled = true;
globalConfig.evaluation.configEvalsEnabled = true;
globalConfig.evaluation.agentEvalsEnabled = true;
globalConfig.instanceAi.mcpConnectionsEnabled = true;
globalConfig.instanceAi.canvasNodeContextEnabled = true;
const ph = new PostHogClient(instanceSettings, globalConfig);
await ph.init();
const flags = await ph.getFeatureFlags({ id: userId, createdAt });
expect(flags).toEqual({
'084_eval_collections': true,
'088_config_evaluations': 'variant',
'101_agent_evals': true,
'089_instance_ai_mcp_connections': 'variant',
'104_canvas_aia_node_context': true,
});
});
});
});
+9
View File
@@ -1,5 +1,6 @@
import {
AGENT_EVALS_FLAG,
CANVAS_NODE_CONTEXT_FLAG,
CONFIG_EVALUATIONS_ENABLED_VARIANT,
CONFIG_EVALUATIONS_FLAG,
EVAL_COLLECTIONS_FLAG,
@@ -199,17 +200,25 @@ export class PostHogClient {
if (this.globalConfig.evaluation.collectionsEnabled) {
overrides[EVAL_COLLECTIONS_FLAG] = true;
}
// `088_config_evaluations` is multivariate — the enabled arm is the
// `variant` string, not a boolean (`isConfigEvalsEnabled` checks for it).
if (this.globalConfig.evaluation.configEvalsEnabled) {
overrides[CONFIG_EVALUATIONS_FLAG] = CONFIG_EVALUATIONS_ENABLED_VARIANT;
}
if (this.globalConfig.evaluation.agentEvalsEnabled) {
overrides[AGENT_EVALS_FLAG] = true;
}
if (this.globalConfig.instanceAi.mcpConnectionsEnabled) {
overrides[INSTANCE_AI_MCP_CONNECTIONS_FLAG] = INSTANCE_AI_MCP_CONNECTIONS_ENABLED_VARIANT;
}
if (this.globalConfig.instanceAi.canvasNodeContextEnabled) {
overrides[CANVAS_NODE_CONTEXT_FLAG] = true;
}
return Object.keys(overrides).length === 0 ? flags : { ...flags, ...overrides };
}
}