use crate::context_bundle::ContextIntent;
use super::domain::{IntentSource, ResolvedIntent};
pub(super) const REASON_EXPLICIT_INTENT: &str = "explicit_intent";
pub(super) const REASON_KEYWORD_MATCH_PREFIX: &str = "keyword_match_";
pub(super) const REASON_UNCLASSIFIED_FALLBACK: &str = "unclassified_conservative_fallback";
const KEYWORD_RULES: [(ContextIntent, &str, &[&str]); 5] = [
(
ContextIntent::DebugFailure,
"debug_failure",
&[
"debug",
"error",
"panic",
"stack trace",
"traceback",
"regression",
"broken",
"failing",
"flaky",
"报错",
"崩溃",
"调试",
"排查",
],
),
(
ContextIntent::ExplainDecision,
"explain_decision",
&[
"why",
"decision",
"decided",
"rationale",
"trade-off",
"tradeoff",
"chose",
"为什么",
"决定",
"决策",
],
),
(
ContextIntent::ReviewChange,
"review_change",
&[
"review",
"pull request",
" pr ",
"diff",
"merge this",
"审查",
"评审",
],
),
(
ContextIntent::ResumeWork,
"resume_work",
&[
"resume",
"continue",
"pick up where",
"where were we",
"last session",
"next step",
"继续",
"上次",
"接着",
],
),
(
ContextIntent::ApplyPreference,
"apply_preference",
&[
"preference",
"convention",
"coding style",
"style guide",
"formatting rule",
"偏好",
"规范",
"习惯",
],
),
];
pub fn resolve_intent(explicit: Option<ContextIntent>, task: &str) -> ResolvedIntent {
match explicit {
Some(intent) => ResolvedIntent {
intent,
source: IntentSource::Explicit,
reason_code: REASON_EXPLICIT_INTENT.to_string(),
},
None => resolve_from_keywords(task),
}
}
fn resolve_from_keywords(task: &str) -> ResolvedIntent {
let haystack = format!(" {} ", task.to_lowercase());
for (intent, code, keywords) in KEYWORD_RULES {
if keywords.iter().any(|kw| haystack.contains(kw)) {
return ResolvedIntent {
intent,
source: IntentSource::KeywordFallback,
reason_code: format!("{REASON_KEYWORD_MATCH_PREFIX}{code}"),
};
}
}
ResolvedIntent {
intent: ContextIntent::ExploreHistory,
source: IntentSource::DefaultFallback,
reason_code: REASON_UNCLASSIFIED_FALLBACK.to_string(),
}
}