diff --git a/src/agent/toolBridgeApi.ts b/src/agent/toolBridgeApi.ts
index f21c53d62..18cd2f522 100644
--- a/src/agent/toolBridgeApi.ts
+++ b/src/agent/toolBridgeApi.ts
@@ -18,7 +18,7 @@ import type {
PipelineRunResponse,
} from "@/api/types.gen";
import type { ArgumentType, ComponentReference } from "@/models/componentSpec";
-import type { AiSpec } from "@/routes/v2/pages/Editor/components/AiChat/serializeSpecForAi";
+import type { AiSpec } from "@/routes/v2/shared/components/AiChat/serializeSpecForAi";
interface ValidationIssue {
type: string;
diff --git a/src/routes/v2/pages/Editor/EditorV2.tsx b/src/routes/v2/pages/Editor/EditorV2.tsx
index afdfbf9a3..cb45724f8 100644
--- a/src/routes/v2/pages/Editor/EditorV2.tsx
+++ b/src/routes/v2/pages/Editor/EditorV2.tsx
@@ -14,6 +14,7 @@ import { Text } from "@/components/ui/typography";
import { ComponentLibraryProvider } from "@/providers/ComponentLibraryProvider";
import { ForcedSearchProvider } from "@/providers/ComponentLibraryProvider/ForcedSearchProvider";
import { DialogProvider } from "@/providers/DialogProvider/DialogProvider";
+import { AiChatStoreProvider } from "@/routes/v2/shared/components/AiChat/AiChatStoreContext";
import { useDockAreaAccordion } from "@/routes/v2/shared/hooks/useDockAreaAccordion";
import { useFocusMode } from "@/routes/v2/shared/hooks/useFocusMode";
import { NodeRegistryProvider } from "@/routes/v2/shared/nodes/NodeRegistryContext";
@@ -28,7 +29,6 @@ import { WindowContainer } from "@/routes/v2/shared/windows/WindowContainer";
import { useWindowPersistence } from "@/routes/v2/shared/windows/windowPersistence";
import type { PipelineRef } from "@/services/pipelineStorage/types";
-import { AiChatStoreProvider } from "./components/AiChat/AiChatStoreContext";
import { useDebugPanelWindow } from "./components/DebugPanel";
import { DriverPermissionGate } from "./components/DriverPermissionGate";
import { EditorMenuBar } from "./components/EditorMenuBar/EditorMenuBar";
diff --git a/src/routes/v2/pages/Editor/components/AiChat/toolBridge.test.ts b/src/routes/v2/pages/Editor/components/AiChat/toolBridge.test.ts
index b4c92712c..cc8921a20 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/toolBridge.test.ts
+++ b/src/routes/v2/pages/Editor/components/AiChat/toolBridge.test.ts
@@ -49,7 +49,7 @@ vi.mock("@/utils/submitPipeline", () => ({
),
}));
-import { createToolBridge } from "./toolBridge";
+import { createEditorToolBridge } from "./toolBridge";
/**
* Pass-through undo stub: records every withGroup label invoked so tests
@@ -91,7 +91,7 @@ function buildSpec(): ComponentSpec {
function makeBridge() {
const spec = buildSpec();
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => spec,
getActiveSubgraphPath: () => [],
undo,
@@ -101,7 +101,7 @@ function makeBridge() {
function makeEmptyBridge() {
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => null,
getActiveSubgraphPath: () => [],
undo,
@@ -119,7 +119,7 @@ function makeBackendBridge(
) {
const spec = buildSpec();
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => spec,
getActiveSubgraphPath: () => [],
undo,
@@ -130,7 +130,7 @@ function makeBackendBridge(
return { bridge, spec };
}
-describe("createToolBridge", () => {
+describe("createEditorToolBridge", () => {
describe("requireSpec guard", () => {
it("throws on every mutating call when getSpec returns null", async () => {
const { bridge } = makeEmptyBridge();
@@ -146,7 +146,7 @@ describe("createToolBridge", () => {
it("returns the serialized spec with the active subgraph path", async () => {
const spec = buildSpec();
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => spec,
getActiveSubgraphPath: () => ["preprocess"],
undo,
@@ -314,7 +314,7 @@ describe("createToolBridge", () => {
}),
);
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => spec,
getActiveSubgraphPath: () => [],
undo,
@@ -372,7 +372,7 @@ describe("createToolBridge", () => {
}),
);
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => spec,
getActiveSubgraphPath: () => [],
undo,
@@ -386,7 +386,7 @@ describe("createToolBridge", () => {
it("maps validation issues into the wire shape", async () => {
const spec = new ComponentSpec({ $id: "spec_1", name: "" });
const undo = new RecordingUndo();
- const bridge = createToolBridge({
+ const bridge = createEditorToolBridge({
getSpec: () => spec,
getActiveSubgraphPath: () => [],
undo,
diff --git a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/csomBridge.ts b/src/routes/v2/pages/Editor/components/AiChat/toolBridge/csomBridge.ts
index 12fc27cc3..542d3d9bf 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/csomBridge.ts
+++ b/src/routes/v2/pages/Editor/components/AiChat/toolBridge/csomBridge.ts
@@ -12,7 +12,6 @@ import type {
ValidationResult,
} from "@/agent/toolBridgeApi";
import { validateSpec } from "@/models/componentSpec/validation/validateSpec";
-import { serializeSpecForAi } from "@/routes/v2/pages/Editor/components/AiChat/serializeSpecForAi";
import {
connectNodes,
deleteSelectedEdgesByEdgeIds,
@@ -40,10 +39,22 @@ import {
renameTask,
unpackSubgraphTask,
} from "@/routes/v2/pages/Editor/store/actions/task.actions";
+import { serializeSpecForAi } from "@/routes/v2/shared/components/AiChat/serializeSpecForAi";
+import type { BridgeDeps } from "@/routes/v2/shared/components/AiChat/toolBridge/utils";
+import {
+ computeNextPosition,
+ requireSpec,
+} from "@/routes/v2/shared/components/AiChat/toolBridge/utils";
+import type { UndoGroupable } from "@/routes/v2/shared/nodes/types";
import { hydrateComponentReference } from "@/services/componentService";
-import type { BridgeDeps } from "./utils";
-import { computeNextPosition, requireSpec } from "./utils";
+/**
+ * CSOM handlers need the Editor's undo store to make the agent's spec
+ * edits user-visible and undoable as a single step. `undo` lives here
+ * (not in the shared `BridgeDeps`) because only the Editor's mutating
+ * bridge depends on it.
+ */
+export type CsomBridgeDeps = BridgeDeps & { undo: UndoGroupable };
type CsomHandlers = Pick<
ToolBridgeApi,
@@ -67,7 +78,7 @@ type CsomHandlers = Pick<
| "validatePipeline"
>;
-export function createCsomBridgeHandlers(deps: BridgeDeps): CsomHandlers {
+export function createCsomBridgeHandlers(deps: CsomBridgeDeps): CsomHandlers {
return {
async getPipelineState() {
return serializeSpecForAi(requireSpec(deps), {
diff --git a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/index.ts b/src/routes/v2/pages/Editor/components/AiChat/toolBridge/index.ts
index 62019c37e..36a5a6d4f 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/index.ts
+++ b/src/routes/v2/pages/Editor/components/AiChat/toolBridge/index.ts
@@ -13,15 +13,21 @@
* changes are picked up without rebuilding the bridge.
*/
import type { ToolBridgeApi } from "@/agent/toolBridgeApi";
+import { createDebugBridgeHandlers } from "@/routes/v2/shared/components/AiChat/toolBridge/debugBridge";
+import { createRunBridgeHandlers } from "@/routes/v2/shared/components/AiChat/toolBridge/runBridge";
+import type { CsomBridgeDeps } from "./csomBridge";
import { createCsomBridgeHandlers } from "./csomBridge";
-import { createDebugBridgeHandlers } from "./debugBridge";
-import { createRunBridgeHandlers } from "./runBridge";
-import type { BridgeDeps } from "./utils";
-export type { BridgeDeps } from "./utils";
+export type EditorToolBridgeDeps = CsomBridgeDeps;
-export function createToolBridge(deps: BridgeDeps): ToolBridgeApi {
+/**
+ * Full Editor bridge — shared run/debug handlers plus the Editor's
+ * spec-mutating CSOM handlers (which require the undo store).
+ */
+export function createEditorToolBridge(
+ deps: EditorToolBridgeDeps,
+): ToolBridgeApi {
return {
...createCsomBridgeHandlers(deps),
...createRunBridgeHandlers(deps),
diff --git a/src/routes/v2/pages/Editor/components/PinnedTaskContent/PinnedTaskContent.tsx b/src/routes/v2/pages/Editor/components/PinnedTaskContent/PinnedTaskContent.tsx
index 6b5f43cdf..9e16188e0 100644
--- a/src/routes/v2/pages/Editor/components/PinnedTaskContent/PinnedTaskContent.tsx
+++ b/src/routes/v2/pages/Editor/components/PinnedTaskContent/PinnedTaskContent.tsx
@@ -6,7 +6,7 @@ import { BlockStack } from "@/components/ui/layout";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Text } from "@/components/ui/typography";
import { serializeComponentSpec } from "@/models/componentSpec";
-import { CodeBlock } from "@/routes/v2/pages/Editor/components/PinnedTaskContent/components/CodeBlock";
+import { CodeBlock } from "@/routes/v2/shared/components/CodeBlock";
import { useSpec } from "@/routes/v2/shared/providers/SpecContext";
import { tracking } from "@/utils/tracking";
import { componentSpecToText } from "@/utils/yaml";
diff --git a/src/routes/v2/pages/Editor/hooks/useAiChatWindow.tsx b/src/routes/v2/pages/Editor/hooks/useAiChatWindow.tsx
index dbcd67fee..56176a676 100644
--- a/src/routes/v2/pages/Editor/hooks/useAiChatWindow.tsx
+++ b/src/routes/v2/pages/Editor/hooks/useAiChatWindow.tsx
@@ -1,12 +1,15 @@
import { useEffect } from "react";
-import { AiChatContent } from "@/routes/v2/pages/Editor/components/AiChat/AiChatContent";
+import { createEditorToolBridge } from "@/routes/v2/pages/Editor/components/AiChat/toolBridge";
+import { useEditorSession } from "@/routes/v2/pages/Editor/store/EditorSessionContext";
+import { AiChatContent } from "@/routes/v2/shared/components/AiChat/AiChatContent";
import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext";
const AI_CHAT_WINDOW_ID = "ai-assistant-chat";
export function useAiChatWindow(enabled: boolean) {
const { windows } = useSharedStores();
+ const editorSession = useEditorSession();
useEffect(() => {
if (!enabled) {
@@ -15,13 +18,20 @@ export function useAiChatWindow(enabled: boolean) {
}
if (windows.getWindowById(AI_CHAT_WINDOW_ID)) return;
- windows.openWindow(, {
- id: AI_CHAT_WINDOW_ID,
- title: "AI Assistant",
- position: { x: 100, y: 80 },
- size: { width: 380, height: 520 },
- disabledActions: ["close"],
- persisted: true,
- });
- }, [enabled, windows]);
+ windows.openWindow(
+
+ createEditorToolBridge({ ...deps, undo: editorSession.undo })
+ }
+ />,
+ {
+ id: AI_CHAT_WINDOW_ID,
+ title: "AI Assistant",
+ position: { x: 100, y: 80 },
+ size: { width: 380, height: 520 },
+ disabledActions: ["close"],
+ persisted: true,
+ },
+ );
+ }, [enabled, windows, editorSession]);
}
diff --git a/src/routes/v2/pages/Editor/components/AiChat/AiChatContent.tsx b/src/routes/v2/shared/components/AiChat/AiChatContent.tsx
similarity index 85%
rename from src/routes/v2/pages/Editor/components/AiChat/AiChatContent.tsx
rename to src/routes/v2/shared/components/AiChat/AiChatContent.tsx
index efdcc850b..6ba5a7e56 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/AiChatContent.tsx
+++ b/src/routes/v2/shared/components/AiChat/AiChatContent.tsx
@@ -3,12 +3,12 @@ import { observer } from "mobx-react-lite";
import { useEffect, useRef, useState } from "react";
import type { RecentPipelineRun } from "@/agent/session";
+import type { ToolBridgeApi } from "@/agent/toolBridgeApi";
import { useAuthLocalStorage } from "@/components/shared/Authentication/useAuthLocalStorage";
import { BlockStack } from "@/components/ui/layout";
import { useAiProviderSettings } from "@/hooks/useAiProviderSettings";
import useToastNotification from "@/hooks/useToastNotification";
import { useBackend } from "@/providers/BackendProvider";
-import { useEditorSession } from "@/routes/v2/pages/Editor/store/EditorSessionContext";
import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext";
import { fetchPipelineRuns } from "@/services/pipelineRunService";
import type { PipelineRun } from "@/types/pipelineRun";
@@ -17,10 +17,22 @@ import { useAiChatStore } from "./AiChatStoreContext";
import { AiProviderSetup } from "./components/AiProviderSetup";
import { ChatInput } from "./components/ChatInput";
import { ChatMessageList } from "./components/ChatMessageList";
-import { createToolBridge } from "./toolBridge";
+import type { BridgeDeps } from "./toolBridge/utils";
const RECENT_RUNS_LIMIT = 5;
+/**
+ * Deps every consumer can supply from the shared navigation/backend/auth
+ * stores. The page-specific bridge factory turns these into a concrete
+ * `ToolBridgeApi` (Editor adds spec-mutating CSOM handlers; RunView stays
+ * read-only).
+ */
+type CreateBridge = (deps: BridgeDeps) => ToolBridgeApi;
+
+interface AiChatContentProps {
+ createBridge: CreateBridge;
+}
+
function projectRecentRuns(runs: PipelineRun[]): RecentPipelineRun[] {
return runs.slice(0, RECENT_RUNS_LIMIT).map((run) => ({
id: run.id,
@@ -31,11 +43,12 @@ function projectRecentRuns(runs: PipelineRun[]): RecentPipelineRun[] {
}));
}
-export const AiChatContent = observer(function AiChatContent() {
+export const AiChatContent = observer(function AiChatContent({
+ createBridge,
+}: AiChatContentProps) {
const aiChat = useAiChatStore();
const notify = useToastNotification();
const { navigation } = useSharedStores();
- const editorSession = useEditorSession();
const { backendUrl } = useBackend();
const authStorage = useAuthLocalStorage();
const queryClient = useQueryClient();
@@ -56,18 +69,17 @@ export const AiChatContent = observer(function AiChatContent() {
authTokenRef.current = authToken;
}, [authToken]);
- // The bridge closes over the navigation + undo stores plus the
+ // The bridge closes over the navigation store plus the
// backend/auth/queryClient deps captured via refs. A single instance
// per AiChatContent mount is correct: each method call re-reads
// `navigation.rootSpec`, the active path, and the latest backend
// values lazily so navigation / backend changes are picked up
// without rebuilding the bridge.
const [bridge] = useState(() =>
- createToolBridge({
+ createBridge({
getSpec: () => navigation.rootSpec,
getActiveSubgraphPath: () =>
navigation.navigationPath.slice(1).map((e) => e.displayName),
- undo: editorSession.undo,
getBackendUrl: () => backendUrlRef.current,
getAuthToken: () => authTokenRef.current,
queryClient,
diff --git a/src/routes/v2/pages/Editor/components/AiChat/AiChatStoreContext.tsx b/src/routes/v2/shared/components/AiChat/AiChatStoreContext.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/AiChatStoreContext.tsx
rename to src/routes/v2/shared/components/AiChat/AiChatStoreContext.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/agentClient.ts b/src/routes/v2/shared/components/AiChat/agentClient.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/agentClient.ts
rename to src/routes/v2/shared/components/AiChat/agentClient.ts
diff --git a/src/routes/v2/pages/Editor/components/AiChat/aiChatStore.ts b/src/routes/v2/shared/components/AiChat/aiChatStore.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/aiChatStore.ts
rename to src/routes/v2/shared/components/AiChat/aiChatStore.ts
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/AiProviderSetup.tsx b/src/routes/v2/shared/components/AiChat/components/AiProviderSetup.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/components/AiProviderSetup.tsx
rename to src/routes/v2/shared/components/AiChat/components/AiProviderSetup.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/ChatEntityChip.tsx b/src/routes/v2/shared/components/AiChat/components/ChatEntityChip.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/components/ChatEntityChip.tsx
rename to src/routes/v2/shared/components/AiChat/components/ChatEntityChip.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/ChatInput.tsx b/src/routes/v2/shared/components/AiChat/components/ChatInput.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/components/ChatInput.tsx
rename to src/routes/v2/shared/components/AiChat/components/ChatInput.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/ChatMessage.tsx b/src/routes/v2/shared/components/AiChat/components/ChatMessage.tsx
similarity index 95%
rename from src/routes/v2/pages/Editor/components/AiChat/components/ChatMessage.tsx
rename to src/routes/v2/shared/components/AiChat/components/ChatMessage.tsx
index 7f5c4142c..b32383cec 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/components/ChatMessage.tsx
+++ b/src/routes/v2/shared/components/AiChat/components/ChatMessage.tsx
@@ -1,5 +1,5 @@
import { Text } from "@/components/ui/typography";
-import type { ChatMessage as ChatMessageType } from "@/routes/v2/pages/Editor/components/AiChat/types";
+import type { ChatMessage as ChatMessageType } from "@/routes/v2/shared/components/AiChat/types";
import { MessageBubble } from "./MessageBubble";
import { renderMarkdown } from "./renderMarkdown";
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/ChatMessageList.tsx b/src/routes/v2/shared/components/AiChat/components/ChatMessageList.tsx
similarity index 96%
rename from src/routes/v2/pages/Editor/components/AiChat/components/ChatMessageList.tsx
rename to src/routes/v2/shared/components/AiChat/components/ChatMessageList.tsx
index 07ee7a653..f0a83ff5f 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/components/ChatMessageList.tsx
+++ b/src/routes/v2/shared/components/AiChat/components/ChatMessageList.tsx
@@ -2,7 +2,7 @@ import { useEffect, useRef } from "react";
import { BlockStack } from "@/components/ui/layout";
import { Text } from "@/components/ui/typography";
-import type { ChatMessage as ChatMessageType } from "@/routes/v2/pages/Editor/components/AiChat/types";
+import type { ChatMessage as ChatMessageType } from "@/routes/v2/shared/components/AiChat/types";
import { ChatMessage } from "./ChatMessage";
import { ThinkingMessage } from "./ThinkingMessage";
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/ComponentChip.tsx b/src/routes/v2/shared/components/AiChat/components/ComponentChip.tsx
similarity index 93%
rename from src/routes/v2/pages/Editor/components/AiChat/components/ComponentChip.tsx
rename to src/routes/v2/shared/components/AiChat/components/ComponentChip.tsx
index c0b4743fc..5b546b5f3 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/components/ComponentChip.tsx
+++ b/src/routes/v2/shared/components/AiChat/components/ComponentChip.tsx
@@ -1,7 +1,7 @@
import type { DragEvent } from "react";
import ComponentDetailsDialog from "@/components/shared/Dialogs/ComponentDetailsDialog";
-import type { ComponentRefData } from "@/routes/v2/pages/Editor/components/AiChat/types";
+import type { ComponentRefData } from "@/routes/v2/shared/components/AiChat/types";
import type { ComponentReference } from "@/utils/componentSpec";
import { ChatEntityChip } from "./ChatEntityChip";
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/EntityChip.tsx b/src/routes/v2/shared/components/AiChat/components/EntityChip.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/components/EntityChip.tsx
rename to src/routes/v2/shared/components/AiChat/components/EntityChip.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/MessageBubble.tsx b/src/routes/v2/shared/components/AiChat/components/MessageBubble.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/components/MessageBubble.tsx
rename to src/routes/v2/shared/components/AiChat/components/MessageBubble.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/ThinkingMessage.tsx b/src/routes/v2/shared/components/AiChat/components/ThinkingMessage.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/components/ThinkingMessage.tsx
rename to src/routes/v2/shared/components/AiChat/components/ThinkingMessage.tsx
diff --git a/src/routes/v2/pages/Editor/components/AiChat/components/renderMarkdown.tsx b/src/routes/v2/shared/components/AiChat/components/renderMarkdown.tsx
similarity index 96%
rename from src/routes/v2/pages/Editor/components/AiChat/components/renderMarkdown.tsx
rename to src/routes/v2/shared/components/AiChat/components/renderMarkdown.tsx
index c37a97eb0..653a3a918 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/components/renderMarkdown.tsx
+++ b/src/routes/v2/shared/components/AiChat/components/renderMarkdown.tsx
@@ -12,8 +12,8 @@ import { Link } from "@/components/ui/link";
import { Separator } from "@/components/ui/separator";
import { Paragraph, Text } from "@/components/ui/typography";
import { getComponentQueryKey } from "@/hooks/useHydrateComponentReference";
-import type { ComponentRefData } from "@/routes/v2/pages/Editor/components/AiChat/types";
-import { CodeBlock } from "@/routes/v2/pages/Editor/components/PinnedTaskContent/components/CodeBlock";
+import type { ComponentRefData } from "@/routes/v2/shared/components/AiChat/types";
+import { CodeBlock } from "@/routes/v2/shared/components/CodeBlock";
import { hydrateComponentReference } from "@/services/componentService";
import { ComponentChip } from "./ComponentChip";
diff --git a/src/routes/v2/pages/Editor/components/AiChat/serializeSpecForAi.test.ts b/src/routes/v2/shared/components/AiChat/serializeSpecForAi.test.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/serializeSpecForAi.test.ts
rename to src/routes/v2/shared/components/AiChat/serializeSpecForAi.test.ts
diff --git a/src/routes/v2/pages/Editor/components/AiChat/serializeSpecForAi.ts b/src/routes/v2/shared/components/AiChat/serializeSpecForAi.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/serializeSpecForAi.ts
rename to src/routes/v2/shared/components/AiChat/serializeSpecForAi.ts
diff --git a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/debugBridge.ts b/src/routes/v2/shared/components/AiChat/toolBridge/debugBridge.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/toolBridge/debugBridge.ts
rename to src/routes/v2/shared/components/AiChat/toolBridge/debugBridge.ts
diff --git a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/runBridge.ts b/src/routes/v2/shared/components/AiChat/toolBridge/runBridge.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/toolBridge/runBridge.ts
rename to src/routes/v2/shared/components/AiChat/toolBridge/runBridge.ts
diff --git a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/utils.ts b/src/routes/v2/shared/components/AiChat/toolBridge/utils.ts
similarity index 96%
rename from src/routes/v2/pages/Editor/components/AiChat/toolBridge/utils.ts
rename to src/routes/v2/shared/components/AiChat/toolBridge/utils.ts
index 31c8469b0..48e1453a3 100644
--- a/src/routes/v2/pages/Editor/components/AiChat/toolBridge/utils.ts
+++ b/src/routes/v2/shared/components/AiChat/toolBridge/utils.ts
@@ -14,7 +14,6 @@
import type { QueryClient } from "@tanstack/react-query";
import type { ComponentSpec } from "@/models/componentSpec";
-import type { UndoGroupable } from "@/routes/v2/shared/nodes/types";
import { EDITOR_POSITION_ANNOTATION } from "@/utils/annotations";
const DEFAULT_POSITION = { x: 250, y: 250 };
@@ -23,7 +22,6 @@ const POSITION_OFFSET = 200;
export interface BridgeDeps {
getSpec: () => ComponentSpec | null;
getActiveSubgraphPath: () => string[];
- undo: UndoGroupable;
getBackendUrl?: () => string;
getAuthToken?: () => string | undefined;
queryClient?: QueryClient;
diff --git a/src/routes/v2/pages/Editor/components/AiChat/types.ts b/src/routes/v2/shared/components/AiChat/types.ts
similarity index 100%
rename from src/routes/v2/pages/Editor/components/AiChat/types.ts
rename to src/routes/v2/shared/components/AiChat/types.ts
diff --git a/src/routes/v2/pages/Editor/components/PinnedTaskContent/components/CodeBlock.tsx b/src/routes/v2/shared/components/CodeBlock.tsx
similarity index 100%
rename from src/routes/v2/pages/Editor/components/PinnedTaskContent/components/CodeBlock.tsx
rename to src/routes/v2/shared/components/CodeBlock.tsx