diff --git a/apps/editor/lib/pascal-agent-mcp.ts b/apps/editor/lib/pascal-agent-mcp.ts index fb619244d..d4fbb9931 100644 --- a/apps/editor/lib/pascal-agent-mcp.ts +++ b/apps/editor/lib/pascal-agent-mcp.ts @@ -95,6 +95,18 @@ function readSceneName(result: unknown, fallback: string): string { : fallback } +function readSceneVersion(result: unknown): number | null { + const version = (result as { structuredContent?: { version?: unknown } })?.structuredContent + ?.version + return typeof version === 'number' && Number.isInteger(version) && version > 0 ? version : null +} + +function assertToolSucceeded(result: unknown, operation: string): void { + if ((result as { isError?: unknown })?.isError === true) { + throw new Error(`Pascal MCP ${operation} failed.`) + } +} + export async function createPascalAgentMcpSession(params: { abortSignal?: AbortSignal env?: NodeJS.ProcessEnv @@ -124,16 +136,19 @@ export async function createPascalAgentMcpSession(params: { { id: params.sceneId }, toolExecutionOptions(params.abortSignal), ) + assertToolSucceeded(loadResult, 'load_scene') const sceneName = readSceneName(loadResult, params.sceneId) + let currentVersion = readSceneVersion(loadResult) const saveScene = withStepTimeout(requireTool(allTools, 'save_scene'), params.stepTimeoutMs) const scopedSaveScene: RequiredTool = { ...saveScene, execute: async (input, options) => { const candidate = input && typeof input === 'object' ? input : {} - return saveScene.execute( + const result = await saveScene.execute( { ...candidate, + expectedVersion: currentVersion ?? undefined, graph: undefined, id: params.sceneId, includeCurrentScene: true, @@ -142,6 +157,9 @@ export async function createPascalAgentMcpSession(params: { }, options, ) + const savedVersion = readSceneVersion(result) + if (savedVersion) currentVersion = savedVersion + return result }, } @@ -168,7 +186,7 @@ export async function createPascalAgentMcpSession(params: { sceneName, tools, saveDraft: async (abortSignal) => { - await scopedSaveScene.execute( + const result = await scopedSaveScene.execute( { id: params.sceneId, includeCurrentScene: true, @@ -177,6 +195,7 @@ export async function createPascalAgentMcpSession(params: { }, toolExecutionOptions(abortSignal), ) + assertToolSucceeded(result, 'save_scene') }, } } catch (error) { diff --git a/packages/mcp/src/operations/scene-operations.ts b/packages/mcp/src/operations/scene-operations.ts index fcf3ba3ba..3a1f3edbd 100644 --- a/packages/mcp/src/operations/scene-operations.ts +++ b/packages/mcp/src/operations/scene-operations.ts @@ -272,19 +272,23 @@ class SceneOperationsFacade implements SceneOperations { } async saveScene(options: SceneSaveOptions): Promise { - return this.requireStore().save(options) + const store = this.requireStore() + return store.save(options) } async loadStoredScene(id: string): Promise { - return this.requireStore().load(id) + const store = this.requireStore() + return store.load(id) } async listScenes(options?: SceneListOptions): Promise { - return this.requireStore().list(options) + const store = this.requireStore() + return store.list(options) } async deleteStoredScene(id: string, options?: SceneMutateOptions): Promise { - return this.requireStore().delete(id, options) + const store = this.requireStore() + return store.delete(id, options) } async renameStoredScene( @@ -292,21 +296,22 @@ class SceneOperationsFacade implements SceneOperations { newName: string, options?: SceneMutateOptions, ): Promise { - return this.requireStore().rename(id, newName, options) + const store = this.requireStore() + return store.rename(id, newName, options) } async appendSceneEvent(options: SceneEventAppendOptions): Promise { - const append = this.requireStore().appendSceneEvent - if (!append) return null - return append(options) + const store = this.requireStore() + if (!store.appendSceneEvent) return null + return store.appendSceneEvent(options) } async listSceneEvents(id: string, options?: SceneEventListOptions): Promise { - const list = this.requireStore().listSceneEvents - if (!list) { + const store = this.requireStore() + if (!store.listSceneEvents) { throw new Error('scene_events_unavailable') } - return list(id, options) + return store.listSceneEvents(id, options) } private requireBridge(): SceneBridge {