fix: add missing newlines and improve code formatting across multiple files
ZhenYi committed
Modified app/aihost/src/main.rs app/aihost/src/main.rs +1 −1 View app/aihost/src/main.rs
@@ -184,4 +184,4 @@
184184 let _ = axum::serve(listener, router)
185185 .with_graceful_shutdown(async move { cancel.cancelled().await })
186186 .await;
187}
No newline at end of file
187}
Modified lib/admin/src/services/queues.rs lib/admin/src/services/queues.rs +2 −7 View lib/admin/src/services/queues.rs
@@ -447,18 +447,13 @@
447447 ai_job::Column::Status,
448448 Expr::value(models::ai::ai_job::AiJobStatus::Pending),
449449 )
450 .col_expr(
451 ai_job::Column::Error,
452 Expr::value(Option::<String>::None),
453 )
450 .col_expr(ai_job::Column::Error, Expr::value(Option::<String>::None))
454451 .col_expr(
455452 ai_job::Column::FinishedAt,
456453 Expr::value(Option::<time::OffsetDateTime>::None),
457454 )
458455 .col_expr(ai_job::Column::UpdatedAt, Expr::value(now))
459 .filter(
460 ai_job::Column::Status.eq(models::ai::ai_job::AiJobStatus::Failed),
461 )
456 .filter(ai_job::Column::Status.eq(models::ai::ai_job::AiJobStatus::Failed))
462457 .exec(self.db().write())
463458 .await?
464459 .rows_affected
Modified lib/admin/src/services/tasks.rs lib/admin/src/services/tasks.rs +15 −9 View lib/admin/src/services/tasks.rs
@@ -440,13 +440,11 @@
440440 SOURCE_AI => {
441441 let mut select = ai_job::Entity::find().order_by_desc(ai_job::Column::CreatedAt);
442442 if let Some(state) = state {
443 select = select.filter(
444 ai_job::Column::Status.eq(
445 parse_ai_state(state).ok_or_else(|| {
446 AdminError::BadRequest("invalid ai job state".to_string())
447 })?,
448 ),
449 );
443 select = select.filter(ai_job::Column::Status.eq(
444 parse_ai_state(state).ok_or_else(|| {
445 AdminError::BadRequest("invalid ai job state".to_string())
446 })?,
447 ));
450448 }
451449 if let Some(from) = from {
452450 select = select.filter(ai_job::Column::CreatedAt.gte(from));
@@ -458,7 +456,11 @@
458456 tasks.push(TaskDto {
459457 id: row.id,
460458 source: SOURCE_AI.to_string(),
461 title: format!("{} {}", row.kind.as_str(), row.target_ref.unwrap_or_default()),
459 title: format!(
460 "{} {}",
461 row.kind.as_str(),
462 row.target_ref.unwrap_or_default()
463 ),
462464 state: ai_state_str(row.status),
463465 created_at: row.created_at,
464466 updated_at: row.updated_at,
@@ -654,7 +656,11 @@
654656 let task = TaskDto {
655657 id: row.id,
656658 source: SOURCE_AI.to_string(),
657 title: format!("{} {}", row.kind.as_str(), row.target_ref.unwrap_or_default()),
659 title: format!(
660 "{} {}",
661 row.kind.as_str(),
662 row.target_ref.unwrap_or_default()
663 ),
658664 state: ai_state_str(row.status),
659665 created_at: row.created_at,
660666 updated_at: row.updated_at,
Modified lib/agent/src/bot.rs lib/agent/src/bot.rs +5 −2 View lib/agent/src/bot.rs
@@ -8,7 +8,10 @@
88///
99/// 该用户以 `bot=true, system=true` 标记,无口令、不可登录,仅用于承载
1010/// AI 评审与评论的作者身份。
11pub async fn resolve_bot_user(db: &DatabaseConnection, cfg: &AiConfig) -> Result<Uuid, sea_orm::DbErr> {
11pub async fn resolve_bot_user(
12 db: &DatabaseConnection,
13 cfg: &AiConfig,
14) -> Result<Uuid, sea_orm::DbErr> {
1215 let username = cfg.bot_username.trim();
1316 let lower = username.to_lowercase();
1417 if let Some(row) = user::Entity::find()
@@ -60,4 +63,4 @@
6063 .map(|row| row.uid)
6164 .ok_or_else(|| sea_orm::DbErr::RecordNotFound("ai bot user".to_string())),
6265 }
63}
No newline at end of file
66}
Modified lib/agent/src/client.rs lib/agent/src/client.rs +3 −5 View lib/agent/src/client.rs
@@ -153,10 +153,8 @@
153153 match self.send_once(&body).await {
154154 Ok(completion) => return Ok(completion),
155155 Err(error) => {
156 let retryable = matches!(
157 error,
158 AgentError::Transport(_) | AgentError::Status { .. }
159 );
156 let retryable =
157 matches!(error, AgentError::Transport(_) | AgentError::Status { .. });
160158 tracing::warn!(%error, attempt = attempt + 1, "ai completion attempt failed");
161159 last_error = Some(error);
162160 if !retryable {
@@ -247,4 +245,4 @@
247245 let rest = rest.strip_prefix("json").unwrap_or(rest);
248246 let end = rest.find("```")?;
249247 Some(rest[..end].trim().to_string())
250}
No newline at end of file
248}
Modified lib/agent/src/context.rs lib/agent/src/context.rs +14 −4 View lib/agent/src/context.rs
@@ -18,7 +18,10 @@
1818 head_sha: &str,
1919 base_ref: &str,
2020 ) -> Result<(BuiltContext, String), git::share::errors::GitError> {
21 let ctx = self.git.context(space_name.to_string(), repo_name.to_string()).await?;
21 let ctx = self
22 .git
23 .context(space_name.to_string(), repo_name.to_string())
24 .await?;
2225 let plan = self
2326 .git
2427 .merge_plan(&ctx, &format!("refs/heads/{base_ref}"), head_sha)
@@ -47,7 +50,10 @@
4750 repo_name: &str,
4851 commit_sha: &str,
4952 ) -> Result<(BuiltContext, String), git::share::errors::GitError> {
50 let ctx = self.git.context(space_name.to_string(), repo_name.to_string()).await?;
53 let ctx = self
54 .git
55 .context(space_name.to_string(), repo_name.to_string())
56 .await?;
5157 let baby = self.git.baby(&ctx);
5258 let info = baby
5359 .get_commit(commit_sha)
@@ -61,7 +67,12 @@
6167 let sha = info.id.to_string();
6268 let diff = self
6369 .git
64 .diff_raw(space_name.to_string(), repo_name.to_string(), parent.clone(), sha.clone())
70 .diff_raw(
71 space_name.to_string(),
72 repo_name.to_string(),
73 parent.clone(),
74 sha.clone(),
75 )
6576 .await?;
6677 let label = format!("{}..{}", short(&parent), short(&sha));
6778 Ok((self.truncate_diff(diff), label))
@@ -131,4 +142,3 @@
131142
132143/// 让 `GitContext` 在本 crate 内可用(避免调用方各自引入 git crate)。
133144pub type RepoContext = GitContext;
134
Modified lib/agent/src/diff.rs lib/agent/src/diff.rs +1 −1 View lib/agent/src/diff.rs
@@ -148,4 +148,4 @@
148148 }
149149 }
150150 (accepted, dropped)
151}
No newline at end of file
151}
Modified lib/agent/src/language_pref.rs lib/agent/src/language_pref.rs +14 −4 View lib/agent/src/language_pref.rs
@@ -36,12 +36,19 @@
3636 async fn user_language(&self, uid: Uuid) -> Option<String> {
3737 use models::users::user;
3838 use sea_orm::EntityTrait;
39 let row = user::Entity::find_by_id(uid).one(self.db_read()).await.ok()??;
39 let row = user::Entity::find_by_id(uid)
40 .one(self.db_read())
41 .await
42 .ok()??;
4043 let raw = row
4144 .language
4245 .as_deref()
4346 .filter(|value| !value.trim().is_empty())
44 .or_else(|| row.locale.as_deref().filter(|value| !value.trim().is_empty()))?;
47 .or_else(|| {
48 row.locale
49 .as_deref()
50 .filter(|value| !value.trim().is_empty())
51 })?;
4552 let normalized = crate::languages::normalize(raw);
4653 (!normalized.is_empty() && normalized != crate::languages::AUTO).then_some(normalized)
4754 }
@@ -50,10 +57,13 @@
5057 async fn repo_owner(&self, repo_id: Uuid) -> Option<Uuid> {
5158 use models::repo::repos;
5259 use sea_orm::EntityTrait;
53 let repo = repos::Entity::find_by_id(repo_id).one(self.db_read()).await.ok()??;
60 let repo = repos::Entity::find_by_id(repo_id)
61 .one(self.db_read())
62 .await
63 .ok()??;
5464 git::share::access::space_for_dir(self.db_read(), repo.dir_id)
5565 .await
5666 .ok()?
5767 .map(|space| space.owner_id)
5868 }
59}
No newline at end of file
69}
Modified lib/agent/src/lib.rs lib/agent/src/lib.rs +6 −3 View lib/agent/src/lib.rs
@@ -11,8 +11,8 @@
1111pub mod client;
1212pub mod context;
1313pub mod diff;
14mod language_pref;
1415pub mod languages;
15mod language_pref;
1616pub mod notifications;
1717pub mod notify;
1818pub mod prompt;
@@ -20,9 +20,12 @@
2020mod service;
2121
2222pub use client::{AgentClient, AgentCompletion, AgentError, AgentResult, extract_json};
23pub use languages::{display_name as language_display_name, normalize as normalize_language, supported_codes as supported_languages};
23pub use languages::{
24 display_name as language_display_name, normalize as normalize_language,
25 supported_codes as supported_languages,
26};
2427pub use prompt::{ReleaseNotesOutput, ReviewFinding, ReviewOutput, SummaryOutput};
2528pub use service::AgentService;
2629
2730/// 便捷别名:AI 队列任务载荷。
28pub use ci_protocol::ai::AgentTask;
No newline at end of file
31pub use ci_protocol::ai::AgentTask;
Modified lib/agent/src/notifications.rs lib/agent/src/notifications.rs +2 −6 View lib/agent/src/notifications.rs
@@ -42,9 +42,5 @@
4242/// 把 BCP-47 代码折叠到语族标签。
4343fn tag(language: &str) -> String {
4444 let normalized = ci_protocol::ai_languages::normalize(language);
45 normalized
46 .split('-')
47 .next()
48 .unwrap_or("en")
49 .to_string()
50}
No newline at end of file
45 normalized.split('-').next().unwrap_or("en").to_string()
46}
Modified lib/agent/src/notify.rs lib/agent/src/notify.rs +1 −1 View lib/agent/src/notify.rs
@@ -68,4 +68,4 @@
6868 }
6969 }
7070 }
71}
No newline at end of file
71}
Modified lib/agent/src/prompt.rs lib/agent/src/prompt.rs +2 −4 View lib/agent/src/prompt.rs
@@ -194,9 +194,7 @@
194194 Some(previous) => format!("{previous}..{tag_name}"),
195195 None => format!("(首个版本){tag_name}"),
196196 };
197 format!(
198 "仓库:{repo_name}\n版本:{tag_name}\n区间:{range}\n\n区间内提交:\n\n{commits}\n"
199 )
197 format!("仓库:{repo_name}\n版本:{tag_name}\n区间:{range}\n\n区间内提交:\n\n{commits}\n")
200198}
201199
202200/// 从补丁文本推断涉及的语言文件名扩展。
@@ -286,4 +284,4 @@
286284 "ipynb" => "Jupyter",
287285 _ => return None,
288286 })
289}
No newline at end of file
287}
Modified lib/agent/src/queue.rs lib/agent/src/queue.rs +3 −5 View lib/agent/src/queue.rs
@@ -1,5 +1,5 @@
1use models::ai::ai_job;
12use models::ai::ai_job::{ActiveModel, AiJobStatus};
2use models::ai::ai_job;
33use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set};
44use time::OffsetDateTime;
55use uuid::Uuid;
@@ -91,9 +91,7 @@
9191 pub async fn pending_jobs(&self, repo_id: Uuid) -> Result<u64, sea_orm::DbErr> {
9292 ai_job::Entity::find()
9393 .filter(ai_job::Column::RepoId.eq(repo_id))
94 .filter(
95 ai_job::Column::Status.is_in([AiJobStatus::Pending, AiJobStatus::Running]),
96 )
94 .filter(ai_job::Column::Status.is_in([AiJobStatus::Pending, AiJobStatus::Running]))
9795 .count(self.db_read())
9896 .await
9997 }
@@ -107,4 +105,4 @@
107105 "release_notes" => AiJobKind::ReleaseNotes,
108106 _ => AiJobKind::PullReview,
109107 }
110}
No newline at end of file
108}
Modified lib/agent/src/service.rs lib/agent/src/service.rs +30 −15 View lib/agent/src/service.rs
@@ -123,7 +123,10 @@
123123
124124 pub(crate) async fn space_name_for(&self, repo_id: Uuid) -> Option<String> {
125125 use models::repo::repos;
126 let repo = repos::Entity::find_by_id(repo_id).one(self.db_read()).await.ok()??;
126 let repo = repos::Entity::find_by_id(repo_id)
127 .one(self.db_read())
128 .await
129 .ok()??;
127130 git::share::access::space_for_dir(self.db_read(), repo.dir_id)
128131 .await
129132 .ok()?
@@ -174,8 +177,11 @@
174177 .complete(&review_system(&ctx), &prompt, true)
175178 .await?;
176179 let parsed: ReviewOutput = parse_output(&completion.content)?;
177 let (findings, dropped) =
178 crate::diff::validate_findings(&diff.text, parsed.findings, self.config().ai.max_findings);
180 let (findings, dropped) = crate::diff::validate_findings(
181 &diff.text,
182 parsed.findings,
183 self.config().ai.max_findings,
184 );
179185 if dropped > 0 {
180186 tracing::info!(dropped, "dropped ai findings outside changed lines");
181187 }
@@ -222,9 +228,7 @@
222228 .map_err(db_err)?;
223229 let now = OffsetDateTime::now_utc();
224230 let state = match verdict {
225 AiReviewVerdict::ChangesRequested => {
226 pull_request_review::ReviewState::ChangesRequested
227 }
231 AiReviewVerdict::ChangesRequested => pull_request_review::ReviewState::ChangesRequested,
228232 AiReviewVerdict::Commented => pull_request_review::ReviewState::Commented,
229233 };
230234 let review_id = Uuid::now_v7();
@@ -319,7 +323,9 @@
319323 .build_commit_diff(&space, &repo_name, commit_sha)
320324 .await
321325 .map_err(|e| AgentError::InvalidTask(format!("build diff: {e}")))?;
322 let lang = self.resolve_language(None, language.as_deref(), *repo_id).await;
326 let lang = self
327 .resolve_language(None, language.as_deref(), *repo_id)
328 .await;
323329 let ctx = self.review_context(&lang, &diff.text);
324330 let prompt = review_user_prompt(
325331 &repo_name,
@@ -459,7 +465,10 @@
459465 .merge_commits(
460466 space.clone(),
461467 repo_name.clone(),
462 &format!("refs/heads/{}", base_sha.clone().unwrap_or_else(|| "HEAD".to_string())),
468 &format!(
469 "refs/heads/{}",
470 base_sha.clone().unwrap_or_else(|| "HEAD".to_string())
471 ),
463472 head_sha,
464473 )
465474 .await
@@ -468,7 +477,9 @@
468477 let trimmed: Vec<_> = commits.into_iter().take(limit).collect();
469478 let commit_text = Self::format_commits(&trimmed);
470479 let prompt = summary_user_prompt(&repo_name, head_sha, &commit_text);
471 let lang = self.resolve_language(None, language.as_deref(), *repo_id).await;
480 let lang = self
481 .resolve_language(None, language.as_deref(), *repo_id)
482 .await;
472483 let ctx = self.repo_context(&lang, *repo_id).await;
473484 let completion = self
474485 .client
@@ -476,7 +487,8 @@
476487 .await?;
477488 let parsed: SummaryOutput = parse_output(&completion.content)?;
478489 let now = OffsetDateTime::now_utc();
479 let highlights = serde_json::to_value(&parsed.highlights).unwrap_or(serde_json::Value::Null);
490 let highlights =
491 serde_json::to_value(&parsed.highlights).unwrap_or(serde_json::Value::Null);
480492 let risks = serde_json::to_value(&parsed.risks).unwrap_or(serde_json::Value::Null);
481493 let existing = models::ai::repo_ai_summary::Entity::find()
482494 .filter(models::ai::repo_ai_summary::Column::RepoId.eq(*repo_id))
@@ -564,9 +576,10 @@
564576 None => Vec::new(),
565577 };
566578 let commit_text = Self::format_commits(&commits);
567 let prompt =
568 release_user_prompt(&repo_name, tag_name, from_sha.as_deref(), &commit_text);
569 let lang = self.resolve_language(None, language.as_deref(), *repo_id).await;
579 let prompt = release_user_prompt(&repo_name, tag_name, from_sha.as_deref(), &commit_text);
580 let lang = self
581 .resolve_language(None, language.as_deref(), *repo_id)
582 .await;
570583 let ctx = self.repo_context(&lang, *repo_id).await;
571584 let completion = self
572585 .client
@@ -603,7 +616,10 @@
603616 pub async fn record_release_request(&self, job_id: Uuid, request: serde_json::Value) {
604617 use models::ai::ai_job;
605618 use sea_orm::EntityTrait;
606 if let Ok(Some(row)) = ai_job::Entity::find_by_id(job_id).one(self.db_write()).await {
619 if let Ok(Some(row)) = ai_job::Entity::find_by_id(job_id)
620 .one(self.db_write())
621 .await
622 {
607623 let mut model: ai_job::ActiveModel = row.into();
608624 model.request_json = Set(Some(request));
609625 model.updated_at = Set(Some(OffsetDateTime::now_utc()));
@@ -625,4 +641,3 @@
625641fn db_err(error: sea_orm::DbErr) -> AgentError {
626642 AgentError::InvalidTask(error.to_string())
627643}
628
Modified lib/ci-protocol/src/ai.rs lib/ci-protocol/src/ai.rs +1 −1 View lib/ci-protocol/src/ai.rs
@@ -116,4 +116,4 @@
116116 pub fn decode(payload: &[u8]) -> Result<Self, serde_json::Error> {
117117 serde_json::from_slice(payload)
118118 }
119}
No newline at end of file
119}
Modified lib/ci-protocol/src/ai_languages.rs lib/ci-protocol/src/ai_languages.rs +1 −1 View lib/ci-protocol/src/ai_languages.rs
@@ -131,4 +131,4 @@
131131 return Err("language code must not be empty".to_string());
132132 }
133133 Ok(())
134}
No newline at end of file
134}
Modified lib/ci-protocol/src/lib.rs lib/ci-protocol/src/lib.rs +1 −1 View lib/ci-protocol/src/lib.rs
@@ -5,4 +5,4 @@
55pub mod runner;
66
77pub const PROTOCOL_VERSION: u32 = 1;
8pub const LOG_CHUNK_MAX_BYTES: usize = 262_144;
No newline at end of file
8pub const LOG_CHUNK_MAX_BYTES: usize = 262_144;
Modified lib/config/src/ai.rs lib/config/src/ai.rs +1 −1 View lib/config/src/ai.rs
@@ -121,4 +121,4 @@
121121 }
122122 Ok(())
123123 }
124}
No newline at end of file
124}
Modified lib/config/src/aihost.rs lib/config/src/aihost.rs +1 −1 View lib/config/src/aihost.rs
@@ -61,4 +61,4 @@
6161 }
6262 Ok(())
6363 }
64}
No newline at end of file
64}
Modified lib/config/src/health.rs lib/config/src/health.rs +1 −1 View lib/config/src/health.rs
@@ -61,4 +61,4 @@
6161 }
6262 Ok(())
6363 }
64}
No newline at end of file
64}
Modified lib/config/src/lib.rs lib/config/src/lib.rs +1 −1 View lib/config/src/lib.rs
@@ -125,4 +125,4 @@
125125 self.aihost.is_valid().map_err(ConfigError::Validation)?;
126126 Ok(())
127127 }
128}
No newline at end of file
128}
Modified lib/config/src/scoped.rs lib/config/src/scoped.rs +1 −2 View lib/config/src/scoped.rs
@@ -351,7 +351,6 @@
351351 }
352352}
353353
354
355354#[derive(Clone, Debug, Default, Deserialize)]
356355#[serde(default)]
357356pub struct AiHostConfig {
@@ -394,4 +393,4 @@
394393 self.aihost.is_valid()?;
395394 self.health.is_valid()
396395 }
397}
No newline at end of file
396}
Modified lib/git/src/handler/ai_review/list_commit_ai_reviews.rs lib/git/src/handler/ai_review/list_commit_ai_reviews.rs +1 −1 View lib/git/src/handler/ai_review/list_commit_ai_reviews.rs
@@ -34,4 +34,4 @@
3434 .await
3535 .map_err(GitApiError::from)?;
3636 Ok(AppResponseData::ok(out))
37}
No newline at end of file
37}
Modified lib/git/src/handler/ai_review/mod.rs lib/git/src/handler/ai_review/mod.rs +1 −1 View lib/git/src/handler/ai_review/mod.rs
@@ -1,2 +1,2 @@
11pub mod list_commit_ai_reviews;
2pub mod trigger_ai_review;
No newline at end of file
2pub mod trigger_ai_review;
Modified lib/git/src/handler/ai_review/trigger_ai_review.rs lib/git/src/handler/ai_review/trigger_ai_review.rs +1 −1 View lib/git/src/handler/ai_review/trigger_ai_review.rs
@@ -51,4 +51,4 @@
5151 .await
5252 .map_err(GitApiError::from)?;
5353 Ok(AppResponseData::ok(out))
54}
No newline at end of file
54}
Modified lib/git/src/handler/ai_summary/get_ai_summary.rs lib/git/src/handler/ai_summary/get_ai_summary.rs +1 −1 View lib/git/src/handler/ai_summary/get_ai_summary.rs
@@ -34,4 +34,4 @@
3434 .await
3535 .map_err(GitApiError::from)?;
3636 Ok(AppResponseData::ok(out))
37}
No newline at end of file
37}
Modified lib/git/src/handler/ai_summary/mod.rs lib/git/src/handler/ai_summary/mod.rs +1 −1 View lib/git/src/handler/ai_summary/mod.rs
@@ -1,2 +1,2 @@
11pub mod get_ai_summary;
2pub mod trigger_ai_summary;
No newline at end of file
2pub mod trigger_ai_summary;
Modified lib/git/src/handler/ai_summary/trigger_ai_summary.rs lib/git/src/handler/ai_summary/trigger_ai_summary.rs +1 −1 View lib/git/src/handler/ai_summary/trigger_ai_summary.rs
@@ -38,4 +38,4 @@
3838 .await
3939 .map_err(GitApiError::from)?;
4040 Ok(AppResponseData::ok(job_id))
41}
No newline at end of file
41}
Modified lib/git/src/handler/code_comments/create_code_comment.rs lib/git/src/handler/code_comments/create_code_comment.rs +1 −1 View lib/git/src/handler/code_comments/create_code_comment.rs
@@ -37,4 +37,4 @@
3737 .await
3838 .map_err(GitApiError::from)?;
3939 Ok(AppResponseData::ok(out))
40}
No newline at end of file
40}
Modified lib/git/src/handler/code_comments/list_code_comments.rs lib/git/src/handler/code_comments/list_code_comments.rs +1 −1 View lib/git/src/handler/code_comments/list_code_comments.rs
@@ -35,4 +35,4 @@
3535 .await
3636 .map_err(GitApiError::from)?;
3737 Ok(AppResponseData::ok(out))
38}
No newline at end of file
38}
Modified lib/git/src/handler/code_comments/mod.rs lib/git/src/handler/code_comments/mod.rs +1 −1 View lib/git/src/handler/code_comments/mod.rs
@@ -1,4 +1,4 @@
11pub mod create_code_comment;
22pub mod list_code_comments;
33pub mod modify;
4pub mod resolve_code_comment;
No newline at end of file
4pub mod resolve_code_comment;
Modified lib/git/src/handler/code_comments/modify.rs lib/git/src/handler/code_comments/modify.rs +9 −2 View lib/git/src/handler/code_comments/modify.rs
@@ -49,7 +49,14 @@
4949 .await
5050 .is_ok();
5151 let out = service
52 .update_code_comment(path.space_name, path.repo_name, path.comment_id, uid, admin, cmd)
52 .update_code_comment(
53 path.space_name,
54 path.repo_name,
55 path.comment_id,
56 uid,
57 admin,
58 cmd,
59 )
5360 .await
5461 .map_err(GitApiError::from)?;
5562 Ok(AppResponseData::ok(out))
@@ -90,4 +97,4 @@
9097 .await
9198 .map_err(GitApiError::from)?;
9299 Ok(AppResponseData::ok(NoData))
93}
No newline at end of file
100}
Modified lib/git/src/handler/code_comments/resolve_code_comment.rs lib/git/src/handler/code_comments/resolve_code_comment.rs +1 −1 View lib/git/src/handler/code_comments/resolve_code_comment.rs
@@ -63,4 +63,4 @@
6363 .await
6464 .map_err(GitApiError::from)?;
6565 Ok(AppResponseData::ok(out))
66}
No newline at end of file
66}
Modified lib/git/src/handler/releases/create_release.rs lib/git/src/handler/releases/create_release.rs +1 −1 View lib/git/src/handler/releases/create_release.rs
@@ -37,4 +37,4 @@
3737 .await
3838 .map_err(GitApiError::from)?;
3939 Ok(AppResponseData::ok(out))
40}
No newline at end of file
40}
Modified lib/git/src/handler/releases/delete_release.rs lib/git/src/handler/releases/delete_release.rs +1 −1 View lib/git/src/handler/releases/delete_release.rs
@@ -41,4 +41,4 @@
4141 .await
4242 .map_err(GitApiError::from)?;
4343 Ok(AppResponseData::ok(NoData))
44}
No newline at end of file
44}
Modified lib/git/src/handler/releases/get_release.rs lib/git/src/handler/releases/get_release.rs +1 −1 View lib/git/src/handler/releases/get_release.rs
@@ -41,4 +41,4 @@
4141 .await
4242 .map_err(GitApiError::from)?;
4343 Ok(AppResponseData::ok(out))
44}
No newline at end of file
44}
Modified lib/git/src/handler/releases/list_releases.rs lib/git/src/handler/releases/list_releases.rs +1 −1 View lib/git/src/handler/releases/list_releases.rs
@@ -35,4 +35,4 @@
3535 .await
3636 .map_err(GitApiError::from)?;
3737 Ok(AppResponseData::ok(out))
38}
No newline at end of file
38}
Modified lib/git/src/handler/releases/mod.rs lib/git/src/handler/releases/mod.rs +1 −1 View lib/git/src/handler/releases/mod.rs
@@ -3,4 +3,4 @@
33pub mod get_release;
44pub mod list_releases;
55pub mod redraft_release;
6pub mod update_release;
No newline at end of file
6pub mod update_release;
Modified lib/git/src/handler/releases/redraft_release.rs lib/git/src/handler/releases/redraft_release.rs +1 −1 View lib/git/src/handler/releases/redraft_release.rs
@@ -38,4 +38,4 @@
3838 .await
3939 .map_err(GitApiError::from)?;
4040 Ok(AppResponseData::ok(job_id))
41}
No newline at end of file
41}
Modified lib/git/src/handler/releases/update_release.rs lib/git/src/handler/releases/update_release.rs +1 −1 View lib/git/src/handler/releases/update_release.rs
@@ -45,4 +45,4 @@
4545 .await
4646 .map_err(GitApiError::from)?;
4747 Ok(AppResponseData::ok(out))
48}
No newline at end of file
48}
Modified lib/git/src/handler/ai_languages.rs lib/git/src/handler/ai_languages.rs +5 −4 View lib/git/src/handler/ai_languages.rs
@@ -44,9 +44,10 @@
4444 let display = ci_protocol::ai_languages::display_name(code);
4545 // display_name 形如「简体中文 (Simplified Chinese)」;拆回两段。
4646 match display.split_once(" (") {
47 Some((native, english)) => {
48 (native.to_string(), english.trim_end_matches(')').to_string())
49 }
47 Some((native, english)) => (
48 native.to_string(),
49 english.trim_end_matches(')').to_string(),
50 ),
5051 None => (display.clone(), display),
5152 }
5253 };
@@ -60,4 +61,4 @@
6061 })
6162 .collect();
6263 Ok(AppResponseData::ok(options))
63}
No newline at end of file
64}
Modified lib/git/src/service/ai_review.rs lib/git/src/service/ai_review.rs +8 −14 View lib/git/src/service/ai_review.rs
@@ -31,10 +31,7 @@
3131}
3232
3333impl CommitAiReviewDto {
34 pub(crate) fn from_row(
35 row: models::ai::ai_review_result::Model,
36 commit_sha: &str,
37 ) -> Self {
34 pub(crate) fn from_row(row: models::ai::ai_review_result::Model, commit_sha: &str) -> Self {
3835 let findings: Vec<models::ai::ai_review_result::AiFinding> =
3936 serde_json::from_value(row.findings_json).unwrap_or_default();
4037 Self {
@@ -103,17 +100,15 @@
103100 commit_sha: sha.clone(),
104101 language: match language.filter(|value| !value.trim().is_empty()) {
105102 Some(explicit) => Some(ci_protocol::ai_languages::normalize(&explicit)),
106 None => crate::sync::ai_language::actor_language(self.db_read(), Some(creator)).await,
103 None => {
104 crate::sync::ai_language::actor_language(self.db_read(), Some(creator)).await
105 }
107106 },
108107 };
109 let job_id = crate::sync::ai_task::submit_ai_task(
110 self.db_write(),
111 &self.state.redis,
112 cfg,
113 &task,
114 )
115 .await
116 .map_err(|e| GitError::Internal(format!("submit ai review: {e}")))?;
108 let job_id =
109 crate::sync::ai_task::submit_ai_task(self.db_write(), &self.state.redis, cfg, &task)
110 .await
111 .map_err(|e| GitError::Internal(format!("submit ai review: {e}")))?;
117112
118113 self.set_ai_review_status(
119114 space_name,
@@ -202,4 +197,3 @@
202197 .collect())
203198 }
204199}
205
Modified lib/git/src/service/ai_summary.rs lib/git/src/service/ai_summary.rs +10 −18 View lib/git/src/service/ai_summary.rs
@@ -85,11 +85,7 @@
8585 .await
8686 .map(|oid| oid.to_string())
8787 .map_err(crate::share::errors::map_baby)?;
88 let base_sha = match cmd
89 .base
90 .as_deref()
91 .filter(|value| !value.trim().is_empty())
92 {
88 let base_sha = match cmd.base.as_deref().filter(|value| !value.trim().is_empty()) {
9389 Some(base) => Some(
9490 self.baby(&ctx)
9591 .rev_parse(base)
@@ -105,19 +101,18 @@
105101 head_sha: head,
106102 base_sha,
107103 limit: cmd.limit,
108 language: match cmd.language.clone().filter(|value| !value.trim().is_empty()) {
104 language: match cmd
105 .language
106 .clone()
107 .filter(|value| !value.trim().is_empty())
108 {
109109 Some(explicit) => Some(ci_protocol::ai_languages::normalize(&explicit)),
110110 None => crate::sync::ai_language::actor_language(self.db_read(), actor).await,
111111 },
112112 };
113 crate::sync::ai_task::submit_ai_task(
114 self.db_write(),
115 &self.state.redis,
116 cfg,
117 &task,
118 )
119 .await
120 .map_err(|e| GitError::Internal(format!("submit ai summary: {e}")))
113 crate::sync::ai_task::submit_ai_task(self.db_write(), &self.state.redis, cfg, &task)
114 .await
115 .map_err(|e| GitError::Internal(format!("submit ai summary: {e}")))
121116 }
122117
123118 /// 该 head 上仍在排队/执行的总结作业。
@@ -127,9 +122,7 @@
127122 .filter(ai_job::Column::RepoId.eq(repo_id))
128123 .filter(ai_job::Column::Kind.eq(AiJobKind::RepoSummary))
129124 .filter(ai_job::Column::TargetRef.eq(head.to_string()))
130 .filter(
131 ai_job::Column::Status.is_in([AiJobStatus::Pending, AiJobStatus::Running]),
132 )
125 .filter(ai_job::Column::Status.is_in([AiJobStatus::Pending, AiJobStatus::Running]))
133126 .one(self.db_read())
134127 .await
135128 .ok()
@@ -163,4 +156,3 @@
163156 }
164157 }
165158}
166
Modified lib/git/src/service/code_comments.rs lib/git/src/service/code_comments.rs +6 −3 View lib/git/src/service/code_comments.rs
@@ -1,5 +1,5 @@
1use crate::context::facade::GitContext;
12use export::pagination::Page;
2use crate::context::facade::GitContext;
33use models::ai::code_comment;
44use sea_orm::{
55 ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter,
@@ -80,7 +80,11 @@
8080 let offset = query.offset.unwrap_or(0);
8181 let mut select =
8282 code_comment::Entity::find().filter(code_comment::Column::RepoId.eq(ctx.model.id));
83 if let Some(path) = query.path.as_deref().filter(|value| !value.trim().is_empty()) {
83 if let Some(path) = query
84 .path
85 .as_deref()
86 .filter(|value| !value.trim().is_empty())
87 {
8488 select = select.filter(code_comment::Column::Path.eq(path.trim()));
8589 }
8690 if let Some(revision) = query
@@ -309,4 +313,3 @@
309313 .collect())
310314 }
311315}
312
Modified lib/git/src/service/releases.rs lib/git/src/service/releases.rs +6 −12 View lib/git/src/service/releases.rs
@@ -1,5 +1,5 @@
1use crate::context::facade::GitContext;
12use export::pagination::Page;
2use crate::context::facade::GitContext;
33use models::repo::repo_release;
44use sea_orm::{
55 ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter,
@@ -83,8 +83,8 @@
8383 let ctx = self.context(space_name, repo_name).await?;
8484 let limit = query.limit.unwrap_or(20).clamp(1, 100);
8585 let offset = query.offset.unwrap_or(0);
86 let mut select = repo_release::Entity::find()
87 .filter(repo_release::Column::RepoId.eq(ctx.model.id));
86 let mut select =
87 repo_release::Entity::find().filter(repo_release::Column::RepoId.eq(ctx.model.id));
8888 if let Some(draft) = query.draft {
8989 select = select.filter(repo_release::Column::IsDraft.eq(draft));
9090 }
@@ -287,14 +287,9 @@
287287 to_sha: release.sha.clone(),
288288 language: crate::sync::ai_language::actor_language(self.db_read(), actor).await,
289289 };
290 crate::sync::ai_task::submit_ai_task(
291 self.db_write(),
292 &self.state.redis,
293 cfg,
294 &task,
295 )
296 .await
297 .map_err(|e| GitError::Internal(format!("submit release notes: {e}")))
290 crate::sync::ai_task::submit_ai_task(self.db_write(), &self.state.redis, cfg, &task)
291 .await
292 .map_err(|e| GitError::Internal(format!("submit release notes: {e}")))
298293 }
299294
300295 /// 读取发布记录实体(供 handler 组合 AI 起草等操作)。
@@ -364,4 +359,3 @@
364359 }
365360 Ok(())
366361}
367
Modified lib/git/src/smart/dispatch.rs lib/git/src/smart/dispatch.rs +7 −5 View lib/git/src/smart/dispatch.rs
@@ -130,11 +130,13 @@
130130 ctx.model.id,
131131 actor_id,
132132 bare.clone(),
133 service.ai_config().map(|cfg| crate::sync::post_receive::AiPushCtx {
134 db: service.git.state.database.clone(),
135 redis: service.git.state.redis.clone(),
136 config: cfg.clone(),
137 }),
133 service
134 .ai_config()
135 .map(|cfg| crate::sync::post_receive::AiPushCtx {
136 db: service.git.state.database.clone(),
137 redis: service.git.state.redis.clone(),
138 config: cfg.clone(),
139 }),
138140 );
139141 let stream = stream.map(|chunk| chunk.map_err(|e| axum::Error::new(e.to_string())));
140142 let stream = body_stream_with_post_receive(stream, post);
Modified lib/git/src/ssh/handler/channel.rs lib/git/src/ssh/handler/channel.rs +9 −9 View lib/git/src/ssh/handler/channel.rs
@@ -158,15 +158,15 @@
158158 let queue = self.service.smart.queue.clone();
159159 let sync_settings = self.service.sync_settings.clone();
160160 let ci_topic = self.service.smart.ci_event_topic().map(|t| t.to_string());
161 let ai_ctx = self
162 .service
163 .smart
164 .ai_config()
165 .map(|cfg| crate::sync::post_receive::AiPushCtx {
166 db: self.service.smart.git.state.database.clone(),
167 redis: self.service.smart.git.state.redis.clone(),
168 config: cfg.clone(),
169 });
161 let ai_ctx =
162 self.service
163 .smart
164 .ai_config()
165 .map(|cfg| crate::sync::post_receive::AiPushCtx {
166 db: self.service.smart.git.state.database.clone(),
167 redis: self.service.smart.git.state.redis.clone(),
168 config: cfg.clone(),
169 });
170170 let ssh_service = self.service.clone();
171171
172172 let db = self.service.smart.git.state.database.clone();
Modified lib/git/src/sync/ai_language.rs lib/git/src/sync/ai_language.rs +6 −2 View lib/git/src/sync/ai_language.rs
@@ -13,7 +13,11 @@
1313 .language
1414 .as_deref()
1515 .filter(|value| !value.trim().is_empty())
16 .or_else(|| row.locale.as_deref().filter(|value| !value.trim().is_empty()))?;
16 .or_else(|| {
17 row.locale
18 .as_deref()
19 .filter(|value| !value.trim().is_empty())
20 })?;
1721 let normalized = ci_protocol::ai_languages::normalize(raw);
1822 (!normalized.is_empty()).then_some(normalized)
19}
No newline at end of file
23}
Modified lib/git/src/sync/ai_task.rs lib/git/src/sync/ai_task.rs +19 −7 View lib/git/src/sync/ai_task.rs
@@ -114,7 +114,18 @@
114114 if is_zero_oid(new) {
115115 continue;
116116 }
117 match ensure_release_draft(conn, redis, cfg, repo_id, actor_id, language.clone(), tag, new).await {
117 match ensure_release_draft(
118 conn,
119 redis,
120 cfg,
121 repo_id,
122 actor_id,
123 language.clone(),
124 tag,
125 new,
126 )
127 .await
128 {
118129 Ok(Some(job_id)) => {
119130 tracing::debug!(%job_id, tag, "release draft queued");
120131 }
@@ -204,10 +215,7 @@
204215}
205216
206217/// 入队时的语言解析:调用方已解析过就直接用,避免重复查用户表。
207async fn resolve_language_for(
208 db: &DatabaseConnection,
209 actor_id: Option<Uuid>,
210) -> Option<String> {
218async fn resolve_language_for(db: &DatabaseConnection, actor_id: Option<Uuid>) -> Option<String> {
211219 crate::sync::ai_language::actor_language(db, actor_id).await
212220}
213221
@@ -249,7 +257,11 @@
249257 select = select.filter(git_commits::Column::Sha.ne(from.to_string()));
250258 }
251259 let _ = to;
252 select.count(db).await.map(|count| count as i32).unwrap_or(0)
260 select
261 .count(db)
262 .await
263 .map(|count| count as i32)
264 .unwrap_or(0)
253265}
254266
255267fn is_zero_oid(oid: &str) -> bool {
@@ -279,4 +291,4 @@
279291 AgentTask::RepoSummary { .. } => AiJobKind::RepoSummary,
280292 AgentTask::ReleaseNotes { .. } => AiJobKind::ReleaseNotes,
281293 }
282}
No newline at end of file
294}
Modified lib/git/src/sync/post_receive.rs lib/git/src/sync/post_receive.rs +5 −7 View lib/git/src/sync/post_receive.rs
@@ -150,7 +150,10 @@
150150 actor_id: Option<Uuid>,
151151 bare: &Path,
152152) -> Result<usize, EnqueueError> {
153 enqueue_push_impl(queue, settings, None, None, channel_id, repo_id, actor_id, bare).await
153 enqueue_push_impl(
154 queue, settings, None, None, channel_id, repo_id, actor_id, bare,
155 )
156 .await
154157}
155158
156159/// Enqueues the sync task and (optionally) publishes a CI push event from the
@@ -215,12 +218,7 @@
215218 .map(|r| (r.name.clone(), r.old_oid.clone(), r.new_oid.clone()))
216219 .collect();
217220 crate::sync::ai_task::trigger_push_ai_tasks(
218 &ai.db,
219 &ai.redis,
220 &ai.config,
221 repo_id,
222 actor_id,
223 &flat,
221 &ai.db, &ai.redis, &ai.config, repo_id, actor_id, &flat,
224222 )
225223 .await;
226224 }
Modified lib/git/src/routes.rs lib/git/src/routes.rs +16 −12 View lib/git/src/routes.rs
@@ -1,12 +1,8 @@
11use crate::handler::ai_languages::list_ai_languages;
22use crate::handler::ai_review::list_commit_ai_reviews::list_commit_ai_reviews;
3use crate::handler::ai_review::trigger_ai_review::trigger_commit_ai_review;
34use crate::handler::ai_summary::get_ai_summary::get_ai_summary;
45use crate::handler::ai_summary::trigger_ai_summary::trigger_ai_summary;
5use crate::handler::code_comments::create_code_comment::create_code_comment;
6use crate::handler::code_comments::list_code_comments::list_code_comments;
7use crate::handler::code_comments::modify::{delete_code_comment, update_code_comment};
8use crate::handler::code_comments::resolve_code_comment::{resolve_code_comment, unresolve_code_comment};
9use crate::handler::ai_review::trigger_ai_review::trigger_commit_ai_review;
106use crate::handler::analysis::code_activity::code_activity;
117use crate::handler::analysis::contributors::contributors;
128use crate::handler::analysis::languages::languages;
@@ -24,6 +20,12 @@
2420use crate::handler::branches::list::list_branches as branch_list;
2521use crate::handler::branches::rename::rename_branch as branch_rename;
2622use crate::handler::branches::set_default::set_default_branch as branch_set_default;
23use crate::handler::code_comments::create_code_comment::create_code_comment;
24use crate::handler::code_comments::list_code_comments::list_code_comments;
25use crate::handler::code_comments::modify::{delete_code_comment, update_code_comment};
26use crate::handler::code_comments::resolve_code_comment::{
27 resolve_code_comment, unresolve_code_comment,
28};
2729use crate::handler::commits::get::get_commit;
2830use crate::handler::commits::is_ancestor::is_ancestor;
2931use crate::handler::commits::list::list_commits;
@@ -61,12 +63,6 @@
6163use crate::handler::patches::generate::patch_generate;
6264use crate::handler::patches::parse::patch_parse;
6365use crate::handler::path_log::path_log;
64use crate::handler::releases::create_release::create_release;
65use crate::handler::releases::delete_release::delete_release;
66use crate::handler::releases::get_release::get_release;
67use crate::handler::releases::list_releases::list_releases;
68use crate::handler::releases::redraft_release::redraft_release;
69use crate::handler::releases::update_release::update_release;
7066use crate::handler::refs::branches::refs_branches;
7167use crate::handler::refs::delete::refs_delete;
7268use crate::handler::refs::filtered::refs_list_filtered as filtered;
@@ -76,6 +72,12 @@
7672use crate::handler::refs::list::refs_list;
7773use crate::handler::refs::resolve::refs_resolve;
7874use crate::handler::refs::update::refs_update;
75use crate::handler::releases::create_release::create_release;
76use crate::handler::releases::delete_release::delete_release;
77use crate::handler::releases::get_release::get_release;
78use crate::handler::releases::list_releases::list_releases;
79use crate::handler::releases::redraft_release::redraft_release;
80use crate::handler::releases::update_release::update_release;
7981use crate::handler::remotes::add::upsert_remote;
8082use crate::handler::remotes::clone_import::clone_import as remote_clone_import;
8183use crate::handler::remotes::fetch::fetch as remote_fetch;
@@ -207,7 +209,9 @@
207209 )
208210 .route(
209211 "/{space_name}/{repo_name}/releases/{tag}",
210 get(get_release).patch(update_release).delete(delete_release),
212 get(get_release)
213 .patch(update_release)
214 .delete(delete_release),
211215 )
212216 .route(
213217 "/{space_name}/{repo_name}/releases/{tag}/ai-draft",
Modified lib/models/src/ai/code_comment.rs lib/models/src/ai/code_comment.rs +1 −6 View lib/models/src/ai/code_comment.rs
@@ -29,12 +29,7 @@
2929 pub author: BelongsTo<super::super::users::user::Entity>,
3030 #[sea_orm(belongs_to, from = "resolved_by", to = "uid")]
3131 pub resolver: BelongsTo<Option<super::super::users::user::Entity>>,
32 #[sea_orm(
33 belongs_to,
34 relation_enum = "Parent",
35 from = "parent_id",
36 to = "id"
37 )]
32 #[sea_orm(belongs_to, relation_enum = "Parent", from = "parent_id", to = "id")]
3833 pub parent: BelongsTo<Option<super::code_comment::Entity>>,
3934}
4035
Modified lib/models/src/repo/mod.rs lib/models/src/repo/mod.rs +1 −1 View lib/models/src/repo/mod.rs
@@ -9,4 +9,4 @@
99pub mod repo_tag_protection_whitelists;
1010pub mod repo_topic;
1111pub mod repo_watch;
12pub mod repos;
No newline at end of file
12pub mod repos;
Modified lib/pulls/src/handlers/ai/get_ai_review.rs lib/pulls/src/handlers/ai/get_ai_review.rs +1 −1 View lib/pulls/src/handlers/ai/get_ai_review.rs
@@ -36,4 +36,4 @@
3636 .await?;
3737 let review = service.get_ai_review(&handle.pull, review_id).await?;
3838 Ok(AppResponseData::ok(review))
39}
No newline at end of file
39}
Modified lib/pulls/src/handlers/ai/list_ai_reviews.rs lib/pulls/src/handlers/ai/list_ai_reviews.rs +1 −1 View lib/pulls/src/handlers/ai/list_ai_reviews.rs
@@ -34,4 +34,4 @@
3434 .await?;
3535 let reviews = service.list_ai_reviews(&handle.pull).await?;
3636 Ok(AppResponseData::ok(reviews))
37}
No newline at end of file
37}
Modified lib/pulls/src/handlers/ai/mod.rs lib/pulls/src/handlers/ai/mod.rs +1 −1 View lib/pulls/src/handlers/ai/mod.rs
@@ -1,3 +1,3 @@
11pub mod get_ai_review;
22pub mod list_ai_reviews;
3pub mod trigger_ai_review;
No newline at end of file
3pub mod trigger_ai_review;
Modified lib/pulls/src/services/ai.rs lib/pulls/src/services/ai.rs +6 −12 View lib/pulls/src/services/ai.rs
@@ -4,9 +4,7 @@
44use models::ai::ai_job;
55use models::ai::ai_review_result::{self, AiFinding, AiReviewVerdict, Model as ReviewRow};
66use models::pull_request::{pull_request_comment, pull_requests};
7use sea_orm::{
8 ColumnTrait, EntityTrait, QueryFilter, QueryOrder,
9};
7use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder};
108use serde::{Deserialize, Serialize};
119use time::OffsetDateTime;
1210use utoipa::ToSchema;
@@ -81,14 +79,10 @@
8179 None => git::sync::actor_language(self.db_read(), actor).await,
8280 },
8381 };
84 let job_id = git::sync::ai_task::submit_ai_task(
85 self.db_write(),
86 &self.state.redis,
87 cfg,
88 &task,
89 )
90 .await
91 .map_err(|e| PullError::Internal(format!("submit ai review: {e}")))?;
82 let job_id =
83 git::sync::ai_task::submit_ai_task(self.db_write(), &self.state.redis, cfg, &task)
84 .await
85 .map_err(|e| PullError::Internal(format!("submit ai review: {e}")))?;
9286 Ok(AiReviewJobDto {
9387 job_id,
9488 status: "pending".to_string(),
@@ -187,4 +181,4 @@
187181 }
188182 Ok(out)
189183 }
190}
No newline at end of file
184}
Modified lib/pulls/src/services/events.rs lib/pulls/src/services/events.rs +8 −8 View lib/pulls/src/services/events.rs
@@ -163,7 +163,12 @@
163163 ///
164164 /// 独立于 `ci.enabled`:只看 `[ai]` 总开关与评审子开关,且投递失败不影响
165165 /// 事件写入与接口返回。
166 async fn publish_ai_event(&self, pull: &pull_requests::Model, actor: Option<Uuid>, event_type: &str) {
166 async fn publish_ai_event(
167 &self,
168 pull: &pull_requests::Model,
169 actor: Option<Uuid>,
170 event_type: &str,
171 ) {
167172 let cfg = &self.config().ai;
168173 if !cfg.review_on() {
169174 return;
@@ -183,13 +188,8 @@
183188 // 评审语言跟随触发者(推送/开 PR 的人)。
184189 language: git::sync::actor_language(self.db_read(), actor).await,
185190 };
186 git::sync::ai_task::submit_ai_task_logged(
187 self.db_write(),
188 &self.state.redis,
189 cfg,
190 &task,
191 )
192 .await;
191 git::sync::ai_task::submit_ai_task_logged(self.db_write(), &self.state.redis, cfg, &task)
192 .await;
193193 }
194194
195195 async fn pull_space_id(&self, repo_id: Uuid) -> Option<Uuid> {