refactor(llm): 拆分提示词与提交解析逻辑到独立模块
将 21 个多语言提示词及选择函数迁入 prompts 模块,将 commit 响应 解析与 GeneratedCommit 迁入 parsing 模块,为 rig 迁移期间新旧 实现共享同一份提示词与解析逻辑做准备。无行为变化。
This commit is contained in:
908
src/llm/mod.rs
908
src/llm/mod.rs
@@ -9,6 +9,8 @@ pub mod kimi;
|
||||
pub mod ollama;
|
||||
pub mod openai;
|
||||
pub mod openrouter;
|
||||
pub mod parsing;
|
||||
pub mod prompts;
|
||||
pub mod thinking;
|
||||
|
||||
pub use anthropic::AnthropicClient;
|
||||
@@ -17,6 +19,7 @@ pub use kimi::KimiClient;
|
||||
pub use ollama::OllamaClient;
|
||||
pub use openai::OpenAiClient;
|
||||
pub use openrouter::OpenRouterClient;
|
||||
pub use parsing::GeneratedCommit;
|
||||
|
||||
/// LLM provider trait
|
||||
#[async_trait]
|
||||
@@ -203,7 +206,7 @@ impl LlmClient {
|
||||
language: Language,
|
||||
template: Option<&str>,
|
||||
) -> Result<GeneratedCommit> {
|
||||
let mut system_prompt = get_commit_system_prompt(format, language).to_string();
|
||||
let mut system_prompt = prompts::get_commit_system_prompt(format, language).to_string();
|
||||
|
||||
if let Some(tmpl) = template {
|
||||
system_prompt.push_str(&format!(
|
||||
@@ -229,7 +232,7 @@ impl LlmClient {
|
||||
.generate_with_system(&system_prompt, &prompt)
|
||||
.await?;
|
||||
|
||||
self.parse_commit_response(&response, format)
|
||||
parsing::parse_commit_response(&response, format)
|
||||
}
|
||||
|
||||
/// Generate tag message from commits
|
||||
@@ -239,7 +242,7 @@ impl LlmClient {
|
||||
commits: &[String],
|
||||
language: Language,
|
||||
) -> Result<String> {
|
||||
let system_prompt = get_tag_system_prompt(language);
|
||||
let system_prompt = prompts::get_tag_system_prompt(language);
|
||||
let commits_text = commits.join("\n");
|
||||
|
||||
// Add language instruction to the prompt
|
||||
@@ -270,7 +273,7 @@ impl LlmClient {
|
||||
commits: &[(String, String)], // (type, message)
|
||||
language: Language,
|
||||
) -> Result<String> {
|
||||
let system_prompt = get_changelog_system_prompt(language);
|
||||
let system_prompt = prompts::get_changelog_system_prompt(language);
|
||||
|
||||
let commits_text = commits
|
||||
.iter()
|
||||
@@ -304,289 +307,8 @@ impl LlmClient {
|
||||
self.provider.is_available().await
|
||||
}
|
||||
|
||||
/// Parse commit response from LLM
|
||||
fn parse_commit_response(
|
||||
&self,
|
||||
response: &str,
|
||||
format: crate::config::CommitFormat,
|
||||
) -> Result<GeneratedCommit> {
|
||||
// Clean markdown code fences from the response
|
||||
let cleaned = Self::strip_code_fences(response);
|
||||
|
||||
let lines: Vec<&str> = cleaned
|
||||
.lines()
|
||||
.map(|l| l.trim())
|
||||
.filter(|l| !l.is_empty())
|
||||
.collect();
|
||||
|
||||
if lines.is_empty() {
|
||||
let preview: String = response.chars().take(200).collect();
|
||||
bail!(
|
||||
"LLM returned empty or whitespace-only response. \
|
||||
Raw response preview: '{}'. \
|
||||
Hint: If using DeepSeek/Kimi with thinking enabled, \
|
||||
the model may have returned reasoning_content only. \
|
||||
Try disabling thinking mode or switching models.",
|
||||
preview
|
||||
);
|
||||
}
|
||||
|
||||
// Find the line most likely to be the commit subject
|
||||
let first_line = Self::find_commit_subject_line(&lines, format);
|
||||
|
||||
// Parse based on format
|
||||
match format {
|
||||
crate::config::CommitFormat::Conventional => {
|
||||
self.parse_conventional_commit(first_line, &lines, response)
|
||||
}
|
||||
crate::config::CommitFormat::Commitlint => {
|
||||
self.parse_commitlint_commit(first_line, &lines, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove surrounding markdown code fences (```) from LLM output
|
||||
fn strip_code_fences(response: &str) -> String {
|
||||
let mut lines: Vec<&str> = response.lines().collect();
|
||||
|
||||
// Strip leading fence lines (``` or ```lang)
|
||||
while lines.first().map_or(false, |l| l.trim().starts_with("```")) {
|
||||
lines.remove(0);
|
||||
}
|
||||
|
||||
// Strip trailing fence lines
|
||||
while lines.last().map_or(false, |l| l.trim() == "```") {
|
||||
lines.pop();
|
||||
}
|
||||
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
/// Find the line that is most likely the commit subject among extracted lines
|
||||
fn find_commit_subject_line<'a>(
|
||||
lines: &[&'a str],
|
||||
format: crate::config::CommitFormat,
|
||||
) -> &'a str {
|
||||
let valid_types = crate::utils::validators::get_commit_types(matches!(
|
||||
format,
|
||||
crate::config::CommitFormat::Commitlint
|
||||
));
|
||||
|
||||
// First pass: line starting with a known type that also has proper syntax
|
||||
// (e.g. "type:", "type(scope):", "type!:")
|
||||
for &line in lines {
|
||||
let trimmed = line.trim();
|
||||
for &t in valid_types {
|
||||
if let Some(rest) = trimmed.strip_prefix(t) {
|
||||
if rest.starts_with(':') || rest.starts_with('(') || rest.starts_with("!:") {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: any line containing a colon (generic "prefix: description")
|
||||
for &line in lines {
|
||||
if line.contains(':') {
|
||||
return line.trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: return the first line as-is
|
||||
lines[0].trim()
|
||||
}
|
||||
|
||||
fn parse_conventional_commit(
|
||||
&self,
|
||||
first_line: &str,
|
||||
lines: &[&str],
|
||||
raw_response: &str,
|
||||
) -> Result<GeneratedCommit> {
|
||||
// Parse: type(scope)!: description
|
||||
let parts: Vec<&str> = first_line.splitn(2, ':').collect();
|
||||
if parts.len() != 2 {
|
||||
let preview: String = raw_response.chars().take(300).collect();
|
||||
bail!(
|
||||
"Invalid conventional commit format: missing colon.\n\
|
||||
Parsed subject line: '{}'\n\
|
||||
Raw response preview: '{}'\n\
|
||||
Expected: <type>[optional scope]: <description>",
|
||||
first_line,
|
||||
preview
|
||||
);
|
||||
}
|
||||
|
||||
let type_part = parts[0];
|
||||
let description = parts[1].trim();
|
||||
|
||||
// Extract type, scope, and breaking indicator
|
||||
let breaking = type_part.ends_with('!');
|
||||
let type_part = type_part.trim_end_matches('!');
|
||||
|
||||
let (commit_type, scope) = if let Some(start) = type_part.find('(') {
|
||||
if let Some(end) = type_part.find(')') {
|
||||
let t = &type_part[..start];
|
||||
let s = &type_part[start + 1..end];
|
||||
(t.to_string(), Some(s.to_string()))
|
||||
} else {
|
||||
bail!("Invalid scope format: missing closing parenthesis");
|
||||
}
|
||||
} else {
|
||||
(type_part.to_string(), None)
|
||||
};
|
||||
|
||||
// Extract body and footer
|
||||
let (body, footer) = self.extract_body_footer(lines);
|
||||
|
||||
Ok(GeneratedCommit {
|
||||
commit_type,
|
||||
scope,
|
||||
description: description.to_string(),
|
||||
body,
|
||||
footer,
|
||||
breaking,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_commitlint_commit(
|
||||
&self,
|
||||
first_line: &str,
|
||||
lines: &[&str],
|
||||
raw_response: &str,
|
||||
) -> Result<GeneratedCommit> {
|
||||
// Similar parsing but with commitlint rules
|
||||
let parts: Vec<&str> = first_line.splitn(2, ':').collect();
|
||||
if parts.len() != 2 {
|
||||
let preview: String = raw_response.chars().take(300).collect();
|
||||
bail!(
|
||||
"Invalid commit format: missing colon.\n\
|
||||
Parsed subject line: '{}'\n\
|
||||
Raw response preview: '{}'\n\
|
||||
Expected: <type>[optional scope]: <subject>",
|
||||
first_line,
|
||||
preview
|
||||
);
|
||||
}
|
||||
|
||||
let type_part = parts[0];
|
||||
let subject = parts[1].trim();
|
||||
|
||||
let (commit_type, scope) = if let Some(start) = type_part.find('(') {
|
||||
if let Some(end) = type_part.find(')') {
|
||||
let t = &type_part[..start];
|
||||
let s = &type_part[start + 1..end];
|
||||
(t.to_string(), Some(s.to_string()))
|
||||
} else {
|
||||
(type_part.to_string(), None)
|
||||
}
|
||||
} else {
|
||||
(type_part.to_string(), None)
|
||||
};
|
||||
|
||||
let (body, footer) = self.extract_body_footer(&lines);
|
||||
|
||||
Ok(GeneratedCommit {
|
||||
commit_type,
|
||||
scope,
|
||||
description: subject.to_string(),
|
||||
body,
|
||||
footer,
|
||||
breaking: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_body_footer(&self, lines: &[&str]) -> (Option<String>, Option<String>) {
|
||||
if lines.len() <= 1 {
|
||||
return (None, None);
|
||||
}
|
||||
|
||||
let rest: Vec<&str> = lines[1..]
|
||||
.iter()
|
||||
.skip_while(|l| l.trim().is_empty())
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
if rest.is_empty() {
|
||||
return (None, None);
|
||||
}
|
||||
|
||||
// Look for footer markers
|
||||
let footer_markers = [
|
||||
"BREAKING CHANGE:",
|
||||
"Closes",
|
||||
"Fixes",
|
||||
"Refs",
|
||||
"Co-authored-by:",
|
||||
];
|
||||
|
||||
let mut body_lines = vec![];
|
||||
let mut footer_lines = vec![];
|
||||
let mut in_footer = false;
|
||||
|
||||
for line in &rest {
|
||||
if footer_markers.iter().any(|m| line.starts_with(m)) {
|
||||
in_footer = true;
|
||||
}
|
||||
|
||||
if in_footer {
|
||||
footer_lines.push(*line);
|
||||
} else {
|
||||
body_lines.push(*line);
|
||||
}
|
||||
}
|
||||
|
||||
let body = if body_lines.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(body_lines.join("\n"))
|
||||
};
|
||||
|
||||
let footer = if footer_lines.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(footer_lines.join("\n"))
|
||||
};
|
||||
|
||||
(body, footer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generated commit structure
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GeneratedCommit {
|
||||
pub commit_type: String,
|
||||
pub scope: Option<String>,
|
||||
pub description: String,
|
||||
pub body: Option<String>,
|
||||
pub footer: Option<String>,
|
||||
pub breaking: bool,
|
||||
}
|
||||
|
||||
impl GeneratedCommit {
|
||||
/// Format as conventional commit
|
||||
pub fn to_conventional(&self) -> String {
|
||||
crate::utils::formatter::format_conventional_commit(
|
||||
&self.commit_type,
|
||||
self.scope.as_deref(),
|
||||
&self.description,
|
||||
self.body.as_deref(),
|
||||
self.footer.as_deref(),
|
||||
self.breaking,
|
||||
)
|
||||
}
|
||||
|
||||
/// Format as commitlint commit
|
||||
pub fn to_commitlint(&self) -> String {
|
||||
crate::utils::formatter::format_commitlint_commit(
|
||||
&self.commit_type,
|
||||
self.scope.as_deref(),
|
||||
&self.description,
|
||||
self.body.as_deref(),
|
||||
self.footer.as_deref(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// HTTP client helper
|
||||
pub(crate) fn create_http_client(timeout: Duration) -> Result<reqwest::Client> {
|
||||
@@ -596,622 +318,6 @@ pub(crate) fn create_http_client(timeout: Duration) -> Result<reqwest::Client> {
|
||||
.context("Failed to create HTTP client")
|
||||
}
|
||||
|
||||
/// Get commit system prompt based on format and language
|
||||
fn get_commit_system_prompt(
|
||||
format: crate::config::CommitFormat,
|
||||
language: Language,
|
||||
) -> &'static str {
|
||||
match (format, language) {
|
||||
(crate::config::CommitFormat::Conventional, Language::Chinese) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ZH
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::Japanese) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_JA
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::Korean) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_KO
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::Spanish) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ES
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::French) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_FR
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::German) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_DE
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, _) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT,
|
||||
(crate::config::CommitFormat::Commitlint, Language::Chinese) => COMMITLINT_SYSTEM_PROMPT_ZH,
|
||||
(crate::config::CommitFormat::Commitlint, Language::Japanese) => {
|
||||
COMMITLINT_SYSTEM_PROMPT_JA
|
||||
}
|
||||
(crate::config::CommitFormat::Commitlint, Language::Korean) => COMMITLINT_SYSTEM_PROMPT_KO,
|
||||
(crate::config::CommitFormat::Commitlint, Language::Spanish) => COMMITLINT_SYSTEM_PROMPT_ES,
|
||||
(crate::config::CommitFormat::Commitlint, Language::French) => COMMITLINT_SYSTEM_PROMPT_FR,
|
||||
(crate::config::CommitFormat::Commitlint, Language::German) => COMMITLINT_SYSTEM_PROMPT_DE,
|
||||
(crate::config::CommitFormat::Commitlint, _) => COMMITLINT_SYSTEM_PROMPT,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_tag_system_prompt(language: Language) -> &'static str {
|
||||
match language {
|
||||
Language::Chinese => TAG_MESSAGE_SYSTEM_PROMPT_ZH,
|
||||
Language::Japanese => TAG_MESSAGE_SYSTEM_PROMPT_JA,
|
||||
Language::Korean => TAG_MESSAGE_SYSTEM_PROMPT_KO,
|
||||
Language::Spanish => TAG_MESSAGE_SYSTEM_PROMPT_ES,
|
||||
Language::French => TAG_MESSAGE_SYSTEM_PROMPT_FR,
|
||||
Language::German => TAG_MESSAGE_SYSTEM_PROMPT_DE,
|
||||
_ => TAG_MESSAGE_SYSTEM_PROMPT,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_changelog_system_prompt(language: Language) -> &'static str {
|
||||
match language {
|
||||
Language::Chinese => CHANGELOG_SYSTEM_PROMPT_ZH,
|
||||
Language::Japanese => CHANGELOG_SYSTEM_PROMPT_JA,
|
||||
Language::Korean => CHANGELOG_SYSTEM_PROMPT_KO,
|
||||
Language::Spanish => CHANGELOG_SYSTEM_PROMPT_ES,
|
||||
Language::French => CHANGELOG_SYSTEM_PROMPT_FR,
|
||||
Language::German => CHANGELOG_SYSTEM_PROMPT_DE,
|
||||
_ => CHANGELOG_SYSTEM_PROMPT,
|
||||
}
|
||||
}
|
||||
|
||||
// System prompts for LLM
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates conventional commit messages.
|
||||
|
||||
Analyze the git diff provided and generate a commit message following the Conventional Commits specification.
|
||||
|
||||
Format: <type>[optional scope]: <description>
|
||||
|
||||
Types:
|
||||
- feat: A new feature
|
||||
- fix: A bug fix
|
||||
- docs: Documentation only changes
|
||||
- style: Changes that don't affect code meaning (formatting, semicolons, etc.)
|
||||
- refactor: Code change that neither fixes a bug nor adds a feature
|
||||
- perf: Code change that improves performance
|
||||
- test: Adding or correcting tests
|
||||
- build: Changes to build system or dependencies
|
||||
- ci: Changes to CI configuration
|
||||
- chore: Other changes that don't modify src or test files
|
||||
- revert: Reverts a previous commit
|
||||
|
||||
Rules:
|
||||
1. Use lowercase for type and scope
|
||||
2. Keep description under 100 characters
|
||||
3. Use imperative mood ("add" not "added")
|
||||
4. Don't capitalize first letter
|
||||
5. No period at the end
|
||||
6. Include scope if the change is specific to a module/component
|
||||
|
||||
Output ONLY the commit message, nothing else.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成符合 Conventional Commits 规范的提交消息的助手。
|
||||
|
||||
分析提供的 git diff,并生成符合 Conventional Commits 规范的提交消息。
|
||||
|
||||
格式: <type>[可选作用域]: <描述>
|
||||
|
||||
类型:
|
||||
- feat: 新功能
|
||||
- fix: 修复错误
|
||||
- docs: 仅文档更改
|
||||
- style: 不影响代码含义的更改(格式化、分号等)
|
||||
- refactor: 既不修复错误也不添加功能的代码更改
|
||||
- perf: 提高性能的代码更改
|
||||
- test: 添加或更正测试
|
||||
- build: 更改构建系统或依赖项
|
||||
- ci: 更改 CI 配置
|
||||
- chore: 其他不修改 src 或测试文件的更改
|
||||
- revert: 撤销之前的提交
|
||||
|
||||
规则:
|
||||
1. 类型和小写使用小写
|
||||
2. 描述保持在 100 个字符以内
|
||||
3. 使用祈使语气("添加"而不是"已添加")
|
||||
4. 不要大写首字母
|
||||
5. 结尾不要句号
|
||||
6. 如果更改特定于模块/组件,请包含作用域
|
||||
7. 仅输出提交消息,不要输出其他内容。
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_JA: &str = r#"あなたはConventional Commits仕様に従ったコミットメッセージを生成するアシスタントです。
|
||||
|
||||
提供されたgit diffを分析し、Conventional Commits仕様に従ったコミットメッセージを生成してください。
|
||||
|
||||
形式: <type>[オプションのスコープ]: <説明>
|
||||
|
||||
タイプ:
|
||||
- feat: 新機能
|
||||
- fix: バグ修正
|
||||
- docs: ドキュメントのみの変更
|
||||
- style: コードの意味に影響しない変更(フォーマット、セミコロンなど)
|
||||
- refactor: バグ修正や機能追加を伴わないコード変更
|
||||
- perf: パフォーマンスを向上させるコード変更
|
||||
- test: テストの追加または修正
|
||||
- build: ビルドシステムまたは依存関係の変更
|
||||
- ci: CI設定の変更
|
||||
- chore: srcやテストファイルを変更しないその他の変更
|
||||
- revert: 以前のコミットを取り消す
|
||||
|
||||
ルール:
|
||||
1. タイプとスコープは小文字を使用
|
||||
2. 説明は100文字以内にする
|
||||
3. 命令形を使用する("追加"ではなく"追加する")
|
||||
4. 先頭を大文字にしない
|
||||
5. 最後にピリオドを付けない
|
||||
6. 変更がモジュール/コンポーネントに固有の場合はスコープを含める
|
||||
7. コミットメッセージのみを出力し、それ以外は出力しないでください。
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_KO: &str = r#"당신은 Conventional Commits 사양에 따른 커밋 메시지를 생성하는 도우미입니다.
|
||||
|
||||
제공된 git diff를 분석하고 Conventional Commits 사양에 따른 커밋 메시지를 생성하세요.
|
||||
|
||||
형식: <type>[선택적 범위]: <설명>
|
||||
|
||||
유형:
|
||||
- feat: 새 기능
|
||||
- fix: 버그 수정
|
||||
- docs: 문서 변경만
|
||||
- style: 코드 의미에 영향을 주지 않는 변경(서식, 세미콜론 등)
|
||||
- refactor: 버그를 수정하거나 기능을 추가하지 않는 코드 변경
|
||||
- perf: 성능을 향상시키는 코드 변경
|
||||
- test: 테스트 추가 또는 수정
|
||||
- build: 빌드 시스템 또는 종속성 변경
|
||||
- ci: CI 구성 변경
|
||||
- chore: src 또는 테스트 파일을 수정하지 않는 기타 변경
|
||||
- revert: 이전 커밋 되돌리기
|
||||
|
||||
규칙:
|
||||
1. 유형과 범위는 소문자 사용
|
||||
2. 설명은 100자 이내로 유지
|
||||
3. 명령형 사용("추가"가 아닌 "추가하다")
|
||||
4. 첫 글자 대문자화하지 않음
|
||||
5. 끝에 마침표 사용하지 않음
|
||||
6. 변경 사항이 모듈/구성 요소에 특정한 경우 범위 포함
|
||||
7. 커밋 메시지만 출력하고 다른 내용은 출력하지 마세요.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de commit siguiendo la especificación Conventional Commits.
|
||||
|
||||
Analiza el diff de git proporcionado y genera un mensaje de commit siguiendo la especificación Conventional Commits.
|
||||
|
||||
Formato: <tipo>[alcance opcional]: <descripción>
|
||||
|
||||
Tipos:
|
||||
- feat: Una nueva característica
|
||||
- fix: Una corrección de error
|
||||
- docs: Solo cambios en documentación
|
||||
- style: Cambios que no afectan el significado del código (formato, punto y coma, etc.)
|
||||
- refactor: Cambio de código que no corrige un error ni agrega una característica
|
||||
- perf: Cambio de código que mejora el rendimiento
|
||||
- test: Agregar o corregir pruebas
|
||||
- build: Cambios en el sistema de construcción o dependencias
|
||||
- ci: Cambios en la configuración de CI
|
||||
- chore: Otros cambios que no modifican archivos src o de prueba
|
||||
- revert: Revierte un commit anterior
|
||||
|
||||
Reglas:
|
||||
1. Usa minúsculas para tipo y alcance
|
||||
2. Mantén la descripción bajo 100 caracteres
|
||||
3. Usa modo imperativo ("agregar" no "agregado")
|
||||
4. No capitalices la primera letra
|
||||
5. Sin punto al final
|
||||
6. Incluye alcance si el cambio es específico de un módulo/componente
|
||||
7. Genera SOLO el mensaje de commit, nada más.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages de commit suivant la spécification Conventional Commits.
|
||||
|
||||
Analysez le diff git fourni et générez un message de commit suivant la spécification Conventional Commits.
|
||||
|
||||
Format: <type>[portée optionnelle]: <description>
|
||||
|
||||
Types:
|
||||
- feat: Une nouvelle fonctionnalité
|
||||
- fix: Une correction de bug
|
||||
- docs: Changements de documentation uniquement
|
||||
- style: Changements qui n'affectent pas la signification du code (formatage, points-virgules, etc.)
|
||||
- refactor: Changement de code qui ne corrige pas un bug ni n'ajoute une fonctionnalité
|
||||
- perf: Changement de code qui améliore les performances
|
||||
- test: Ajout ou correction de tests
|
||||
- build: Changements du système de build ou des dépendances
|
||||
- ci: Changements de la configuration CI
|
||||
- chore: Autres changements qui ne modifient pas les fichiers src ou de test
|
||||
- revert: Révertit un commit précédent
|
||||
|
||||
Règles:
|
||||
1. Utilisez des minuscules pour le type et la portée
|
||||
2. Gardez la description sous 100 caractères
|
||||
3. Utilisez le mode impératif ("ajouter" non "ajouté")
|
||||
4. Ne capitalisez pas la première lettre
|
||||
5. Pas de point à la fin
|
||||
6. Incluez la portée si le changement est spécifique à un module/composant
|
||||
7. Générez SEULEMENT le message de commit, rien d'autre.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Commit-Nachrichten gemäß der Conventional Commits-Spezifikation generiert.
|
||||
|
||||
Analysieren Sie den bereitgestellten git diff und generieren Sie eine Commit-Nachricht gemäß der Conventional Commits-Spezifikation.
|
||||
|
||||
Format: <typ>[optionaler Bereich]: <beschreibung>
|
||||
|
||||
Typen:
|
||||
- feat: Eine neue Funktion
|
||||
- fix: Ein Bugfix
|
||||
- docs: Nur Dokumentationsänderungen
|
||||
- style: Änderungen, die die Code-Bedeutung nicht beeinflussen (Formatierung, Semikolons usw.)
|
||||
- refactor: Code-Änderung, die weder einen Bug behebt noch eine Funktion hinzufügt
|
||||
- perf: Code-Änderung, die die Leistung verbessert
|
||||
- test: Hinzufügen oder Korrigieren von Tests
|
||||
- build: Änderungen am Build-System oder Abhängigkeiten
|
||||
- ci: Änderungen an der CI-Konfiguration
|
||||
- chore: Andere Änderungen, die src- oder Testdateien nicht ändern
|
||||
- revert: Setzt einen vorherigen Commit zurück
|
||||
|
||||
Regeln:
|
||||
1. Verwenden Sie Kleinbuchstaben für Typ und Bereich
|
||||
2. Halten Sie die Beschreibung unter 100 Zeichen
|
||||
3. Verwenden Sie den Imperativ ("hinzufügen" nicht "hinzugefügt")
|
||||
4. Großschreiben Sie den ersten Buchstaben nicht
|
||||
5. Kein Punkt am Ende
|
||||
6. Fügen Sie einen Bereich ein, wenn die Änderung spezifisch für ein Modul/Komponente ist
|
||||
7. Geben Sie NUR die Commit-Nachricht aus, nichts anderes.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates commit messages following @commitlint/config-conventional.
|
||||
|
||||
Analyze the git diff and generate a commit message.
|
||||
|
||||
Format: <type>[optional scope]: <subject>
|
||||
|
||||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Rules:
|
||||
1. Subject should not start with uppercase
|
||||
2. Subject should not end with period
|
||||
3. Subject should be 4-100 characters
|
||||
4. Use imperative mood
|
||||
5. Be concise but descriptive
|
||||
6. Output ONLY the commit message, nothing else.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成符合 @commitlint/config-conventional 规范的提交消息的助手。
|
||||
|
||||
分析 git diff 并生成提交消息。
|
||||
|
||||
格式: <type>[可选作用域]: <主题>
|
||||
|
||||
类型: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
规则:
|
||||
1. 主题不应以大写字母开头
|
||||
2. 主题不应以句号结尾
|
||||
3. 主题应为 4-100 个字符
|
||||
4. 使用祈使语气
|
||||
5. 简洁但描述性强
|
||||
6. 仅输出提交消息,不要输出其他额外内容。
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_JA: &str = r#"あなたは@commitlint/config-conventionalに従ったコミットメッセージを生成するアシスタントです。
|
||||
|
||||
git diffを分析し、コミットメッセージを生成してください。
|
||||
|
||||
形式: <type>[オプションのスコープ]: <件名>
|
||||
|
||||
タイプ: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
ルール:
|
||||
1. 件名は大文字で始めないでください
|
||||
2. 件名はピリオドで終わらないでください
|
||||
3. 件名は4-100文字である必要があります
|
||||
4. 命令形を使用してください
|
||||
5. 簡潔ですが説明的であること
|
||||
6. コミットメッセージのみを出力し、それ以外は出力しないでください。
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_KO: &str = r#"당신은 @commitlint/config-conventional에 따른 커밋 메시지를 생성하는 도우미입니다.
|
||||
|
||||
git diff를 분석하고 커밋 메시지를 생성하세요.
|
||||
|
||||
형식: <type>[선택적 범위]: <제목>
|
||||
|
||||
유형: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
규칙:
|
||||
1. 제목은 대문자로 시작하지 않아야 합니다
|
||||
2. 제목은 마침표로 끝나지 않아야 합니다
|
||||
3. 제목은 4-100자여야 합니다
|
||||
4. 명령형을 사용하세요
|
||||
5. 간결하지만 설명적이어야 합니다
|
||||
6. 커밋 메시지만 출력하고 다른 내용은 출력하지 마세요.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de commit siguiendo @commitlint/config-conventional.
|
||||
|
||||
Analiza el diff de git y genera un mensaje de commit.
|
||||
|
||||
Formato: <tipo>[alcance opcional]: <asunto>
|
||||
|
||||
Tipos: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Reglas:
|
||||
1. El asunto no debe comenzar con mayúscula
|
||||
2. El asunto no debe terminar con punto
|
||||
3. El asunto debe tener 4-100 caracteres
|
||||
4. Usa modo imperativo
|
||||
5. Sé conciso pero descriptivo
|
||||
6. Genera SOLO el mensaje de commit, nada más.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages de commit suivant @commitlint/config-conventional.
|
||||
|
||||
Analysez le diff git et générez un message de commit.
|
||||
|
||||
Format: <type>[portée optionnelle]: <sujet>
|
||||
|
||||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Règles:
|
||||
1. Le sujet ne doit pas commencer par une majuscule
|
||||
2. Le sujet ne doit pas se terminer par un point
|
||||
3. Le sujet doit avoir 4-100 caractères
|
||||
4. Utilisez le mode impératif
|
||||
5. Soyez concis mais descriptif
|
||||
6. Générez SEULEMENT le message de commit, rien d'autre.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Commit-Nachrichten gemäß @commitlint/config-conventional generiert.
|
||||
|
||||
Analysieren Sie den git diff und generieren Sie eine Commit-Nachricht.
|
||||
|
||||
Format: <typ>[optionaler Bereich]: <betreff>
|
||||
|
||||
Typen: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Regeln:
|
||||
1. Der Betreff sollte nicht mit einem Großbuchstaben beginnen
|
||||
2. Der Betreff sollte nicht mit einem Punkt enden
|
||||
3. Der Betreff sollte 4-100 Zeichen haben
|
||||
4. Verwenden Sie den Imperativ
|
||||
5. Seien Sie prägnant aber beschreibend
|
||||
6. Geben Sie NUR die Commit-Nachricht aus, nichts anderes.
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates git tag annotation messages.
|
||||
|
||||
Given a version number and a list of commits, generate a concise but informative tag message.
|
||||
|
||||
The message should:
|
||||
1. Start with a brief summary of the release
|
||||
2. Group changes by type (features, fixes, etc.)
|
||||
3. Be suitable for a git annotated tag
|
||||
|
||||
Format:
|
||||
<version> Release
|
||||
|
||||
Summary of changes...
|
||||
|
||||
Changes:
|
||||
- Feature: description
|
||||
- Fix: description
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成 git 标签注释消息的助手。
|
||||
|
||||
给定版本号和提交列表,生成简洁但信息丰富的标签消息。
|
||||
|
||||
消息应该:
|
||||
1. 以发布的简要摘要开始
|
||||
2. 按类型分组更改(功能、修复等)
|
||||
3. 适合 git 标注标签
|
||||
|
||||
格式:
|
||||
<version> 发布
|
||||
|
||||
更改摘要...
|
||||
|
||||
更改:
|
||||
- 功能:描述
|
||||
- 修复:描述
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_JA: &str = r#"あなたはgitタグ注釈メッセージを生成するアシスタントです。
|
||||
|
||||
バージョン番号とコミットのリストを考慮して、簡潔ですが情報豊富なタグメッセージを生成してください。
|
||||
|
||||
メッセージは以下のようであるべきです:
|
||||
1. リリースの簡単な要約から始める
|
||||
2. タイプ別に変更をグループ化する(機能、修正など)
|
||||
3. git注釈タグに適している
|
||||
|
||||
形式:
|
||||
<version> リリース
|
||||
|
||||
変更の概要...
|
||||
|
||||
変更:
|
||||
- 機能:説明
|
||||
- 修正:説明
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_KO: &str = r#"당신은 git 태그 주석 메시지를 생성하는 도우미입니다.
|
||||
|
||||
버전 번호와 커밋 목록을 고려하여 간결하지만 정보가 풍부한 태그 메시지를 생성하세요.
|
||||
|
||||
메시지는 다음과 같아야 합니다:
|
||||
1. 릴리스의 간단한 요약으로 시작
|
||||
2. 유형별로 변경 사항 그룹화(기능, 수정 등)
|
||||
3. git 주석 태그에 적합
|
||||
|
||||
형식:
|
||||
<version> 릴리스
|
||||
|
||||
변경 사항 요약...
|
||||
|
||||
변경 사항:
|
||||
- 기능: 설명
|
||||
- 수정: 설명
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de anotación de etiquetas git.
|
||||
|
||||
Dado un número de versión y una lista de commits, genera un mensaje de etiqueta conciso pero informativo.
|
||||
|
||||
El mensaje debe:
|
||||
1. Comenzar con un resumen breve de la versión
|
||||
2. Agrupar cambios por tipo (características, correcciones, etc.)
|
||||
3. Ser adecuado para una etiqueta git anotada
|
||||
|
||||
Formato:
|
||||
<version> Versión
|
||||
|
||||
Resumen de cambios...
|
||||
|
||||
Cambios:
|
||||
- Característica: descripción
|
||||
- Corrección: descripción
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages d'annotation de balises git.
|
||||
|
||||
Étant donné un numéro de version et une liste de commits, générez un message de balise concis mais informatif.
|
||||
|
||||
Le message doit :
|
||||
1. Commencer par un bref résumé de la version
|
||||
2. Grouper les changements par type (fonctionnalités, corrections, etc.)
|
||||
3. Être adapté à une balise git annotée
|
||||
|
||||
Format :
|
||||
<version> Version
|
||||
|
||||
Résumé des changements...
|
||||
|
||||
Changements :
|
||||
- Fonctionnalité : description
|
||||
- Correction : description
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der git-Tag-Anmerkungsnachrichten generiert.
|
||||
|
||||
Gegeben eine Versionsnummer und eine Liste von Commits, generieren Sie eine prägnante aber informative Tag-Nachricht.
|
||||
|
||||
Die Nachricht sollte:
|
||||
1. Mit einer kurzen Zusammenfassung der Version beginnen
|
||||
2. Änderungen nach Typ gruppieren (Funktionen, Fixes, etc.)
|
||||
3. Für ein git-annotiertes Tag geeignet sein
|
||||
|
||||
Format:
|
||||
<version> Version
|
||||
|
||||
Zusammenfassung der Änderungen...
|
||||
|
||||
Änderungen:
|
||||
- Funktion: Beschreibung
|
||||
- Fix: Beschreibung
|
||||
...
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates changelog entries.
|
||||
|
||||
Given a version and a list of commits, generate a well-formatted changelog section.
|
||||
|
||||
Group commits by:
|
||||
- Features (feat)
|
||||
- Bug Fixes (fix)
|
||||
- Documentation (docs)
|
||||
- Other Changes
|
||||
|
||||
Format in markdown with proper headings and bullet points.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成变更日志条目的助手。
|
||||
|
||||
给定版本和提交列表,生成格式良好的变更日志部分。
|
||||
|
||||
按以下方式分组提交:
|
||||
- 功能 (feat)
|
||||
- 错误修复 (fix)
|
||||
- 文档 (docs)
|
||||
- 其他更改
|
||||
|
||||
使用适当的标题和项目符号以 markdown 格式输出。
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_JA: &str = r#"あなたは変更ログエントリを生成するアシスタントです。
|
||||
|
||||
バージョンとコミットのリストを考慮して、適切にフォーマットされた変更ログセクションを生成してください。
|
||||
|
||||
コミットを以下でグループ化してください:
|
||||
- 機能 (feat)
|
||||
- バグ修正 (fix)
|
||||
- ドキュメント (docs)
|
||||
- その他の変更
|
||||
|
||||
適切な見出しと箇条書きを使用してmarkdown形式でフォーマットしてください。
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_KO: &str = r#"당신은 변경 로그 항목을 생성하는 도우미입니다.
|
||||
|
||||
버전과 커밋 목록을 고려하여 잘 포맷된 변경 로그 섹션을 생성하세요.
|
||||
|
||||
다음으로 커밋을 그룹화하세요:
|
||||
- 기능 (feat)
|
||||
- 버그 수정 (fix)
|
||||
- 문서 (docs)
|
||||
- 기타 변경 사항
|
||||
|
||||
적절한 제목과 글머리 기호를 사용하여 markdown 형식으로 포맷하세요.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera entradas de registro de cambios.
|
||||
|
||||
Dada una versión y una lista de commits, genera una sección de registro de cambios bien formateada.
|
||||
|
||||
Agrupa los commits por:
|
||||
- Características (feat)
|
||||
- Correcciones de errores (fix)
|
||||
- Documentación (docs)
|
||||
- Otros cambios
|
||||
|
||||
Formatea en markdown con encabezados y viñetas apropiados.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des entrées de journal des modifications.
|
||||
|
||||
Étant donné une version et une liste de commits, générez une section de journal des modifications bien formatée.
|
||||
|
||||
Groupez les commits par :
|
||||
- Fonctionnalités (feat)
|
||||
- Corrections de bugs (fix)
|
||||
- Documentation (docs)
|
||||
- Autres modifications
|
||||
|
||||
Formatez en markdown avec des en-têtes et des puces appropriés.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Changelog-Einträge generiert.
|
||||
|
||||
Gegeben eine Version und eine Liste von Commits, generieren Sie einen gut formatierten Changelog-Abschnitt.
|
||||
|
||||
Gruppieren Sie Commits nach:
|
||||
- Funktionen (feat)
|
||||
- Bugfixes (fix)
|
||||
- Dokumentation (docs)
|
||||
- Andere Änderungen
|
||||
|
||||
Formatieren Sie in Markdown mit geeigneten Überschriften und Aufzählungspunkten.
|
||||
"#;
|
||||
|
||||
/// Test LLM connection
|
||||
pub async fn test_connection(manager: &crate::config::manager::ConfigManager) -> Result<String> {
|
||||
|
||||
281
src/llm/parsing.rs
Normal file
281
src/llm/parsing.rs
Normal file
@@ -0,0 +1,281 @@
|
||||
use anyhow::{Result, bail};
|
||||
|
||||
/// Parse commit response from LLM
|
||||
pub(crate) fn parse_commit_response(
|
||||
response: &str,
|
||||
format: crate::config::CommitFormat,
|
||||
) -> Result<GeneratedCommit> {
|
||||
// Clean markdown code fences from the response
|
||||
let cleaned = strip_code_fences(response);
|
||||
|
||||
let lines: Vec<&str> = cleaned
|
||||
.lines()
|
||||
.map(|l| l.trim())
|
||||
.filter(|l| !l.is_empty())
|
||||
.collect();
|
||||
|
||||
if lines.is_empty() {
|
||||
let preview: String = response.chars().take(200).collect();
|
||||
bail!(
|
||||
"LLM returned empty or whitespace-only response. \
|
||||
Raw response preview: '{}'. \
|
||||
Hint: If using DeepSeek/Kimi with thinking enabled, \
|
||||
the model may have returned reasoning_content only. \
|
||||
Try disabling thinking mode or switching models.",
|
||||
preview
|
||||
);
|
||||
}
|
||||
|
||||
// Find the line most likely to be the commit subject
|
||||
let first_line = find_commit_subject_line(&lines, format);
|
||||
|
||||
// Parse based on format
|
||||
match format {
|
||||
crate::config::CommitFormat::Conventional => {
|
||||
parse_conventional_commit(first_line, &lines, response)
|
||||
}
|
||||
crate::config::CommitFormat::Commitlint => {
|
||||
parse_commitlint_commit(first_line, &lines, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove surrounding markdown code fences (```) from LLM output
|
||||
fn strip_code_fences(response: &str) -> String {
|
||||
let mut lines: Vec<&str> = response.lines().collect();
|
||||
|
||||
// Strip leading fence lines (``` or ```lang)
|
||||
while lines.first().map_or(false, |l| l.trim().starts_with("```")) {
|
||||
lines.remove(0);
|
||||
}
|
||||
|
||||
// Strip trailing fence lines
|
||||
while lines.last().map_or(false, |l| l.trim() == "```") {
|
||||
lines.pop();
|
||||
}
|
||||
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
/// Find the line that is most likely the commit subject among extracted lines
|
||||
fn find_commit_subject_line<'a>(
|
||||
lines: &[&'a str],
|
||||
format: crate::config::CommitFormat,
|
||||
) -> &'a str {
|
||||
let valid_types = crate::utils::validators::get_commit_types(matches!(
|
||||
format,
|
||||
crate::config::CommitFormat::Commitlint
|
||||
));
|
||||
|
||||
// First pass: line starting with a known type that also has proper syntax
|
||||
// (e.g. "type:", "type(scope):", "type!:")
|
||||
for &line in lines {
|
||||
let trimmed = line.trim();
|
||||
for &t in valid_types {
|
||||
if let Some(rest) = trimmed.strip_prefix(t) {
|
||||
if rest.starts_with(':') || rest.starts_with('(') || rest.starts_with("!:") {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: any line containing a colon (generic "prefix: description")
|
||||
for &line in lines {
|
||||
if line.contains(':') {
|
||||
return line.trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: return the first line as-is
|
||||
lines[0].trim()
|
||||
}
|
||||
|
||||
fn parse_conventional_commit(
|
||||
first_line: &str,
|
||||
lines: &[&str],
|
||||
raw_response: &str,
|
||||
) -> Result<GeneratedCommit> {
|
||||
// Parse: type(scope)!: description
|
||||
let parts: Vec<&str> = first_line.splitn(2, ':').collect();
|
||||
if parts.len() != 2 {
|
||||
let preview: String = raw_response.chars().take(300).collect();
|
||||
bail!(
|
||||
"Invalid conventional commit format: missing colon.\n\
|
||||
Parsed subject line: '{}'\n\
|
||||
Raw response preview: '{}'\n\
|
||||
Expected: <type>[optional scope]: <description>",
|
||||
first_line,
|
||||
preview
|
||||
);
|
||||
}
|
||||
|
||||
let type_part = parts[0];
|
||||
let description = parts[1].trim();
|
||||
|
||||
// Extract type, scope, and breaking indicator
|
||||
let breaking = type_part.ends_with('!');
|
||||
let type_part = type_part.trim_end_matches('!');
|
||||
|
||||
let (commit_type, scope) = if let Some(start) = type_part.find('(') {
|
||||
if let Some(end) = type_part.find(')') {
|
||||
let t = &type_part[..start];
|
||||
let s = &type_part[start + 1..end];
|
||||
(t.to_string(), Some(s.to_string()))
|
||||
} else {
|
||||
bail!("Invalid scope format: missing closing parenthesis");
|
||||
}
|
||||
} else {
|
||||
(type_part.to_string(), None)
|
||||
};
|
||||
|
||||
// Extract body and footer
|
||||
let (body, footer) = extract_body_footer(lines);
|
||||
|
||||
Ok(GeneratedCommit {
|
||||
commit_type,
|
||||
scope,
|
||||
description: description.to_string(),
|
||||
body,
|
||||
footer,
|
||||
breaking,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_commitlint_commit(
|
||||
first_line: &str,
|
||||
lines: &[&str],
|
||||
raw_response: &str,
|
||||
) -> Result<GeneratedCommit> {
|
||||
// Similar parsing but with commitlint rules
|
||||
let parts: Vec<&str> = first_line.splitn(2, ':').collect();
|
||||
if parts.len() != 2 {
|
||||
let preview: String = raw_response.chars().take(300).collect();
|
||||
bail!(
|
||||
"Invalid commit format: missing colon.\n\
|
||||
Parsed subject line: '{}'\n\
|
||||
Raw response preview: '{}'\n\
|
||||
Expected: <type>[optional scope]: <subject>",
|
||||
first_line,
|
||||
preview
|
||||
);
|
||||
}
|
||||
|
||||
let type_part = parts[0];
|
||||
let subject = parts[1].trim();
|
||||
|
||||
let (commit_type, scope) = if let Some(start) = type_part.find('(') {
|
||||
if let Some(end) = type_part.find(')') {
|
||||
let t = &type_part[..start];
|
||||
let s = &type_part[start + 1..end];
|
||||
(t.to_string(), Some(s.to_string()))
|
||||
} else {
|
||||
(type_part.to_string(), None)
|
||||
}
|
||||
} else {
|
||||
(type_part.to_string(), None)
|
||||
};
|
||||
|
||||
let (body, footer) = extract_body_footer(&lines);
|
||||
|
||||
Ok(GeneratedCommit {
|
||||
commit_type,
|
||||
scope,
|
||||
description: subject.to_string(),
|
||||
body,
|
||||
footer,
|
||||
breaking: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_body_footer(lines: &[&str]) -> (Option<String>, Option<String>) {
|
||||
if lines.len() <= 1 {
|
||||
return (None, None);
|
||||
}
|
||||
|
||||
let rest: Vec<&str> = lines[1..]
|
||||
.iter()
|
||||
.skip_while(|l| l.trim().is_empty())
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
if rest.is_empty() {
|
||||
return (None, None);
|
||||
}
|
||||
|
||||
// Look for footer markers
|
||||
let footer_markers = [
|
||||
"BREAKING CHANGE:",
|
||||
"Closes",
|
||||
"Fixes",
|
||||
"Refs",
|
||||
"Co-authored-by:",
|
||||
];
|
||||
|
||||
let mut body_lines = vec![];
|
||||
let mut footer_lines = vec![];
|
||||
let mut in_footer = false;
|
||||
|
||||
for line in &rest {
|
||||
if footer_markers.iter().any(|m| line.starts_with(m)) {
|
||||
in_footer = true;
|
||||
}
|
||||
|
||||
if in_footer {
|
||||
footer_lines.push(*line);
|
||||
} else {
|
||||
body_lines.push(*line);
|
||||
}
|
||||
}
|
||||
|
||||
let body = if body_lines.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(body_lines.join("\n"))
|
||||
};
|
||||
|
||||
let footer = if footer_lines.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(footer_lines.join("\n"))
|
||||
};
|
||||
|
||||
(body, footer)
|
||||
}
|
||||
|
||||
/// Generated commit structure
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GeneratedCommit {
|
||||
pub commit_type: String,
|
||||
pub scope: Option<String>,
|
||||
pub description: String,
|
||||
pub body: Option<String>,
|
||||
pub footer: Option<String>,
|
||||
pub breaking: bool,
|
||||
}
|
||||
|
||||
impl GeneratedCommit {
|
||||
/// Format as conventional commit
|
||||
pub fn to_conventional(&self) -> String {
|
||||
crate::utils::formatter::format_conventional_commit(
|
||||
&self.commit_type,
|
||||
self.scope.as_deref(),
|
||||
&self.description,
|
||||
self.body.as_deref(),
|
||||
self.footer.as_deref(),
|
||||
self.breaking,
|
||||
)
|
||||
}
|
||||
|
||||
/// Format as commitlint commit
|
||||
pub fn to_commitlint(&self) -> String {
|
||||
crate::utils::formatter::format_commitlint_commit(
|
||||
&self.commit_type,
|
||||
self.scope.as_deref(),
|
||||
&self.description,
|
||||
self.body.as_deref(),
|
||||
self.footer.as_deref(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
618
src/llm/prompts.rs
Normal file
618
src/llm/prompts.rs
Normal file
@@ -0,0 +1,618 @@
|
||||
use crate::config::Language;
|
||||
|
||||
/// Get commit system prompt based on format and language
|
||||
pub(crate) fn get_commit_system_prompt(
|
||||
format: crate::config::CommitFormat,
|
||||
language: Language,
|
||||
) -> &'static str {
|
||||
match (format, language) {
|
||||
(crate::config::CommitFormat::Conventional, Language::Chinese) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ZH
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::Japanese) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_JA
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::Korean) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_KO
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::Spanish) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ES
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::French) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_FR
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, Language::German) => {
|
||||
CONVENTIONAL_COMMIT_SYSTEM_PROMPT_DE
|
||||
}
|
||||
(crate::config::CommitFormat::Conventional, _) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT,
|
||||
(crate::config::CommitFormat::Commitlint, Language::Chinese) => COMMITLINT_SYSTEM_PROMPT_ZH,
|
||||
(crate::config::CommitFormat::Commitlint, Language::Japanese) => {
|
||||
COMMITLINT_SYSTEM_PROMPT_JA
|
||||
}
|
||||
(crate::config::CommitFormat::Commitlint, Language::Korean) => COMMITLINT_SYSTEM_PROMPT_KO,
|
||||
(crate::config::CommitFormat::Commitlint, Language::Spanish) => COMMITLINT_SYSTEM_PROMPT_ES,
|
||||
(crate::config::CommitFormat::Commitlint, Language::French) => COMMITLINT_SYSTEM_PROMPT_FR,
|
||||
(crate::config::CommitFormat::Commitlint, Language::German) => COMMITLINT_SYSTEM_PROMPT_DE,
|
||||
(crate::config::CommitFormat::Commitlint, _) => COMMITLINT_SYSTEM_PROMPT,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_tag_system_prompt(language: Language) -> &'static str {
|
||||
match language {
|
||||
Language::Chinese => TAG_MESSAGE_SYSTEM_PROMPT_ZH,
|
||||
Language::Japanese => TAG_MESSAGE_SYSTEM_PROMPT_JA,
|
||||
Language::Korean => TAG_MESSAGE_SYSTEM_PROMPT_KO,
|
||||
Language::Spanish => TAG_MESSAGE_SYSTEM_PROMPT_ES,
|
||||
Language::French => TAG_MESSAGE_SYSTEM_PROMPT_FR,
|
||||
Language::German => TAG_MESSAGE_SYSTEM_PROMPT_DE,
|
||||
_ => TAG_MESSAGE_SYSTEM_PROMPT,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_changelog_system_prompt(language: Language) -> &'static str {
|
||||
match language {
|
||||
Language::Chinese => CHANGELOG_SYSTEM_PROMPT_ZH,
|
||||
Language::Japanese => CHANGELOG_SYSTEM_PROMPT_JA,
|
||||
Language::Korean => CHANGELOG_SYSTEM_PROMPT_KO,
|
||||
Language::Spanish => CHANGELOG_SYSTEM_PROMPT_ES,
|
||||
Language::French => CHANGELOG_SYSTEM_PROMPT_FR,
|
||||
Language::German => CHANGELOG_SYSTEM_PROMPT_DE,
|
||||
_ => CHANGELOG_SYSTEM_PROMPT,
|
||||
}
|
||||
}
|
||||
|
||||
// System prompts for LLM
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates conventional commit messages.
|
||||
|
||||
Analyze the git diff provided and generate a commit message following the Conventional Commits specification.
|
||||
|
||||
Format: <type>[optional scope]: <description>
|
||||
|
||||
Types:
|
||||
- feat: A new feature
|
||||
- fix: A bug fix
|
||||
- docs: Documentation only changes
|
||||
- style: Changes that don't affect code meaning (formatting, semicolons, etc.)
|
||||
- refactor: Code change that neither fixes a bug nor adds a feature
|
||||
- perf: Code change that improves performance
|
||||
- test: Adding or correcting tests
|
||||
- build: Changes to build system or dependencies
|
||||
- ci: Changes to CI configuration
|
||||
- chore: Other changes that don't modify src or test files
|
||||
- revert: Reverts a previous commit
|
||||
|
||||
Rules:
|
||||
1. Use lowercase for type and scope
|
||||
2. Keep description under 100 characters
|
||||
3. Use imperative mood ("add" not "added")
|
||||
4. Don't capitalize first letter
|
||||
5. No period at the end
|
||||
6. Include scope if the change is specific to a module/component
|
||||
|
||||
Output ONLY the commit message, nothing else.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成符合 Conventional Commits 规范的提交消息的助手。
|
||||
|
||||
分析提供的 git diff,并生成符合 Conventional Commits 规范的提交消息。
|
||||
|
||||
格式: <type>[可选作用域]: <描述>
|
||||
|
||||
类型:
|
||||
- feat: 新功能
|
||||
- fix: 修复错误
|
||||
- docs: 仅文档更改
|
||||
- style: 不影响代码含义的更改(格式化、分号等)
|
||||
- refactor: 既不修复错误也不添加功能的代码更改
|
||||
- perf: 提高性能的代码更改
|
||||
- test: 添加或更正测试
|
||||
- build: 更改构建系统或依赖项
|
||||
- ci: 更改 CI 配置
|
||||
- chore: 其他不修改 src 或测试文件的更改
|
||||
- revert: 撤销之前的提交
|
||||
|
||||
规则:
|
||||
1. 类型和小写使用小写
|
||||
2. 描述保持在 100 个字符以内
|
||||
3. 使用祈使语气("添加"而不是"已添加")
|
||||
4. 不要大写首字母
|
||||
5. 结尾不要句号
|
||||
6. 如果更改特定于模块/组件,请包含作用域
|
||||
7. 仅输出提交消息,不要输出其他内容。
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_JA: &str = r#"あなたはConventional Commits仕様に従ったコミットメッセージを生成するアシスタントです。
|
||||
|
||||
提供されたgit diffを分析し、Conventional Commits仕様に従ったコミットメッセージを生成してください。
|
||||
|
||||
形式: <type>[オプションのスコープ]: <説明>
|
||||
|
||||
タイプ:
|
||||
- feat: 新機能
|
||||
- fix: バグ修正
|
||||
- docs: ドキュメントのみの変更
|
||||
- style: コードの意味に影響しない変更(フォーマット、セミコロンなど)
|
||||
- refactor: バグ修正や機能追加を伴わないコード変更
|
||||
- perf: パフォーマンスを向上させるコード変更
|
||||
- test: テストの追加または修正
|
||||
- build: ビルドシステムまたは依存関係の変更
|
||||
- ci: CI設定の変更
|
||||
- chore: srcやテストファイルを変更しないその他の変更
|
||||
- revert: 以前のコミットを取り消す
|
||||
|
||||
ルール:
|
||||
1. タイプとスコープは小文字を使用
|
||||
2. 説明は100文字以内にする
|
||||
3. 命令形を使用する("追加"ではなく"追加する")
|
||||
4. 先頭を大文字にしない
|
||||
5. 最後にピリオドを付けない
|
||||
6. 変更がモジュール/コンポーネントに固有の場合はスコープを含める
|
||||
7. コミットメッセージのみを出力し、それ以外は出力しないでください。
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_KO: &str = r#"당신은 Conventional Commits 사양에 따른 커밋 메시지를 생성하는 도우미입니다.
|
||||
|
||||
제공된 git diff를 분석하고 Conventional Commits 사양에 따른 커밋 메시지를 생성하세요.
|
||||
|
||||
형식: <type>[선택적 범위]: <설명>
|
||||
|
||||
유형:
|
||||
- feat: 새 기능
|
||||
- fix: 버그 수정
|
||||
- docs: 문서 변경만
|
||||
- style: 코드 의미에 영향을 주지 않는 변경(서식, 세미콜론 등)
|
||||
- refactor: 버그를 수정하거나 기능을 추가하지 않는 코드 변경
|
||||
- perf: 성능을 향상시키는 코드 변경
|
||||
- test: 테스트 추가 또는 수정
|
||||
- build: 빌드 시스템 또는 종속성 변경
|
||||
- ci: CI 구성 변경
|
||||
- chore: src 또는 테스트 파일을 수정하지 않는 기타 변경
|
||||
- revert: 이전 커밋 되돌리기
|
||||
|
||||
규칙:
|
||||
1. 유형과 범위는 소문자 사용
|
||||
2. 설명은 100자 이내로 유지
|
||||
3. 명령형 사용("추가"가 아닌 "추가하다")
|
||||
4. 첫 글자 대문자화하지 않음
|
||||
5. 끝에 마침표 사용하지 않음
|
||||
6. 변경 사항이 모듈/구성 요소에 특정한 경우 범위 포함
|
||||
7. 커밋 메시지만 출력하고 다른 내용은 출력하지 마세요.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de commit siguiendo la especificación Conventional Commits.
|
||||
|
||||
Analiza el diff de git proporcionado y genera un mensaje de commit siguiendo la especificación Conventional Commits.
|
||||
|
||||
Formato: <tipo>[alcance opcional]: <descripción>
|
||||
|
||||
Tipos:
|
||||
- feat: Una nueva característica
|
||||
- fix: Una corrección de error
|
||||
- docs: Solo cambios en documentación
|
||||
- style: Cambios que no afectan el significado del código (formato, punto y coma, etc.)
|
||||
- refactor: Cambio de código que no corrige un error ni agrega una característica
|
||||
- perf: Cambio de código que mejora el rendimiento
|
||||
- test: Agregar o corregir pruebas
|
||||
- build: Cambios en el sistema de construcción o dependencias
|
||||
- ci: Cambios en la configuración de CI
|
||||
- chore: Otros cambios que no modifican archivos src o de prueba
|
||||
- revert: Revierte un commit anterior
|
||||
|
||||
Reglas:
|
||||
1. Usa minúsculas para tipo y alcance
|
||||
2. Mantén la descripción bajo 100 caracteres
|
||||
3. Usa modo imperativo ("agregar" no "agregado")
|
||||
4. No capitalices la primera letra
|
||||
5. Sin punto al final
|
||||
6. Incluye alcance si el cambio es específico de un módulo/componente
|
||||
7. Genera SOLO el mensaje de commit, nada más.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages de commit suivant la spécification Conventional Commits.
|
||||
|
||||
Analysez le diff git fourni et générez un message de commit suivant la spécification Conventional Commits.
|
||||
|
||||
Format: <type>[portée optionnelle]: <description>
|
||||
|
||||
Types:
|
||||
- feat: Une nouvelle fonctionnalité
|
||||
- fix: Une correction de bug
|
||||
- docs: Changements de documentation uniquement
|
||||
- style: Changements qui n'affectent pas la signification du code (formatage, points-virgules, etc.)
|
||||
- refactor: Changement de code qui ne corrige pas un bug ni n'ajoute une fonctionnalité
|
||||
- perf: Changement de code qui améliore les performances
|
||||
- test: Ajout ou correction de tests
|
||||
- build: Changements du système de build ou des dépendances
|
||||
- ci: Changements de la configuration CI
|
||||
- chore: Autres changements qui ne modifient pas les fichiers src ou de test
|
||||
- revert: Révertit un commit précédent
|
||||
|
||||
Règles:
|
||||
1. Utilisez des minuscules pour le type et la portée
|
||||
2. Gardez la description sous 100 caractères
|
||||
3. Utilisez le mode impératif ("ajouter" non "ajouté")
|
||||
4. Ne capitalisez pas la première lettre
|
||||
5. Pas de point à la fin
|
||||
6. Incluez la portée si le changement est spécifique à un module/composant
|
||||
7. Générez SEULEMENT le message de commit, rien d'autre.
|
||||
"#;
|
||||
|
||||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Commit-Nachrichten gemäß der Conventional Commits-Spezifikation generiert.
|
||||
|
||||
Analysieren Sie den bereitgestellten git diff und generieren Sie eine Commit-Nachricht gemäß der Conventional Commits-Spezifikation.
|
||||
|
||||
Format: <typ>[optionaler Bereich]: <beschreibung>
|
||||
|
||||
Typen:
|
||||
- feat: Eine neue Funktion
|
||||
- fix: Ein Bugfix
|
||||
- docs: Nur Dokumentationsänderungen
|
||||
- style: Änderungen, die die Code-Bedeutung nicht beeinflussen (Formatierung, Semikolons usw.)
|
||||
- refactor: Code-Änderung, die weder einen Bug behebt noch eine Funktion hinzufügt
|
||||
- perf: Code-Änderung, die die Leistung verbessert
|
||||
- test: Hinzufügen oder Korrigieren von Tests
|
||||
- build: Änderungen am Build-System oder Abhängigkeiten
|
||||
- ci: Änderungen an der CI-Konfiguration
|
||||
- chore: Andere Änderungen, die src- oder Testdateien nicht ändern
|
||||
- revert: Setzt einen vorherigen Commit zurück
|
||||
|
||||
Regeln:
|
||||
1. Verwenden Sie Kleinbuchstaben für Typ und Bereich
|
||||
2. Halten Sie die Beschreibung unter 100 Zeichen
|
||||
3. Verwenden Sie den Imperativ ("hinzufügen" nicht "hinzugefügt")
|
||||
4. Großschreiben Sie den ersten Buchstaben nicht
|
||||
5. Kein Punkt am Ende
|
||||
6. Fügen Sie einen Bereich ein, wenn die Änderung spezifisch für ein Modul/Komponente ist
|
||||
7. Geben Sie NUR die Commit-Nachricht aus, nichts anderes.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates commit messages following @commitlint/config-conventional.
|
||||
|
||||
Analyze the git diff and generate a commit message.
|
||||
|
||||
Format: <type>[optional scope]: <subject>
|
||||
|
||||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Rules:
|
||||
1. Subject should not start with uppercase
|
||||
2. Subject should not end with period
|
||||
3. Subject should be 4-100 characters
|
||||
4. Use imperative mood
|
||||
5. Be concise but descriptive
|
||||
6. Output ONLY the commit message, nothing else.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成符合 @commitlint/config-conventional 规范的提交消息的助手。
|
||||
|
||||
分析 git diff 并生成提交消息。
|
||||
|
||||
格式: <type>[可选作用域]: <主题>
|
||||
|
||||
类型: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
规则:
|
||||
1. 主题不应以大写字母开头
|
||||
2. 主题不应以句号结尾
|
||||
3. 主题应为 4-100 个字符
|
||||
4. 使用祈使语气
|
||||
5. 简洁但描述性强
|
||||
6. 仅输出提交消息,不要输出其他额外内容。
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_JA: &str = r#"あなたは@commitlint/config-conventionalに従ったコミットメッセージを生成するアシスタントです。
|
||||
|
||||
git diffを分析し、コミットメッセージを生成してください。
|
||||
|
||||
形式: <type>[オプションのスコープ]: <件名>
|
||||
|
||||
タイプ: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
ルール:
|
||||
1. 件名は大文字で始めないでください
|
||||
2. 件名はピリオドで終わらないでください
|
||||
3. 件名は4-100文字である必要があります
|
||||
4. 命令形を使用してください
|
||||
5. 簡潔ですが説明的であること
|
||||
6. コミットメッセージのみを出力し、それ以外は出力しないでください。
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_KO: &str = r#"당신은 @commitlint/config-conventional에 따른 커밋 메시지를 생성하는 도우미입니다.
|
||||
|
||||
git diff를 분석하고 커밋 메시지를 생성하세요.
|
||||
|
||||
형식: <type>[선택적 범위]: <제목>
|
||||
|
||||
유형: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
규칙:
|
||||
1. 제목은 대문자로 시작하지 않아야 합니다
|
||||
2. 제목은 마침표로 끝나지 않아야 합니다
|
||||
3. 제목은 4-100자여야 합니다
|
||||
4. 명령형을 사용하세요
|
||||
5. 간결하지만 설명적이어야 합니다
|
||||
6. 커밋 메시지만 출력하고 다른 내용은 출력하지 마세요.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de commit siguiendo @commitlint/config-conventional.
|
||||
|
||||
Analiza el diff de git y genera un mensaje de commit.
|
||||
|
||||
Formato: <tipo>[alcance opcional]: <asunto>
|
||||
|
||||
Tipos: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Reglas:
|
||||
1. El asunto no debe comenzar con mayúscula
|
||||
2. El asunto no debe terminar con punto
|
||||
3. El asunto debe tener 4-100 caracteres
|
||||
4. Usa modo imperativo
|
||||
5. Sé conciso pero descriptivo
|
||||
6. Genera SOLO el mensaje de commit, nada más.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages de commit suivant @commitlint/config-conventional.
|
||||
|
||||
Analysez le diff git et générez un message de commit.
|
||||
|
||||
Format: <type>[portée optionnelle]: <sujet>
|
||||
|
||||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Règles:
|
||||
1. Le sujet ne doit pas commencer par une majuscule
|
||||
2. Le sujet ne doit pas se terminer par un point
|
||||
3. Le sujet doit avoir 4-100 caractères
|
||||
4. Utilisez le mode impératif
|
||||
5. Soyez concis mais descriptif
|
||||
6. Générez SEULEMENT le message de commit, rien d'autre.
|
||||
"#;
|
||||
|
||||
const COMMITLINT_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Commit-Nachrichten gemäß @commitlint/config-conventional generiert.
|
||||
|
||||
Analysieren Sie den git diff und generieren Sie eine Commit-Nachricht.
|
||||
|
||||
Format: <typ>[optionaler Bereich]: <betreff>
|
||||
|
||||
Typen: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
|
||||
Regeln:
|
||||
1. Der Betreff sollte nicht mit einem Großbuchstaben beginnen
|
||||
2. Der Betreff sollte nicht mit einem Punkt enden
|
||||
3. Der Betreff sollte 4-100 Zeichen haben
|
||||
4. Verwenden Sie den Imperativ
|
||||
5. Seien Sie prägnant aber beschreibend
|
||||
6. Geben Sie NUR die Commit-Nachricht aus, nichts anderes.
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates git tag annotation messages.
|
||||
|
||||
Given a version number and a list of commits, generate a concise but informative tag message.
|
||||
|
||||
The message should:
|
||||
1. Start with a brief summary of the release
|
||||
2. Group changes by type (features, fixes, etc.)
|
||||
3. Be suitable for a git annotated tag
|
||||
|
||||
Format:
|
||||
<version> Release
|
||||
|
||||
Summary of changes...
|
||||
|
||||
Changes:
|
||||
- Feature: description
|
||||
- Fix: description
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成 git 标签注释消息的助手。
|
||||
|
||||
给定版本号和提交列表,生成简洁但信息丰富的标签消息。
|
||||
|
||||
消息应该:
|
||||
1. 以发布的简要摘要开始
|
||||
2. 按类型分组更改(功能、修复等)
|
||||
3. 适合 git 标注标签
|
||||
|
||||
格式:
|
||||
<version> 发布
|
||||
|
||||
更改摘要...
|
||||
|
||||
更改:
|
||||
- 功能:描述
|
||||
- 修复:描述
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_JA: &str = r#"あなたはgitタグ注釈メッセージを生成するアシスタントです。
|
||||
|
||||
バージョン番号とコミットのリストを考慮して、簡潔ですが情報豊富なタグメッセージを生成してください。
|
||||
|
||||
メッセージは以下のようであるべきです:
|
||||
1. リリースの簡単な要約から始める
|
||||
2. タイプ別に変更をグループ化する(機能、修正など)
|
||||
3. git注釈タグに適している
|
||||
|
||||
形式:
|
||||
<version> リリース
|
||||
|
||||
変更の概要...
|
||||
|
||||
変更:
|
||||
- 機能:説明
|
||||
- 修正:説明
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_KO: &str = r#"당신은 git 태그 주석 메시지를 생성하는 도우미입니다.
|
||||
|
||||
버전 번호와 커밋 목록을 고려하여 간결하지만 정보가 풍부한 태그 메시지를 생성하세요.
|
||||
|
||||
메시지는 다음과 같아야 합니다:
|
||||
1. 릴리스의 간단한 요약으로 시작
|
||||
2. 유형별로 변경 사항 그룹화(기능, 수정 등)
|
||||
3. git 주석 태그에 적합
|
||||
|
||||
형식:
|
||||
<version> 릴리스
|
||||
|
||||
변경 사항 요약...
|
||||
|
||||
변경 사항:
|
||||
- 기능: 설명
|
||||
- 수정: 설명
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de anotación de etiquetas git.
|
||||
|
||||
Dado un número de versión y una lista de commits, genera un mensaje de etiqueta conciso pero informativo.
|
||||
|
||||
El mensaje debe:
|
||||
1. Comenzar con un resumen breve de la versión
|
||||
2. Agrupar cambios por tipo (características, correcciones, etc.)
|
||||
3. Ser adecuado para una etiqueta git anotada
|
||||
|
||||
Formato:
|
||||
<version> Versión
|
||||
|
||||
Resumen de cambios...
|
||||
|
||||
Cambios:
|
||||
- Característica: descripción
|
||||
- Corrección: descripción
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages d'annotation de balises git.
|
||||
|
||||
Étant donné un numéro de version et une liste de commits, générez un message de balise concis mais informatif.
|
||||
|
||||
Le message doit :
|
||||
1. Commencer par un bref résumé de la version
|
||||
2. Grouper les changements par type (fonctionnalités, corrections, etc.)
|
||||
3. Être adapté à une balise git annotée
|
||||
|
||||
Format :
|
||||
<version> Version
|
||||
|
||||
Résumé des changements...
|
||||
|
||||
Changements :
|
||||
- Fonctionnalité : description
|
||||
- Correction : description
|
||||
...
|
||||
"#;
|
||||
|
||||
const TAG_MESSAGE_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der git-Tag-Anmerkungsnachrichten generiert.
|
||||
|
||||
Gegeben eine Versionsnummer und eine Liste von Commits, generieren Sie eine prägnante aber informative Tag-Nachricht.
|
||||
|
||||
Die Nachricht sollte:
|
||||
1. Mit einer kurzen Zusammenfassung der Version beginnen
|
||||
2. Änderungen nach Typ gruppieren (Funktionen, Fixes, etc.)
|
||||
3. Für ein git-annotiertes Tag geeignet sein
|
||||
|
||||
Format:
|
||||
<version> Version
|
||||
|
||||
Zusammenfassung der Änderungen...
|
||||
|
||||
Änderungen:
|
||||
- Funktion: Beschreibung
|
||||
- Fix: Beschreibung
|
||||
...
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates changelog entries.
|
||||
|
||||
Given a version and a list of commits, generate a well-formatted changelog section.
|
||||
|
||||
Group commits by:
|
||||
- Features (feat)
|
||||
- Bug Fixes (fix)
|
||||
- Documentation (docs)
|
||||
- Other Changes
|
||||
|
||||
Format in markdown with proper headings and bullet points.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成变更日志条目的助手。
|
||||
|
||||
给定版本和提交列表,生成格式良好的变更日志部分。
|
||||
|
||||
按以下方式分组提交:
|
||||
- 功能 (feat)
|
||||
- 错误修复 (fix)
|
||||
- 文档 (docs)
|
||||
- 其他更改
|
||||
|
||||
使用适当的标题和项目符号以 markdown 格式输出。
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_JA: &str = r#"あなたは変更ログエントリを生成するアシスタントです。
|
||||
|
||||
バージョンとコミットのリストを考慮して、適切にフォーマットされた変更ログセクションを生成してください。
|
||||
|
||||
コミットを以下でグループ化してください:
|
||||
- 機能 (feat)
|
||||
- バグ修正 (fix)
|
||||
- ドキュメント (docs)
|
||||
- その他の変更
|
||||
|
||||
適切な見出しと箇条書きを使用してmarkdown形式でフォーマットしてください。
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_KO: &str = r#"당신은 변경 로그 항목을 생성하는 도우미입니다.
|
||||
|
||||
버전과 커밋 목록을 고려하여 잘 포맷된 변경 로그 섹션을 생성하세요.
|
||||
|
||||
다음으로 커밋을 그룹화하세요:
|
||||
- 기능 (feat)
|
||||
- 버그 수정 (fix)
|
||||
- 문서 (docs)
|
||||
- 기타 변경 사항
|
||||
|
||||
적절한 제목과 글머리 기호를 사용하여 markdown 형식으로 포맷하세요.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera entradas de registro de cambios.
|
||||
|
||||
Dada una versión y una lista de commits, genera una sección de registro de cambios bien formateada.
|
||||
|
||||
Agrupa los commits por:
|
||||
- Características (feat)
|
||||
- Correcciones de errores (fix)
|
||||
- Documentación (docs)
|
||||
- Otros cambios
|
||||
|
||||
Formatea en markdown con encabezados y viñetas apropiados.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des entrées de journal des modifications.
|
||||
|
||||
Étant donné une version et une liste de commits, générez une section de journal des modifications bien formatée.
|
||||
|
||||
Groupez les commits par :
|
||||
- Fonctionnalités (feat)
|
||||
- Corrections de bugs (fix)
|
||||
- Documentation (docs)
|
||||
- Autres modifications
|
||||
|
||||
Formatez en markdown avec des en-têtes et des puces appropriés.
|
||||
"#;
|
||||
|
||||
const CHANGELOG_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Changelog-Einträge generiert.
|
||||
|
||||
Gegeben eine Version und eine Liste von Commits, generieren Sie einen gut formatierten Changelog-Abschnitt.
|
||||
|
||||
Gruppieren Sie Commits nach:
|
||||
- Funktionen (feat)
|
||||
- Bugfixes (fix)
|
||||
- Dokumentation (docs)
|
||||
- Andere Änderungen
|
||||
|
||||
Formatieren Sie in Markdown mit geeigneten Überschriften und Aufzählungspunkten.
|
||||
"#;
|
||||
Reference in New Issue
Block a user