diff --git a/lib/runtime/desktop_thread_artifact_service.dart b/lib/runtime/desktop_thread_artifact_service.dart index 1f9acf21..d046f301 100644 --- a/lib/runtime/desktop_thread_artifact_service.dart +++ b/lib/runtime/desktop_thread_artifact_service.dart @@ -60,7 +60,9 @@ class DesktopThreadArtifactService { final taskArtifactPaths = normalizeTaskArtifactPathsInternal( artifactRelativePaths, ); - final allFiles = await collectFilesInternal(root); + final allFiles = taskArtifactPaths.isEmpty + ? const [] + : await collectFilesInternal(root); final fileEntries = await buildEntriesInternal(allFiles, normalizedRef); final taskFiles = taskArtifactPaths.isEmpty ? const [] @@ -91,7 +93,9 @@ class DesktopThreadArtifactService { ? 'No task artifacts recorded for this run.' : 'No current task artifacts found. Showing all files for this thread.' : ''; - final filesMessage = fileEntries.isEmpty + final filesMessage = taskArtifactPaths.isEmpty + ? '' + : fileEntries.isEmpty ? 'No files found in the recorded working directory.' : ''; final changesMessage = changes.isEmpty diff --git a/test/runtime/app_controller_thread_workspace_binding_test.dart b/test/runtime/app_controller_thread_workspace_binding_test.dart index 5aab6cec..3025ceea 100644 --- a/test/runtime/app_controller_thread_workspace_binding_test.dart +++ b/test/runtime/app_controller_thread_workspace_binding_test.dart @@ -1310,10 +1310,8 @@ void main() { sessionKey: 'unit-fixture-task-a', ); expect(snapshot.resultEntries, isEmpty); - expect( - snapshot.fileEntries.map((entry) => entry.relativePath), - contains('old-task-report.md'), - ); + expect(snapshot.fileEntries, isEmpty); + expect(snapshot.resultMessage, 'No task artifacts recorded for this run.'); }); test('skips download URL artifacts outside the bridge host', () async { diff --git a/test/runtime/assistant_execution_target_test.dart b/test/runtime/assistant_execution_target_test.dart index be4435b7..17d01d25 100644 --- a/test/runtime/assistant_execution_target_test.dart +++ b/test/runtime/assistant_execution_target_test.dart @@ -2263,9 +2263,10 @@ void main() { ); expect(taskBSnapshot.fileEntries, isEmpty); expect( - taskBSnapshot.filesMessage, - 'No files found in the recorded working directory.', + taskBSnapshot.resultMessage, + 'No task artifacts recorded for this run.', ); + expect(taskBSnapshot.filesMessage, isEmpty); }, ); @@ -2404,9 +2405,10 @@ void main() { sessionKey: 'terminal-failure-task', ); expect(snapshot.resultEntries, isEmpty); + expect(snapshot.fileEntries, isEmpty); expect( - snapshot.fileEntries.map((entry) => entry.relativePath), - contains('first.md'), + snapshot.resultMessage, + 'No task artifacts recorded for this run.', ); }, ); @@ -2709,6 +2711,57 @@ void main() { }, ); + test( + 'OpenClaw gateway admits five representative E2E tasks without queueing', + () async { + final fakeGoTaskService = _BlockingGoTaskServiceClient(); + final controller = _connectedGatewayController(fakeGoTaskService); + addTearDown(() { + fakeGoTaskService.completeAll(); + controller.dispose(); + }); + + const prompts = [ + '从单机权限 → 网络边界 → Web安全 → 云身份 → Zero Trust → AI Agent 身份 → AI模型与知识保护 演进 制作 使用codex 制作连续制作 7张的一些列图片', + '参考附件模版制作 ,围绕 从单机权限 → 网络边界 → Web安全 → 云身份 → Zero Trust → AI Agent 身份 → AI模型与知识保护 演进 连续制作 7张的一些列图片', + '拆章节 -> 每章调用 Codex -> 每章 GPT images2 生成图 -> 汇总排版 -> 输出 PDF', + '围绕 从单机权限 → 网络边界 → Web安全 → 云身份 → Zero Trust → AI Agent 身份 → AI模型与知识保护 演进 右侧是当下 测试制作视频', + '从单机权限 → 网络边界 → Web安全 → 云身份 → Zero Trust → AI Agent 身份 → AI模型与知识保护 演进 拆章节 -> 每章调用 Codex -> 每章 GPT images2 生成图 -> 汇总排版 -> 制作视频', + ]; + + for (var index = 0; index < prompts.length; index += 1) { + final sessionKey = 'openclaw-e2e-$index'; + await _selectGatewaySession(controller, sessionKey); + await expectLater( + controller + .sendChatMessage(prompts[index]) + .timeout(const Duration(seconds: 2)), + completes, + ); + } + + await fakeGoTaskService.waitForRequestCount(prompts.length); + expect(fakeGoTaskService.requests, hasLength(prompts.length)); + expect(controller.openClawGatewayActiveTasksInternal, prompts.length); + expect(controller.openClawGatewayQueuedTurnsInternal, isEmpty); + for (var index = 0; index < prompts.length; index += 1) { + final sessionKey = 'openclaw-e2e-$index'; + expect( + controller + .requireTaskThreadForSessionInternal(sessionKey) + .lifecycleState + .status, + 'running', + ); + expect(fakeGoTaskService.requests[index].sessionId, sessionKey); + expect( + fakeGoTaskService.requests[index].prompt, + contains(prompts[index]), + ); + } + }, + ); + test('OpenClaw gateway task uses the server default model', () async { final fakeGoTaskService = _BlockingGoTaskServiceClient(); final controller = _connectedGatewayController(fakeGoTaskService); diff --git a/test/runtime/desktop_thread_artifact_service_test.dart b/test/runtime/desktop_thread_artifact_service_test.dart index 9917a34b..a797093f 100644 --- a/test/runtime/desktop_thread_artifact_service_test.dart +++ b/test/runtime/desktop_thread_artifact_service_test.dart @@ -1,12 +1,13 @@ import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; +import 'package:xworkmate/runtime/assistant_artifacts.dart'; import 'package:xworkmate/runtime/desktop_thread_artifact_service.dart'; import 'package:xworkmate/runtime/runtime_models.dart'; void main() { test( - 'loadSnapshot exposes all local workspace files when current run has no artifacts', + 'loadSnapshot hides historical workspace files when current run has no artifacts', () async { final workspace = await Directory.systemTemp.createTemp( 'xworkmate-artifact-snapshot-', @@ -25,10 +26,7 @@ void main() { ); expect(snapshot.resultEntries, isEmpty); - expect( - snapshot.fileEntries.map((entry) => entry.relativePath), - contains('historical.md'), - ); + expect(snapshot.fileEntries, isEmpty); expect( snapshot.resultMessage, 'No task artifacts recorded for this run.', @@ -80,13 +78,14 @@ void main() { } }); await File('${workspace.path}/historical.md').writeAsString('# Old\n'); - final snapshot = await DesktopThreadArtifactService().loadSnapshot( - workspacePath: workspace.path, - workspaceKind: WorkspaceRefKind.localPath, - artifactRelativePaths: const [], - ); - final historical = snapshot.fileEntries.singleWhere( - (entry) => entry.relativePath == 'historical.md', + const historical = AssistantArtifactEntry( + id: 'historical.md', + label: 'historical.md', + relativePath: 'historical.md', + kind: AssistantArtifactEntryKind.file, + mimeType: 'text/markdown', + previewable: true, + workspacePath: '', ); final preview = await DesktopThreadArtifactService().loadPreview(