From 3c7de420d2f30731c390dcd6838c99fbf74f9b22 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Sat, 27 Jun 2026 06:31:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(acp):=20S1=20=E2=80=94=20default=20expected?= =?UTF-8?q?ArtifactDirs=20so=20plugin=20root-fallback=20collects=20artifac?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live verification (docs/cases/06 §7 S1) showed the session mapping recorded expectedArtifactDirs:[] for an md-producing task. openclaw-multi-session-plugins only scans the workspace-root deliverable dirs (reports/, artifacts/, ...) when expectedArtifactDirs is non-empty; empty → the root fallback is inert, so an agent that writes news.md to the workspace root (the common case) yields "no files". openClawArtifactContractForParams now defaults expectedArtifactDirs to reports//artifacts//exports/ when the task expects artifacts (requiresExport or inferred requiredExts) but declared no dirs, and marks requiresExport so the export path runs. Pure-chat turns (no artifact intent) are unaffected. Test: orchestrator_s1_artifact_dirs_test.go (md task gets dirs+export; chat gets neither). Co-Authored-By: Claude Opus 4.8 --- internal/acp/orchestrator.go | 14 ++++++++++++++ .../acp/orchestrator_s1_artifact_dirs_test.go | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 internal/acp/orchestrator_s1_artifact_dirs_test.go diff --git a/internal/acp/orchestrator.go b/internal/acp/orchestrator.go index dbfbbfa..3f4ed0d 100644 --- a/internal/acp/orchestrator.go +++ b/internal/acp/orchestrator.go @@ -850,6 +850,12 @@ type openClawArtifactContract struct { SourceMessage string } +// defaultOpenClawExpectedArtifactDirs 是 agent 最常用的产物落盘目录。当任务期望产物却没有 +// 显式声明目录时,用作 openclaw-multi-session-plugins 的 workspace 根兜底扫描范围(S1)。 +func defaultOpenClawExpectedArtifactDirs() []string { + return []string{"reports/", "artifacts/", "exports/"} +} + func openClawArtifactContractForParams(params map[string]any, chatParams map[string]any) openClawArtifactContract { metadata := shared.AsMap(params["metadata"]) taskLoadClass := strings.TrimSpace(shared.StringArg(metadata, "taskLoadClass", "")) @@ -869,6 +875,14 @@ func openClawArtifactContractForParams(params map[string]any, chatParams map[str if len(requiredExts) == 0 { requiredExts = inferOpenClawRequiredArtifactExts(lowerMessage) } + // S1(docs/cases/06 §7):任务期望产物(需导出 或 已推断出 requiredExts)却没有显式声明 + // expectedArtifactDirs 时,补一组缺省目录。openclaw-multi-session-plugins 在 task scope + // 目录为空时会回扫 workspace 根的 expectedArtifactDirs;该列表为空则兜底形同虚设, + // agent 写到 workspace 根(reports//artifacts//exports/)的产物就再也收不回(表现「暂无文件」)。 + if len(expectedDirs) == 0 && (requiresExport || len(requiredExts) > 0) { + expectedDirs = defaultOpenClawExpectedArtifactDirs() + requiresExport = true + } expectedFileCounts := normalizeOpenClawArtifactExtCountMap(shared.AsMap(contract["expectedFileCountByExtension"])) if len(expectedFileCounts) == 0 { expectedFileCounts = normalizeOpenClawArtifactExtCountMap(shared.AsMap(metadata["expectedFileCountByExtension"])) diff --git a/internal/acp/orchestrator_s1_artifact_dirs_test.go b/internal/acp/orchestrator_s1_artifact_dirs_test.go new file mode 100644 index 0000000..29e98b3 --- /dev/null +++ b/internal/acp/orchestrator_s1_artifact_dirs_test.go @@ -0,0 +1,19 @@ +package acp +import "testing" +func TestS1DefaultExpectedArtifactDirs(t *testing.T) { + // 任务消息要求产出 md → 推断 requiredExts,但未声明 expectedArtifactDirs → 应补缺省目录 + c := openClawArtifactContractForParams( + map[string]any{}, map[string]any{"message": "采集最新AI资讯,保存在md文件"}) + if len(c.ExpectedArtifactDirs) == 0 { + t.Fatalf("expected default artifact dirs for an md-producing task, got none") + } + if !c.RequiresArtifactExport { + t.Fatalf("expected RequiresArtifactExport=true when default dirs applied") + } + // 纯聊天(无产物意图)→ 不应补目录、不应强制导出 + c2 := openClawArtifactContractForParams( + map[string]any{}, map[string]any{"message": "你好,介绍一下你自己"}) + if len(c2.ExpectedArtifactDirs) != 0 || c2.RequiresArtifactExport { + t.Fatalf("pure chat should not get default dirs / forced export, got dirs=%v export=%v", c2.ExpectedArtifactDirs, c2.RequiresArtifactExport) + } +}