From 0f3196f305d6d91e6cbc21fed1e493dbccf5e5df Mon Sep 17 00:00:00 2001 From: lpf Date: Wed, 4 Mar 2026 15:15:19 +0800 Subject: [PATCH] feat(scheduling): improve natural-language resource key inference for session parallelism --- pkg/scheduling/resource_keys.go | 38 +++++++++++++++++++++++++--- pkg/scheduling/resource_keys_test.go | 32 +++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/pkg/scheduling/resource_keys.go b/pkg/scheduling/resource_keys.go index 0bb294f..6eb66bf 100644 --- a/pkg/scheduling/resource_keys.go +++ b/pkg/scheduling/resource_keys.go @@ -24,7 +24,6 @@ func DeriveResourceKeys(content string) []string { lower := strings.ToLower(raw) keys := make([]string, 0, 8) - hasRepo := false for _, token := range strings.Fields(lower) { t := strings.Trim(token, "`'\"()[]{}:;,,。!?") if t == "" { @@ -33,7 +32,6 @@ func DeriveResourceKeys(content string) []string { if strings.Contains(t, "gitea.") || strings.Contains(t, "github.com") || strings.Count(t, "/") >= 1 { if strings.Contains(t, "github.com/") || strings.Contains(t, "gitea.") { keys = append(keys, "repo:"+t) - hasRepo = true } } if strings.Contains(t, "/") || strings.HasSuffix(t, ".go") || strings.HasSuffix(t, ".md") || strings.HasSuffix(t, ".json") || strings.HasSuffix(t, ".yaml") || strings.HasSuffix(t, ".yml") { @@ -43,8 +41,8 @@ func DeriveResourceKeys(content string) []string { keys = append(keys, "branch:"+strings.TrimPrefix(t, "branch:")) } } - if !hasRepo { - keys = append(keys, "repo:default") + for _, topic := range deriveTopicKeys(lower) { + keys = append(keys, topic) } if len(keys) == 0 { keys = append(keys, "scope:general") @@ -52,6 +50,38 @@ func DeriveResourceKeys(content string) []string { return NormalizeResourceKeys(keys) } +func deriveTopicKeys(lower string) []string { + if strings.TrimSpace(lower) == "" { + return nil + } + type topicRule struct { + name string + keywords []string + } + rules := []topicRule{ + {name: "webui", keywords: []string{"webui", "ui", "frontend", "前端", "页面", "界面"}}, + {name: "docs", keywords: []string{"readme", "doc", "docs", "文档", "说明"}}, + {name: "release", keywords: []string{"release", "tag", "version", "版本", "发版", "打版本"}}, + {name: "git", keywords: []string{"git", "branch", "commit", "push", "merge", "分支", "提交", "推送"}}, + {name: "config", keywords: []string{"config", "配置", "参数"}}, + {name: "test", keywords: []string{"test", "tests", "testing", "测试", "回归"}}, + {name: "task", keywords: []string{"task", "tasks", "任务", "调度", "并发"}}, + {name: "memory", keywords: []string{"memory", "记忆"}}, + {name: "cron", keywords: []string{"cron", "schedule", "scheduled", "定时", "定时任务"}}, + {name: "log", keywords: []string{"log", "logs", "日志"}}, + } + out := make([]string, 0, 3) + for _, r := range rules { + for _, kw := range r.keywords { + if strings.Contains(lower, kw) { + out = append(out, "topic:"+r.name) + break + } + } + } + return out +} + // ParseExplicitResourceKeys parses directive-style keys from content. func ParseExplicitResourceKeys(content string) []string { raw := strings.TrimSpace(content) diff --git a/pkg/scheduling/resource_keys_test.go b/pkg/scheduling/resource_keys_test.go index 1e516b5..59705b0 100644 --- a/pkg/scheduling/resource_keys_test.go +++ b/pkg/scheduling/resource_keys_test.go @@ -36,6 +36,38 @@ func TestDeriveResourceKeysHeuristic(t *testing.T) { if !foundBranch { t.Fatalf("expected branch key in %#v", keys) } + for _, k := range keys { + if k == "repo:default" { + t.Fatalf("should not include global repo:default key in %#v", keys) + } + } +} + +func TestDeriveResourceKeysNaturalLanguageTopic(t *testing.T) { + keys := DeriveResourceKeys("请更新webui交互并补充readme文档") + if len(keys) == 0 { + t.Fatalf("expected non-empty keys") + } + foundWebUI := false + foundDocs := false + for _, k := range keys { + if k == "topic:webui" { + foundWebUI = true + } + if k == "topic:docs" { + foundDocs = true + } + } + if !foundWebUI || !foundDocs { + t.Fatalf("expected topic keys in %#v", keys) + } +} + +func TestDeriveResourceKeysNaturalLanguageFallbackGeneral(t *testing.T) { + keys := DeriveResourceKeys("帮我处理一下") + if len(keys) != 1 || keys[0] != "scope:general" { + t.Fatalf("expected scope:general fallback, got %#v", keys) + } } func TestParseResourceKeyListAddsFilePrefix(t *testing.T) {