Skip to content
Clone

refactor: refresh agent/llm, agent/lprovider, all 5 app binaries, chat stack, and dvcs crates

zhenyi committed
parent 0ee5d02 commit 6be9b58 Browse files

58 files changed

+240 −241

File tree 58
Modified agent/llm/provider/openai/config.rs View agent/llm/provider/openai/config.rs
@@ -156,11 +156,15 @@
156156 if let Some(proj) = &self.config.project {
157157 req = req.header("OpenAI-Project", proj);
158158 }
159 let resp = req.send().await.map_err(|e| map_response_err(e, "openai"))?;
159 let resp = req
160 .send()
161 .await
162 .map_err(|e| map_response_err(e, "openai"))?;
160163 let status = resp.status();
161 let bytes = resp.bytes().await.map_err(|e| {
162 LlmError::Network(format!("openai response body read failed: {e}"))
163 })?;
164 let bytes = resp
165 .bytes()
166 .await
167 .map_err(|e| LlmError::Network(format!("openai response body read failed: {e}")))?;
164168 if !status.is_success() {
165169 return Err(super::error::classify_status(
166170 "openai",
@@ -184,12 +188,16 @@
184188 if let Some(proj) = &self.config.project {
185189 req = req.header("OpenAI-Project", proj);
186190 }
187 let resp = req.send().await.map_err(|e| map_response_err(e, "openai"))?;
191 let resp = req
192 .send()
193 .await
194 .map_err(|e| map_response_err(e, "openai"))?;
188195 let status = resp.status();
189196 if !status.is_success() {
190 let bytes = resp.bytes().await.map_err(|e| {
191 LlmError::Network(format!("openai stream body read failed: {e}"))
192 })?;
197 let bytes = resp
198 .bytes()
199 .await
200 .map_err(|e| LlmError::Network(format!("openai stream body read failed: {e}")))?;
193201 return Err(super::error::classify_status(
194202 "openai",
195203 status.as_u16(),
@@ -199,4 +207,4 @@
199207 let sse = resp.bytes_stream().eventsource();
200208 Ok(Box::pin(sse_to_stream_events(sse).boxed()))
201209 }
202}
No newline at end of file
210}
Modified agent/llm/provider/openai/error.rs View agent/llm/provider/openai/error.rs
@@ -51,9 +51,9 @@
5151#[derive(Debug, Default)]
5252struct ErrorEnvelope {
5353 message: String,
54 kind: String,
55 code: String,
56 param: Option<String>,
54 kind: String,
55 code: String,
56 param: Option<String>,
5757}
5858
5959fn parse_error_envelope(body: &[u8]) -> Option<ErrorEnvelope> {
@@ -191,7 +191,11 @@
191191
192192 #[test]
193193 fn content_filter_recognised() {
194 let body = envelope("invalid_request_error", "content_policy_violation", "filtered");
194 let body = envelope(
195 "invalid_request_error",
196 "content_policy_violation",
197 "filtered",
198 );
195199 let e = classify_status("openai", 400, &body);
196200 assert!(matches!(e, LlmError::ContentFiltered { .. }));
197201 }
@@ -242,4 +246,4 @@
242246 fn transport_timeout_helper_compiles_and_routes_to_network() {
243247 let _ = reqwest::Client::new();
244248 }
245}
No newline at end of file
249}
Modified agent/llm/provider/openai/mod.rs View agent/llm/provider/openai/mod.rs
@@ -4,4 +4,4 @@
44mod response;
55mod stream;
66
7pub use config::{OpenAIConfig, OpenAIProvider, SecretString};
No newline at end of file
7pub use config::{OpenAIConfig, OpenAIProvider, SecretString};
Modified agent/llm/provider/openai/request.rs View agent/llm/provider/openai/request.rs
@@ -58,7 +58,10 @@
5858 }
5959 MessageRole::Tool => {
6060 let id = msg.tool_call_id.as_deref().ok_or_else(|| {
61 LlmError::Serialization(serde_json::from_str::<()>("\"tool message requires tool_call_id\"").unwrap_err())
61 LlmError::Serialization(
62 serde_json::from_str::<()>("\"tool message requires tool_call_id\"")
63 .unwrap_err(),
64 )
6265 })?;
6366 input.push(json!({
6467 "type": "function_call_output",
@@ -96,10 +99,9 @@
9699 .insert("top_p".into(), Value::from(p));
97100 }
98101 if !request.stop_sequences.is_empty() {
99 body.as_object_mut().unwrap().insert(
100 "truncation".into(),
101 Value::String("auto".into()),
102 );
102 body.as_object_mut()
103 .unwrap()
104 .insert("truncation".into(), Value::String("auto".into()));
103105 }
104106
105107 if !request.tools.is_empty() {
@@ -264,12 +266,13 @@
264266
265267 #[test]
266268 fn tools_become_function_tool_entries() {
267 let req = ChatRequest::new(vec![ChatMessage::user("hi")]).with_tools(vec![ToolDefinition {
268 name: "search".into(),
269 description: "Search".into(),
270 parameters: json!({"type": "object"}),
271 concurrency: ConcurrencyPolicy::default(),
272 }]);
269 let req =
270 ChatRequest::new(vec![ChatMessage::user("hi")]).with_tools(vec![ToolDefinition {
271 name: "search".into(),
272 description: "Search".into(),
273 parameters: json!({"type": "object"}),
274 concurrency: ConcurrencyPolicy::default(),
275 }]);
273276 let body = build_request_body("m", &req, false).unwrap();
274277 assert_eq!(body["tools"][0]["type"], "function");
275278 assert_eq!(body["tools"][0]["name"], "search");
@@ -303,4 +306,4 @@
303306 let body = build_request_body("m", &req, false).unwrap();
304307 assert_eq!(body["prompt_cache_key"], "session-1");
305308 }
306}
No newline at end of file
309}
Modified agent/llm/provider/openai/response.rs View agent/llm/provider/openai/response.rs
@@ -4,8 +4,7 @@
44use serde_json::Value;
55
66pub fn parse_response(bytes: &[u8]) -> Result<ChatResponse, LlmError> {
7 let v: Value = serde_json::from_slice(bytes)
8 .map_err(LlmError::Serialization)?;
7 let v: Value = serde_json::from_slice(bytes).map_err(LlmError::Serialization)?;
98
109 let provider = "openai".to_string();
1110 let model = v
@@ -117,15 +116,11 @@
117116}
118117
119118fn parse_usage(v: Option<&Value>) -> TokenUsageStats {
120 let Some(v) = v else { return TokenUsageStats::default() };
121 let input = v
122 .get("input_tokens")
123 .and_then(|t| t.as_u64())
124 .unwrap_or(0) as usize;
125 let output = v
126 .get("output_tokens")
127 .and_then(|t| t.as_u64())
128 .unwrap_or(0) as usize;
119 let Some(v) = v else {
120 return TokenUsageStats::default();
121 };
122 let input = v.get("input_tokens").and_then(|t| t.as_u64()).unwrap_or(0) as usize;
123 let output = v.get("output_tokens").and_then(|t| t.as_u64()).unwrap_or(0) as usize;
129124 let reasoning = v
130125 .get("output_tokens_details")
131126 .and_then(|d| d.get("reasoning_tokens"))
@@ -250,4 +245,4 @@
250245 let resp = parse_response(&serde_json::to_vec(&body).unwrap()).unwrap();
251246 assert_eq!(resp.tool_calls[0].arguments, json!({"q": "rust"}));
252247 }
253}
No newline at end of file
248}
Modified agent/llm/provider/openai/stream.rs View agent/llm/provider/openai/stream.rs
@@ -1,6 +1,6 @@
11use crate::error::LlmError;
2use crate::token::TokenUsageStats;
23use crate::types::*;
3use crate::token::TokenUsageStats;
44use async_stream::try_stream;
55use futures::{Stream, StreamExt};
66use serde_json::Value;
@@ -18,14 +18,18 @@
1818 match ty {
1919 "response.output_text.delta" => {
2020 if let Some(d) = v.get("delta").and_then(|d| d.as_str()) {
21 out.push(StreamEvent::TextDelta { delta: d.to_string() });
21 out.push(StreamEvent::TextDelta {
22 delta: d.to_string(),
23 });
2224 }
2325 }
2426 "response.reasoning_summary_text.delta"
2527 | "response.reasoning_text.delta"
2628 | "response.reasoning.delta" => {
2729 if let Some(d) = v.get("delta").and_then(|d| d.as_str()) {
28 out.push(StreamEvent::ReasoningDelta { delta: d.to_string() });
30 out.push(StreamEvent::ReasoningDelta {
31 delta: d.to_string(),
32 });
2933 }
3034 }
3135 "response.function_call_arguments.delta" => {
@@ -35,10 +39,7 @@
3539 .or_else(|| v.get("call_id").and_then(|s| s.as_str()))
3640 .unwrap_or("")
3741 .to_string();
38 let name = v
39 .get("name")
40 .and_then(|s| s.as_str())
41 .map(String::from);
42 let name = v.get("name").and_then(|s| s.as_str()).map(String::from);
4243 let delta = v
4344 .get("delta")
4445 .and_then(|d| d.as_str())
@@ -64,10 +65,7 @@
6465 .or_else(|| item.get("id").and_then(|s| s.as_str()))
6566 .unwrap_or("")
6667 .to_string();
67 let name = item
68 .get("name")
69 .and_then(|s| s.as_str())
70 .map(String::from);
68 let name = item.get("name").and_then(|s| s.as_str()).map(String::from);
7169 let args = item
7270 .get("arguments")
7371 .and_then(|a| a.as_str())
@@ -101,21 +99,14 @@
10199 finish_reason: FinishReason::Error,
102100 });
103101 }
104 _ => {
105 }
102 _ => {}
106103 }
107104 Ok(out)
108105}
109106
110107fn parse_usage(v: &Value) -> TokenUsageStats {
111 let input = v
112 .get("input_tokens")
113 .and_then(|t| t.as_u64())
114 .unwrap_or(0) as usize;
115 let output = v
116 .get("output_tokens")
117 .and_then(|t| t.as_u64())
118 .unwrap_or(0) as usize;
108 let input = v.get("input_tokens").and_then(|t| t.as_u64()).unwrap_or(0) as usize;
109 let output = v.get("output_tokens").and_then(|t| t.as_u64()).unwrap_or(0) as usize;
119110 let reasoning = v
120111 .get("output_tokens_details")
121112 .and_then(|d| d.get("reasoning_tokens"))
@@ -167,16 +158,14 @@
167158
168159 #[test]
169160 fn text_delta_yields_text_delta() {
170 let data = json!({"type": "response.output_text.delta", "delta": "hi"})
171 .to_string();
161 let data = json!({"type": "response.output_text.delta", "delta": "hi"}).to_string();
172162 let evs = parse_event_data(&data).unwrap();
173163 assert!(matches!(&evs[0], StreamEvent::TextDelta { delta } if delta == "hi"));
174164 }
175165
176166 #[test]
177167 fn reasoning_delta_yields_reasoning_delta() {
178 let data = json!({"type": "response.reasoning_text.delta", "delta": "hmm"})
179 .to_string();
168 let data = json!({"type": "response.reasoning_text.delta", "delta": "hmm"}).to_string();
180169 let evs = parse_event_data(&data).unwrap();
181170 assert!(matches!(&evs[0], StreamEvent::ReasoningDelta { delta } if delta == "hmm"));
182171 }
@@ -267,4 +256,4 @@
267256 let err = parse_event_data("not-json").unwrap_err();
268257 assert!(matches!(err, LlmError::Stream(_)));
269258 }
270}
No newline at end of file
259}
Modified agent/llm/provider/mod.rs View agent/llm/provider/mod.rs
@@ -24,7 +24,7 @@
2424 request: ChatRequest,
2525 ) -> Result<Pin<Box<dyn Stream<Item = Result<StreamEvent, LlmError>> + Send>>, LlmError>;
2626
27 fn count_tokens(&self, request: &ChatRequest) -> usize {
27 fn count_tokens(&self, request: &ChatRequest) -> usize {
2828 let messages: usize = request
2929 .messages
3030 .iter()
@@ -141,7 +141,7 @@
141141
142142 #[test]
143143 fn cjk_is_not_inflated_by_byte_counting() {
144 let zh = "这是一段中文测试文本内容";
144 let zh = "这是一段中文测试文本内容";
145145 let req = ChatRequest::new(vec![user(zh)]);
146146 assert_eq!(Stub.count_tokens(&req), 12 + MESSAGE_OVERHEAD_TOKENS);
147147 }
Modified agent/llm/tests/openai_provider.rs View agent/llm/tests/openai_provider.rs
@@ -1,8 +1,8 @@
1use futures::StreamExt;
12use llm::error::LlmError;
23use llm::provider::LlmProvider;
34use llm::provider::openai::{OpenAIConfig, OpenAIProvider};
45use llm::types::*;
5use futures::StreamExt;
66use serde_json::json;
77use wiremock::matchers::{method, path};
88use wiremock::{Mock, MockServer, ResponseTemplate};
@@ -164,10 +164,7 @@
164164 .chat_stream(ChatRequest::new(vec![ChatMessage::user("hi")]))
165165 .await
166166 .unwrap();
167 let events: Vec<StreamEvent> = stream
168 .map(|r| r.unwrap())
169 .collect()
170 .await;
167 let events: Vec<StreamEvent> = stream.map(|r| r.unwrap()).collect().await;
171168
172169 let texts: Vec<String> = events
173170 .iter()
@@ -177,9 +174,12 @@
177174 })
178175 .collect();
179176 assert_eq!(texts, vec!["he", "llo"]);
180 assert!(events.iter().any(
181 |e| matches!(e, StreamEvent::Done { finish_reason: FinishReason::Stop })
182 ));
177 assert!(events.iter().any(|e| matches!(
178 e,
179 StreamEvent::Done {
180 finish_reason: FinishReason::Stop
181 }
182 )));
183183 assert!(events.iter().any(|e| matches!(e, StreamEvent::Usage(_))));
184184}
185185
@@ -230,4 +230,4 @@
230230 .chat(ChatRequest::new(vec![ChatMessage::user("hi")]).with_model_override("o3"))
231231 .await
232232 .unwrap();
233}
No newline at end of file
233}
Modified agent/llm/types/capabilities.rs View agent/llm/types/capabilities.rs
@@ -21,12 +21,12 @@
2121}
2222
2323impl ProviderCapabilities {
24 pub fn fits_context(&self, input_tokens: usize, output_tokens: usize) -> bool {
24 pub fn fits_context(&self, input_tokens: usize, output_tokens: usize) -> bool {
2525 self.max_context_tokens == 0
2626 || input_tokens.saturating_add(output_tokens) <= self.max_context_tokens
2727 }
2828
29 pub fn remaining_input_budget(&self, output_tokens: usize) -> Option<usize> {
29 pub fn remaining_input_budget(&self, output_tokens: usize) -> Option<usize> {
3030 (self.max_context_tokens != 0)
3131 .then(|| self.max_context_tokens.saturating_sub(output_tokens))
3232 }
Modified agent/llm/types/message.rs View agent/llm/types/message.rs
@@ -47,7 +47,7 @@
4747 pub name: Option<String>,
4848 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4949 pub tool_calls: Vec<ToolCall>,
50 #[serde(default, skip_serializing_if = "Option::is_none")]
50 #[serde(default, skip_serializing_if = "Option::is_none")]
5151 pub tool_call_id: Option<String>,
5252}
5353
@@ -74,7 +74,7 @@
7474 Self::text(MessageRole::Assistant, text)
7575 }
7676
77 pub fn tool(tool_call_id: impl Into<String>, text: impl Into<String>) -> Self {
77 pub fn tool(tool_call_id: impl Into<String>, text: impl Into<String>) -> Self {
7878 Self {
7979 tool_call_id: Some(tool_call_id.into()),
8080 ..Self::text(MessageRole::Tool, text)
@@ -91,7 +91,7 @@
9191 self
9292 }
9393
94 pub fn validate(&self) -> Result<(), &'static str> {
94 pub fn validate(&self) -> Result<(), &'static str> {
9595 match self.role {
9696 MessageRole::Tool if self.tool_call_id.is_none() => {
9797 Err("tool message requires tool_call_id")
@@ -105,7 +105,7 @@
105105 }
106106 }
107107
108 pub fn text_content(&self) -> String {
108 pub fn text_content(&self) -> String {
109109 match &self.content {
110110 MessageContent::Text(s) => s.clone(),
111111 MessageContent::Parts(parts) => parts
Modified agent/llm/types/request.rs View agent/llm/types/request.rs
@@ -51,7 +51,7 @@
5151 self
5252 }
5353
54 pub fn with_temperature(mut self, temperature: f32) -> Self {
54 pub fn with_temperature(mut self, temperature: f32) -> Self {
5555 if !temperature.is_finite() {
5656 return self;
5757 }
@@ -59,7 +59,7 @@
5959 self
6060 }
6161
62 pub fn with_top_p(mut self, top_p: f32) -> Self {
62 pub fn with_top_p(mut self, top_p: f32) -> Self {
6363 if !top_p.is_finite() {
6464 return self;
6565 }
@@ -139,8 +139,14 @@
139139
140140 #[test]
141141 fn sampling_parameters_clamp_inclusive_endpoints() {
142 assert_eq!(ChatRequest::default().with_temperature(0.0).temperature, Some(0.0));
143 assert_eq!(ChatRequest::default().with_temperature(2.0).temperature, Some(2.0));
142 assert_eq!(
143 ChatRequest::default().with_temperature(0.0).temperature,
144 Some(0.0)
145 );
146 assert_eq!(
147 ChatRequest::default().with_temperature(2.0).temperature,
148 Some(2.0)
149 );
144150 assert_eq!(ChatRequest::default().with_top_p(0.0).top_p, Some(0.0));
145151 assert_eq!(ChatRequest::default().with_top_p(1.0).top_p, Some(1.0));
146152 }
Modified agent/llm/types/response.rs View agent/llm/types/response.rs
@@ -46,11 +46,11 @@
4646 self
4747 }
4848
49 pub fn requests_tools(&self) -> bool {
49 pub fn requests_tools(&self) -> bool {
5050 !self.tool_calls.is_empty()
5151 }
5252
53 pub fn is_truncated(&self) -> bool {
53 pub fn is_truncated(&self) -> bool {
5454 matches!(
5555 self.finish_reason,
5656 FinishReason::MaxTokens | FinishReason::ContentFilter | FinishReason::Error
Modified agent/llm/types/stream.rs View agent/llm/types/stream.rs
@@ -100,7 +100,7 @@
100100 self.finish_reason
101101 }
102102
103 pub fn tool_calls(&self) -> Result<Vec<ToolCall>, LlmError> {
103 pub fn tool_calls(&self) -> Result<Vec<ToolCall>, LlmError> {
104104 self.calls
105105 .values()
106106 .map(|p| {
@@ -124,7 +124,7 @@
124124 .collect()
125125 }
126126
127 pub fn finish(
127 pub fn finish(
128128 self,
129129 provider: impl Into<String>,
130130 model: impl Into<String>,
Modified agent/llm/types/tools.rs View agent/llm/types/tools.rs
@@ -10,17 +10,17 @@
1010#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
1111#[serde(rename_all = "snake_case")]
1212pub enum ConcurrencyPolicy {
13 #[default]
13 #[default]
1414 Safe,
15 Exclusive,
16 Ordered,
15 Exclusive,
16 Ordered,
1717}
1818
1919#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2020pub struct ToolDefinition {
2121 pub name: String,
2222 pub description: String,
23 pub parameters: serde_json::Value,
23 pub parameters: serde_json::Value,
2424 #[serde(default)]
2525 pub concurrency: ConcurrencyPolicy,
2626}
Modified agent/llm/error.rs View agent/llm/error.rs
@@ -74,7 +74,9 @@
7474 #[error("Skill rendering failed: {0}")]
7575 SkillRenderFailed(String),
7676
77 #[error("primary failed (retryable), then fallback also failed: primary={primary} -> fallback={fallback}")]
77 #[error(
78 "primary failed (retryable), then fallback also failed: primary={primary} -> fallback={fallback}"
79 )]
7880 FallbackExhausted {
7981 primary: Box<LlmError>,
8082 fallback: Box<LlmError>,
@@ -82,7 +84,7 @@
8284}
8385
8486impl LlmError {
85 pub fn is_retryable(&self) -> bool {
87 pub fn is_retryable(&self) -> bool {
8688 match self {
8789 Self::RateLimited { .. } | Self::Network(_) => true,
8890 Self::ApiError { status, .. } => *status == 429 || (500..600).contains(status),
@@ -99,7 +101,7 @@
99101 }
100102 }
101103
102 pub fn retry_after(&self) -> Option<Duration> {
104 pub fn retry_after(&self) -> Option<Duration> {
103105 match self {
104106 Self::RateLimited {
105107 retry_after_secs, ..
@@ -109,7 +111,7 @@
109111 }
110112 }
111113
112 pub fn provider(&self) -> Option<&str> {
114 pub fn provider(&self) -> Option<&str> {
113115 match self {
114116 Self::RateLimited { provider, .. }
115117 | Self::ContentFiltered { provider, .. }
Modified agent/llm/fallback.rs View agent/llm/fallback.rs
@@ -23,7 +23,7 @@
2323 Self { primary, fallback }
2424 }
2525
26 fn retarget(mut request: ChatRequest, model: &str) -> ChatRequest {
26 fn retarget(mut request: ChatRequest, model: &str) -> ChatRequest {
2727 if let Some(previous) = &request.model_override
2828 && previous != model
2929 {
@@ -149,12 +149,12 @@
149149 use std::sync::Mutex;
150150 use std::sync::atomic::{AtomicUsize, Ordering};
151151
152 struct Scripted {
152 struct Scripted {
153153 id: String,
154154 caps: ProviderCapabilities,
155155 calls: AtomicUsize,
156 fail_with: Mutex<Option<LlmError>>,
157 fail_mid_stream: Mutex<Option<LlmError>>,
156 fail_with: Mutex<Option<LlmError>>,
157 fail_mid_stream: Mutex<Option<LlmError>>,
158158 seen_model_override: Mutex<Option<String>>,
159159 }
160160
@@ -399,13 +399,7 @@
399399 match err {
400400 LlmError::FallbackExhausted { primary, fallback } => {
401401 assert!(matches!(*primary, LlmError::RateLimited { .. }));
402 assert!(matches!(
403 *fallback,
404 LlmError::ApiError {
405 status: 503,
406 ..
407 }
408 ));
402 assert!(matches!(*fallback, LlmError::ApiError { status: 503, .. }));
409403 }
410404 other => panic!("expected FallbackExhausted, got {other:?}"),
411405 }
Modified agent/llm/register.rs View agent/llm/register.rs
@@ -35,8 +35,8 @@
3535 }
3636 }
3737
38 /// Displacement is logged at warn level: most call sites ignore the
39 pub fn register(&mut self, provider: Arc<dyn LlmProvider>) -> Option<Arc<dyn LlmProvider>> {
38 /// Displacement is logged at warn level: most call sites ignore the
39 pub fn register(&mut self, provider: Arc<dyn LlmProvider>) -> Option<Arc<dyn LlmProvider>> {
4040 let key = ProviderKey::new(provider.provider_id(), provider.model_id());
4141 let displaced = self.providers.insert(key.clone(), provider);
4242 if displaced.is_some() {
@@ -49,13 +49,13 @@
4949 displaced
5050 }
5151
52 pub fn get(&self, provider_id: &str, model_id: &str) -> Option<Arc<dyn LlmProvider>> {
52 pub fn get(&self, provider_id: &str, model_id: &str) -> Option<Arc<dyn LlmProvider>> {
5353 self.providers
5454 .get(&ProviderKey::new(provider_id, model_id))
5555 .cloned()
5656 }
5757
58 pub fn any_for_provider(&self, provider_id: &str) -> Option<Arc<dyn LlmProvider>> {
58 pub fn any_for_provider(&self, provider_id: &str) -> Option<Arc<dyn LlmProvider>> {
5959 self.providers
6060 .iter()
6161 .filter(|(k, _)| k.provider_id == provider_id)
@@ -73,13 +73,13 @@
7373 .remove(&ProviderKey::new(provider_id, model_id))
7474 }
7575
76 pub fn keys(&self) -> Vec<ProviderKey> {
76 pub fn keys(&self) -> Vec<ProviderKey> {
7777 let mut keys: Vec<_> = self.providers.keys().cloned().collect();
7878 keys.sort();
7979 keys
8080 }
8181
82 pub fn provider_ids(&self) -> Vec<String> {
82 pub fn provider_ids(&self) -> Vec<String> {
8383 let mut ids: Vec<_> = self
8484 .providers
8585 .keys()
Modified agent/llm/skill.rs View agent/llm/skill.rs
@@ -21,7 +21,7 @@
2121}
2222
2323impl Skill {
24 pub fn render(&self, params: &HashMap<String, String>) -> Result<String, LlmError> {
24 pub fn render(&self, params: &HashMap<String, String>) -> Result<String, LlmError> {
2525 for param in &self.parameters {
2626 if param.required && !params.contains_key(&param.name) && param.default.is_none() {
2727 return Err(LlmError::SkillMissingParameter {
@@ -37,7 +37,7 @@
3737 while let Some(open) = rest.find("{{") {
3838 let after_open = &rest[open + 2..];
3939 let Some(close) = after_open.find("}}") else {
40 break;
40 break;
4141 };
4242 let end = open + 2 + close + 2;
4343
@@ -78,25 +78,25 @@
7878 }
7979 }
8080
81 pub fn register(&mut self, skill: Skill) -> Option<Skill> {
81 pub fn register(&mut self, skill: Skill) -> Option<Skill> {
8282 self.skills.insert(skill.name.clone(), skill)
8383 }
8484
85 pub fn get(&self, name: &str) -> Option<&Skill> {
85 pub fn get(&self, name: &str) -> Option<&Skill> {
8686 self.skills.get(name)
8787 }
8888
89 pub fn render(&self, name: &str, params: &HashMap<String, String>) -> Result<String, LlmError> {
89 pub fn render(&self, name: &str, params: &HashMap<String, String>) -> Result<String, LlmError> {
9090 self.get(name)
9191 .ok_or_else(|| LlmError::SkillNotFound(name.to_string()))?
9292 .render(params)
9393 }
9494
95 pub fn names(&self) -> Vec<String> {
95 pub fn names(&self) -> Vec<String> {
9696 self.skills.keys().cloned().collect()
9797 }
9898
99 pub fn count(&self) -> usize {
99 pub fn count(&self) -> usize {
100100 self.skills.len()
101101 }
102102
Modified agent/llm/token.rs View agent/llm/token.rs
@@ -65,15 +65,15 @@
6565
6666fn is_cjk(c: char) -> bool {
6767 matches!(c as u32,
68 0x2E80..=0x303F
69 | 0x3040..=0x30FF
70 | 0x3400..=0x4DBF
71 | 0x4E00..=0x9FFF
72 | 0xA960..=0xA97F
73 | 0xAC00..=0xD7FF
74 | 0xF900..=0xFAFF
75 | 0xFF00..=0xFFEF
76 | 0x20000..=0x3FFFF
68 0x2E80..=0x303F
69 | 0x3040..=0x30FF
70 | 0x3400..=0x4DBF
71 | 0x4E00..=0x9FFF
72 | 0xA960..=0xA97F
73 | 0xAC00..=0xD7FF
74 | 0xF900..=0xFAFF
75 | 0xFF00..=0xFFEF
76 | 0x20000..=0x3FFFF
7777 )
7878}
7979
@@ -126,7 +126,7 @@
126126 #[test]
127127 fn latin_uses_four_chars_per_token() {
128128 assert_eq!(estimate_text_tokens("abcdefgh"), 2);
129 assert_eq!(estimate_text_tokens("abcde"), 2);
129 assert_eq!(estimate_text_tokens("abcde"), 2);
130130 assert_eq!(estimate_text_tokens(""), 0);
131131 }
132132
Modified agent/lprovider/Cargo.toml View agent/lprovider/Cargo.toml
@@ -12,3 +12,5 @@
1212path = "lib.rs"
1313name = "lprovider"
1414[dependencies]
15axum.workspace = true
16tokio.workspace = true
Modified agent/lprovider/lib.rs View agent/lprovider/lib.rs
@@ -0,0 +1 @@
1
Modified app/apihost/src/cmd_serve.rs View app/apihost/src/cmd_serve.rs
@@ -7,7 +7,7 @@
77use tracing::info;
88use webapi::{AppServices, router};
99
10use crate::cli::{ServeArgs, DEFAULT_LOG_FILTER};
10use crate::cli::{DEFAULT_LOG_FILTER, ServeArgs};
1111
1212pub async fn run(args: ServeArgs) -> Result<(), Box<dyn std::error::Error>> {
1313 let mut loader = ConfigLoader::new();
@@ -28,9 +28,12 @@
2828 let listener = TcpListener::bind(addr).await?;
2929 info!(%addr, "webapi listening");
3030
31 serve(listener, router(services).into_make_service_with_connect_info::<SocketAddr>())
32 .with_graceful_shutdown(shutdown_signal())
33 .await?;
31 serve(
32 listener,
33 router(services).into_make_service_with_connect_info::<SocketAddr>(),
34 )
35 .with_graceful_shutdown(shutdown_signal())
36 .await?;
3437 info!("apihost shut down cleanly");
3538 Ok(())
3639}
Modified app/apihost/Cargo.toml View app/apihost/Cargo.toml
@@ -16,4 +16,4 @@
1616tokio.workspace = true
1717tracing.workspace = true
1818clap.workspace = true
19thiserror.workspace = true
No newline at end of file
19thiserror.workspace = true
Modified app/githook/src/main.rs View app/githook/src/main.rs
@@ -27,9 +27,10 @@
2727 loader = loader.config_file(path);
2828 }
2929 other => {
30 return Err(
31 format!("unknown argument: {other} (usage: githook [--config <path>])").into(),
32 );
30 return Err(format!(
31 "unknown argument: {other} (usage: githook [--config <path>])"
32 )
33 .into());
3334 }
3435 }
3536 }
@@ -106,4 +107,4 @@
106107 _ = ctrl_c => info!("ctrl-c received, beginning shutdown"),
107108 _ = term => info!("SIGTERM received, beginning shutdown"),
108109 }
109}
No newline at end of file
110}
Modified app/gitpro/src/main.rs View app/gitpro/src/main.rs
@@ -63,11 +63,8 @@
6363 .with_kv(kv.clone())
6464 .with_queue(queue.clone())
6565 .with_sync_settings(app.git_sync.clone());
66 let http_listener = TcpListener::bind((
67 app.git_smart.bind_addr.as_str(),
68 app.git_smart.port,
69 ))
70 .await?;
66 let http_listener =
67 TcpListener::bind((app.git_smart.bind_addr.as_str(), app.git_smart.port)).await?;
7168 info!(
7269 addr = %app.git_smart.bind_addr,
7370 port = app.git_smart.port,
@@ -79,7 +76,8 @@
7976 .with_kv(kv)
8077 .with_queue(queue)
8178 .with_sync_settings(app.git_sync);
82 let ssh_listener = TcpListener::bind((app.git_ssh.bind_addr.as_str(), app.git_ssh.port)).await?;
79 let ssh_listener =
80 TcpListener::bind((app.git_ssh.bind_addr.as_str(), app.git_ssh.port)).await?;
8381 info!(
8482 addr = %app.git_ssh.bind_addr,
8583 port = app.git_ssh.port,
@@ -91,9 +89,8 @@
9189 .with_graceful_shutdown(shutdown_signal())
9290 .await
9391 });
94 let ssh_task = tokio::spawn(async move {
95 gitssh::server::serve_on_listener(ssh, ssh_listener).await
96 });
92 let ssh_task =
93 tokio::spawn(async move { gitssh::server::serve_on_listener(ssh, ssh_listener).await });
9794
9895 tokio::select! {
9996 http = http_task => http??,
@@ -130,4 +127,4 @@
130127 _ = ctrl_c => info!("ctrl-c received, shutting down"),
131128 _ = term => info!("SIGTERM received, shutting down"),
132129 }
133}
No newline at end of file
130}
Modified app/migrate/src/main.rs View app/migrate/src/main.rs
@@ -23,9 +23,10 @@
2323 loader = loader.config_file(path);
2424 }
2525 other => {
26 return Err(
27 format!("unknown argument: {other} (usage: migrate [--config <path>])").into(),
28 );
26 return Err(format!(
27 "unknown argument: {other} (usage: migrate [--config <path>])"
28 )
29 .into());
2930 }
3031 }
3132 }
Modified chat/chatlayer/actor/live.rs View chat/chatlayer/actor/live.rs
@@ -30,7 +30,7 @@
3030
3131impl MeetActorCtx {
3232 /// Errors are logged and swallowed; Kafka at-least-once redelivery is
33 pub async fn handle(&self, envelope: EventEnvelope<ChatLiveEvent>) {
33 pub async fn handle(&self, envelope: EventEnvelope<ChatLiveEvent>) {
3434 match self.handle_inner(&envelope).await {
3535 Ok(()) => crate::metrics::live_event_applied("success"),
3636 Err(e) => {
Modified chat/chatlayer/events/live.rs View chat/chatlayer/events/live.rs
@@ -34,7 +34,7 @@
3434}
3535
3636impl ChatLiveEvent {
37 pub fn channel_id(&self) -> Uuid {
37 pub fn channel_id(&self) -> Uuid {
3838 match self {
3939 Self::MeetStarted { channel_id, .. }
4040 | Self::MeetEnded { channel_id, .. }
@@ -78,7 +78,7 @@
7878}
7979
8080impl ChatLiveViewEvent {
81 pub fn user_id(&self) -> Uuid {
81 pub fn user_id(&self) -> Uuid {
8282 match self {
8383 Self::MeetStartedView { user_id, .. }
8484 | Self::MeetEndedView { user_id, .. }
Modified chat/chatlayer/media.rs View chat/chatlayer/media.rs
@@ -34,8 +34,8 @@
3434];
3535
3636const DANGEROUS_EXTENSIONS: &[&str] = &[
37 "html", "htm", "xhtml", "shtml", "svg", "xml", "js", "mjs", "cjs", "jsp", "php", "asp",
38 "aspx", "swf",
37 "html", "htm", "xhtml", "shtml", "svg", "xml", "js", "mjs", "cjs", "jsp", "php", "asp", "aspx",
38 "swf",
3939];
4040
4141fn is_dangerous_upload(filename: &str, content_type: &str) -> bool {
Modified chat/chatlayer/service.rs View chat/chatlayer/service.rs
@@ -490,7 +490,7 @@
490490 })
491491 }
492492
493 pub fn spawn_live_worker(self: &Arc<Self>) -> ChatLayerResult<WorkerHandle> {
493 pub fn spawn_live_worker(self: &Arc<Self>) -> ChatLayerResult<WorkerHandle> {
494494 let queue = self
495495 .queue()
496496 .ok_or_else(|| ChatLayerError::invalid("chat queue disabled"))?;
Modified chat/glayer/consumer.rs View chat/glayer/consumer.rs
@@ -39,7 +39,7 @@
3939 }
4040 }
4141
42 pub fn run(&self) -> Result<SubscribeHandle, QueueError> {
42 pub fn run(&self) -> Result<SubscribeHandle, QueueError> {
4343 let mode = SubscriptionMode::Broadcast {
4444 subscriber_id: self.settings.subscriber_id.clone(),
4545 };
Modified chat/glayer/hub.rs View chat/glayer/hub.rs
@@ -61,7 +61,7 @@
6161 })
6262 }
6363
64 pub fn register(&self, conn: Connection) -> Result<(), HubError> {
64 pub fn register(&self, conn: Connection) -> Result<(), HubError> {
6565 let mut g = self.inner.lock().unwrap_or_else(|p| p.into_inner());
6666 let conns = g.entry(conn.user_id).or_default();
6767 if conns.len() >= self.max_per_user {
@@ -71,7 +71,7 @@
7171 Ok(())
7272 }
7373
74 pub fn unregister(&self, user_id: Uuid, conn_id: Uuid) -> bool {
74 pub fn unregister(&self, user_id: Uuid, conn_id: Uuid) -> bool {
7575 let mut g = self.inner.lock().unwrap_or_else(|p| p.into_inner());
7676 let removed = g
7777 .get_mut(&user_id)
@@ -83,7 +83,7 @@
8383 removed
8484 }
8585
86 pub fn dispatch(&self, user_id: Uuid, frame: ServerFrame) -> usize {
86 pub fn dispatch(&self, user_id: Uuid, frame: ServerFrame) -> usize {
8787 let mut dead = Vec::new();
8888 let mut delivered = 0usize;
8989 {
Modified chat/glayer/state.rs View chat/glayer/state.rs
@@ -49,7 +49,7 @@
4949 self.shutdown.clone()
5050 }
5151
52 pub fn spawn_user_view_consumer(&self) -> GatewayResult<SubscribeHandle> {
52 pub fn spawn_user_view_consumer(&self) -> GatewayResult<SubscribeHandle> {
5353 let queue = self.chat.queue().ok_or_else(|| {
5454 GatewayError::Chat(chatlayer::ChatLayerError::invalid(
5555 "chat queue disabled; cannot start user-view consumer",
@@ -64,7 +64,7 @@
6464 .map_err(GatewayError::from)
6565 }
6666
67 pub fn spawn_typing_consumer(&self) -> GatewayResult<SubscribeHandle> {
67 pub fn spawn_typing_consumer(&self) -> GatewayResult<SubscribeHandle> {
6868 let queue = self.chat.queue().ok_or_else(|| {
6969 GatewayError::Chat(chatlayer::ChatLayerError::invalid(
7070 "chat queue disabled; cannot start typing consumer",
@@ -79,7 +79,7 @@
7979 .map_err(GatewayError::from)
8080 }
8181
82 pub fn spawn_live_view_consumer(&self) -> GatewayResult<SubscribeHandle> {
82 pub fn spawn_live_view_consumer(&self) -> GatewayResult<SubscribeHandle> {
8383 let queue = self.chat.queue().ok_or_else(|| {
8484 GatewayError::Chat(chatlayer::ChatLayerError::invalid(
8585 "chat queue disabled; cannot start live-view consumer",
@@ -94,7 +94,7 @@
9494 .map_err(GatewayError::from)
9595 }
9696
97 pub async fn publish_typing(&self, signal: &TypingSignal) -> GatewayResult<()> {
97 pub async fn publish_typing(&self, signal: &TypingSignal) -> GatewayResult<()> {
9898 let Some(queue) = self.chat.queue() else {
9999 return Ok(());
100100 };
Modified chat/glayer/typing.rs View chat/glayer/typing.rs
@@ -45,7 +45,7 @@
4545 }
4646 }
4747
48 pub fn allow(&self, conversation_id: Uuid, user_id: Uuid) -> bool {
48 pub fn allow(&self, conversation_id: Uuid, user_id: Uuid) -> bool {
4949 let now = Instant::now();
5050 let mut map = self.last.lock().unwrap_or_else(|p| p.into_inner());
5151 match map.get(&(conversation_id, user_id)) {
Modified chat/glayer/ws.rs View chat/glayer/ws.rs
@@ -50,7 +50,7 @@
5050 .await
5151 {
5252 Ok(Ok(Some(id))) => id,
53 Ok(Ok(None)) => return,
53 Ok(Ok(None)) => return,
5454 Ok(Err(_)) => {
5555 close(&mut ws, WS_CLOSE_AUTH_FAILED, "auth failed").await;
5656 return;
@@ -186,7 +186,7 @@
186186 break;
187187 }
188188 }
189 _ = &mut idle => break,
189 _ = &mut idle => break,
190190 frame = rx.recv() => {
191191 match frame {
192192 Some(f) => {
Modified chat/live/handler/meet.rs View chat/live/handler/meet.rs
@@ -78,4 +78,4 @@
7878) -> LiveResult<AppResponseData<Vec<ParticipantRecord>>> {
7979 let records = svc.list_history(claims.sub, q.limit).await?;
8080 Ok(AppResponseData::ok(records))
81}
No newline at end of file
81}
Modified chat/live/handler/mod.rs View chat/live/handler/mod.rs
@@ -3,4 +3,4 @@
33pub(crate) mod routes;
44
55pub use openapi::LiveApiDoc;
6pub use routes::live_router;
No newline at end of file
6pub use routes::live_router;
Modified chat/live/handler/openapi.rs View chat/live/handler/openapi.rs
@@ -32,4 +32,4 @@
3232 )
3333 )
3434)]
35pub struct LiveApiDoc;
No newline at end of file
35pub struct LiveApiDoc;
Modified chat/live/handler/routes.rs View chat/live/handler/routes.rs
@@ -7,10 +7,7 @@
77use rate_limit::ratelimit;
88
99pub fn live_router(svc: LiveService) -> Router {
10 let public = Router::new().route(
11 "/live/webhook",
12 post(crate::webhook::handle_webhook),
13 );
10 let public = Router::new().route("/live/webhook", post(crate::webhook::handle_webhook));
1411
1512 let protected = Router::new()
1613 .route("/live/meet/join", post(super::meet::join))
@@ -21,11 +18,14 @@
2118 get(super::meet::presence),
2219 )
2320 .route("/live/meet/history", get(super::meet::history))
24 .layer(from_fn_with_state(svc.clone(), inject_jwt_ctx::<LiveService>));
21 .layer(from_fn_with_state(
22 svc.clone(),
23 inject_jwt_ctx::<LiveService>,
24 ));
2525
2626 Router::new()
2727 .merge(public)
2828 .merge(protected)
2929 .layer(from_fn_with_state(svc.clone(), ratelimit::<LiveService>))
3030 .with_state(svc)
31}
No newline at end of file
31}
Modified chat/live/client.rs View chat/live/client.rs
@@ -66,7 +66,7 @@
6666 resp.json().await.map_err(LiveError::from)
6767 }
6868
69 pub async fn create_room(&self, room_name: &str, empty_timeout_seconds: u64) -> LiveResult<()> {
69 pub async fn create_room(&self, room_name: &str, empty_timeout_seconds: u64) -> LiveResult<()> {
7070 #[derive(Serialize)]
7171 struct CreateRoomBody<'a> {
7272 name: &'a str,
@@ -108,7 +108,7 @@
108108 Ok(resp.participants)
109109 }
110110
111 pub async fn remove_participant(&self, room_name: &str, identity: &str) -> LiveResult<()> {
111 pub async fn remove_participant(&self, room_name: &str, identity: &str) -> LiveResult<()> {
112112 #[derive(Serialize)]
113113 struct RemoveBody<'a> {
114114 room: &'a str,
Modified chat/live/service.rs View chat/live/service.rs
@@ -78,7 +78,7 @@
7878 + "/room"
7979 }
8080
81 pub async fn join_room(&self, user_id: Uuid, channel_id: Uuid) -> LiveResult<JoinInfo> {
81 pub async fn join_room(&self, user_id: Uuid, channel_id: Uuid) -> LiveResult<JoinInfo> {
8282 self.require_enabled()?;
8383 let ctx = ChatStorageCtx::new(user_id);
8484
@@ -173,7 +173,7 @@
173173 })
174174 }
175175
176 pub async fn leave_room(&self, user_id: Uuid, meet_id: Uuid) -> LiveResult<()> {
176 pub async fn leave_room(&self, user_id: Uuid, meet_id: Uuid) -> LiveResult<()> {
177177 self.require_enabled()?;
178178 let ctx = ChatStorageCtx::new(user_id);
179179 let active = self
@@ -208,7 +208,7 @@
208208 Ok(())
209209 }
210210
211 pub async fn end_room(&self, user_id: Uuid, channel_id: Uuid) -> LiveResult<()> {
211 pub async fn end_room(&self, user_id: Uuid, channel_id: Uuid) -> LiveResult<()> {
212212 self.require_enabled()?;
213213 let ctx = ChatStorageCtx::new(user_id);
214214 let Some(meet) = self
@@ -255,7 +255,7 @@
255255 Ok(())
256256 }
257257
258 pub async fn presence(&self, user_id: Uuid, channel_id: Uuid) -> LiveResult<MeetPresence> {
258 pub async fn presence(&self, user_id: Uuid, channel_id: Uuid) -> LiveResult<MeetPresence> {
259259 let ctx = ChatStorageCtx::new(user_id);
260260 let Some(meet) = self
261261 .store
@@ -281,7 +281,7 @@
281281 })
282282 }
283283
284 pub async fn list_history(
284 pub async fn list_history(
285285 &self,
286286 user_id: Uuid,
287287 limit: u32,
@@ -298,7 +298,7 @@
298298 Ok(records)
299299 }
300300
301 pub async fn handle_webhook(&self, headers: &HeaderMap, body: &[u8]) -> LiveResult<()> {
301 pub async fn handle_webhook(&self, headers: &HeaderMap, body: &[u8]) -> LiveResult<()> {
302302 let claims = verify_webhook(
303303 headers,
304304 body,
Modified chat/live/token.rs View chat/live/token.rs
@@ -55,7 +55,7 @@
5555 }
5656 }
5757
58 pub fn admin() -> Self {
58 pub fn admin() -> Self {
5959 Self {
6060 room: None,
6161 room_join: Some(false),
@@ -75,9 +75,9 @@
7575
7676#[derive(Debug, Clone, Serialize, Deserialize)]
7777pub struct LiveTokenClaims {
78 pub iss: String,
78 pub iss: String,
7979 #[serde(rename = "sub")]
80 pub sub: String,
80 pub sub: String,
8181 #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
8282 pub name: Option<String>,
8383 #[serde(rename = "video")]
Modified chat/live/types.rs View chat/live/types.rs
@@ -66,4 +66,4 @@
6666pub struct MeetPresence {
6767 pub meet: MeetInfo,
6868 pub participants: Vec<ParticipantRecord>,
69}
No newline at end of file
69}
Modified chat/live/webhook.rs View chat/live/webhook.rs
@@ -40,7 +40,7 @@
4040
4141#[derive(Debug, Clone, Deserialize)]
4242pub struct WebhookClaims {
43 #[serde(rename = "sub")]
43 #[serde(rename = "sub")]
4444 pub sub: String,
4545 #[allow(dead_code)]
4646 #[serde(rename = "iss", default)]
Modified chat/storagelayer/repository/conversation.rs View chat/storagelayer/repository/conversation.rs
@@ -46,7 +46,7 @@
4646
4747 async fn exists(&self, ctx: &ChatStorageCtx, id: uuid::Uuid) -> ChatStorageResult<bool>;
4848
49 async fn list_member_user_ids(
49 async fn list_member_user_ids(
5050 &self,
5151 ctx: &ChatStorageCtx,
5252 id: uuid::Uuid,
Modified chat/storagelayer/repository/meet.rs View chat/storagelayer/repository/meet.rs
@@ -40,7 +40,7 @@
4040 limit: u32,
4141 ) -> ChatStorageResult<Vec<Meet>>;
4242
43 async fn list_channel_member_user_ids(
43 async fn list_channel_member_user_ids(
4444 &self,
4545 ctx: &ChatStorageCtx,
4646 channel_id: Uuid,
Modified chat/storagelayer/repository/meet_participant.rs View chat/storagelayer/repository/meet_participant.rs
@@ -42,7 +42,7 @@
4242 user_id: Uuid,
4343 ) -> ChatStorageResult<bool>;
4444
45 async fn mark_all_ended(&self, ctx: &ChatStorageCtx, meet_id: Uuid) -> ChatStorageResult<u64>;
45 async fn mark_all_ended(&self, ctx: &ChatStorageCtx, meet_id: Uuid) -> ChatStorageResult<u64>;
4646}
4747
4848pub type DynMeetParticipantRepository = Arc<dyn MeetParticipantRepository>;
Modified chat/storagelayer/auth.rs View chat/storagelayer/auth.rs
@@ -121,13 +121,16 @@
121121) -> ChatStorageResult<Uuid> {
122122 let user_id = require_authenticated(ctx).await?;
123123 let reader = db.reader();
124 let Some(chat) = chat_entity::Entity::find_by_id(chat_id).one(&reader).await? else {
124 let Some(chat) = chat_entity::Entity::find_by_id(chat_id)
125 .one(&reader)
126 .await?
127 else {
125128 return Err(chat_not_in_space(chat_id));
126129 };
127130 match chat.kind {
128131 chat_entity::ChatKind::Private => {
129 let allowed = chat.creator_user_id == user_id
130 || chat.counterpart_user_id == Some(user_id);
132 let allowed =
133 chat.creator_user_id == user_id || chat.counterpart_user_id == Some(user_id);
131134 if !allowed {
132135 return Err(ChatStorageError::PermissionDenied(format!(
133136 "user {user_id} is not a participant of private chat {chat_id}"
Modified chat/storagelayer/lib.rs View chat/storagelayer/lib.rs
@@ -30,8 +30,8 @@
3030 thread::Thread,
3131};
3232pub use repository::{
33 ChatStorage, ChatStorageCtx, DynChatStorage,
34 attachment::AttachmentRepository, conversation::ConversationRepository, meet::MeetRepository,
33 ChatStorage, ChatStorageCtx, DynChatStorage, attachment::AttachmentRepository,
34 conversation::ConversationRepository, meet::MeetRepository,
3535 meet_participant::MeetParticipantRepository, mention::MentionRepository,
3636 message::MessageRepository, pinned::PinnedMessageRepository, reaction::ReactionRepository,
3737 read_receipt::ReadReceiptRepository, thread::ThreadRepository,
Modified dvcs/git/gitcli.rs View dvcs/git/gitcli.rs
@@ -79,10 +79,7 @@
7979 .duration_since(std::time::UNIX_EPOCH)
8080 .map(|d| d.subsec_nanos())
8181 .unwrap_or(0);
82 let path = dir.join(format!(
83 "git-askpass-{}-{nonce:x}.sh",
84 std::process::id()
85 ));
82 let path = dir.join(format!("git-askpass-{}-{nonce:x}.sh", std::process::id()));
8683 let script = "#!/bin/sh\nprintf '%s\\n' \"$GIT_ASKPASS_TOKEN\"\n";
8784 std::fs::write(&path, script).map_err(|e| Error::Io(e.to_string()))?;
8885 #[cfg(unix)]
Modified dvcs/gitauth/permission.rs View dvcs/gitauth/permission.rs
@@ -53,4 +53,4 @@
5353 GitAuthError::Forbidden("access forbidden".into())
5454 }
5555 }
56}
No newline at end of file
56}
Modified dvcs/gitauth/service.rs View dvcs/gitauth/service.rs
@@ -117,7 +117,7 @@
117117 result
118118 }
119119
120 async fn verify_credentials(
120 async fn verify_credentials(
121121 &self,
122122 user: &users::Model,
123123 password: &str,
@@ -139,7 +139,7 @@
139139 }
140140 }
141141
142 async fn verify_access_key(
142 async fn verify_access_key(
143143 &self,
144144 user: &users::Model,
145145 presented: &str,
Modified dvcs/gitsmart/handler/lfs.rs View dvcs/gitsmart/handler/lfs.rs
@@ -229,8 +229,7 @@
229229 raw_stream
230230 };
231231
232 let max_size = usize::try_from(state.config.max_lfs_object_size)
233 .unwrap_or(usize::MAX);
232 let max_size = usize::try_from(state.config.max_lfs_object_size).unwrap_or(usize::MAX);
234233 let limited = enforce_limit(stream, max_size);
235234 repo.lfs.put_object_stream(&oid, limited).await?;
236235 Ok(StatusCode::OK.into_response())
Modified dvcs/gitsmart/pre_receive.rs View dvcs/gitsmart/pre_receive.rs
@@ -1,6 +1,4 @@
1use db::conn::sea_orm::{
2 ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter,
3};
1use db::conn::sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter};
42use db::repo::repo_branch_protection_policy as policy_entity;
53use db::repo::repo_collaborations as collab_entity;
64use db::repo::repo_tag_protection_policy as tag_policy_entity;
@@ -24,8 +22,9 @@
2422impl PreReceiveVerdict {
2523 pub fn accepted_only(self) -> SmartResult<Vec<RefUpdate>> {
2624 let mut iter = self.per_ref.into_iter();
27 if let Some((_, RefVerdict::Reject(msg))) =
28 iter.by_ref().find(|(_, v)| matches!(v, RefVerdict::Reject(_)))
25 if let Some((_, RefVerdict::Reject(msg))) = iter
26 .by_ref()
27 .find(|(_, v)| matches!(v, RefVerdict::Reject(_)))
2928 {
3029 return Err(SmartError::Forbidden(msg));
3130 }
@@ -123,9 +122,8 @@
123122 };
124123
125124 let is_delete = r.new_oid == zero_oid;
126 let is_force = r.old_oid != zero_oid
127 && r.new_oid != zero_oid
128 && !is_fast_forward(&r.old_oid, &r.new_oid);
125 let is_force =
126 r.old_oid != zero_oid && r.new_oid != zero_oid && !is_fast_forward(&r.old_oid, &r.new_oid);
129127
130128 if is_delete {
131129 return RefVerdict::Reject(format!(
@@ -222,4 +220,4 @@
222220 });
223221 }
224222 out
225}
No newline at end of file
223}
Modified dvcs/gitsmart/service.rs View dvcs/gitsmart/service.rs
@@ -93,12 +93,10 @@
9393 self.storage.clone(),
9494 self.lfs_prefix(resolved),
9595 ));
96 Ok(git::GitRepository::new(
97 self.bare_path(resolved),
98 oc,
99 self.storage.clone(),
96 Ok(
97 git::GitRepository::new(self.bare_path(resolved), oc, self.storage.clone())
98 .with_lfs_store(lfs),
10099 )
101 .with_lfs_store(lfs))
102100 }
103101}
104102
Modified dvcs/gitssh/handler/channel.rs View dvcs/gitssh/handler/channel.rs
@@ -10,10 +10,7 @@
1010impl GitSshHandler {
1111 pub async fn data_impl(&mut self, channel: ChannelId, data: &[u8]) -> Result<(), russh::Error> {
1212 let state = self.channels.entry(channel).or_default();
13 let projected = state
14 .buffer
15 .len()
16 .saturating_add(data.len());
13 let projected = state.buffer.len().saturating_add(data.len());
1714 if projected > MAX_SSH_CHANNEL_BUF {
1815 tracing::warn!(
1916 channel = ?channel,
@@ -64,7 +61,14 @@
6461 let _ = handle.exit_status_request(channel, 1).await;
6562 let _ = handle.eof(channel).await;
6663 let _ = handle.close(channel).await;
67 let _ = handle.data(channel, Bytes::from_static(b"remote: request rejected: ssh channel buffer cap exceeded\n")).await;
64 let _ = handle
65 .data(
66 channel,
67 Bytes::from_static(
68 b"remote: request rejected: ssh channel buffer cap exceeded\n",
69 ),
70 )
71 .await;
6872 return;
6973 }
7074 let is_write = op.as_ref().is_some_and(|o| o.is_write());
@@ -73,23 +77,17 @@
7377 Some(crate::handler::git_op::GitOperation::ReceivePack { .. })
7478 );
7579
76 if is_receive
77 && let (Some(repo_id), Some(actor_uid)) = (repo_id, actor_id)
78 {
80 if is_receive && let (Some(repo_id), Some(actor_uid)) = (repo_id, actor_id) {
7981 let updates = parse_receive_pack_refs(&buffer);
8082 if !updates.is_empty() {
8183 let db_conn = db.reader();
82 match pre_receive::validate_pre_receive(
83 &db_conn, repo_id, actor_uid, &updates,
84 )
85 .await
84 match pre_receive::validate_pre_receive(&db_conn, repo_id, actor_uid, &updates)
85 .await
8686 {
8787 Ok(verdict) => {
8888 if let Err(e) = verdict.accepted_only() {
8989 let msg = format!("remote: {}\n", e);
90 let _ = handle
91 .data(channel, Bytes::from(msg.into_bytes()))
92 .await;
90 let _ = handle.data(channel, Bytes::from(msg.into_bytes())).await;
9391 let _ = handle.exit_status_request(channel, 1).await;
9492 let _ = handle.eof(channel).await;
9593 let _ = handle.close(channel).await;
Modified dvcs/gitssh/handler/git_op.rs View dvcs/gitssh/handler/git_op.rs
@@ -28,7 +28,7 @@
2828 }
2929 }
3030
31 pub fn is_upload_archive(&self) -> bool {
31 pub fn is_upload_archive(&self) -> bool {
3232 matches!(self, Self::UploadArchive { .. })
3333 }
3434}
Modified dvcs/gitssh/handler/mod.rs View dvcs/gitssh/handler/mod.rs
@@ -36,7 +36,7 @@
3636 pub session_permit: Option<OwnedSemaphorePermit>,
3737 pub operator: Option<users::Model>,
3838 pub channels: HashMap<ChannelId, ChannelState>,
39 pub over_capacity: bool,
39 pub over_capacity: bool,
4040}
4141
4242impl GitSshHandler {