Use named ErrorCode variants for ACP JSON-RPC errors
Replace literal JSON-RPC error codes with the schema's named ErrorCode variants, constructed via Error::new(ErrorCode::X.into(), msg) to keep each custom message: -32603 -> InternalError, -32602 -> InvalidParams, -32002 -> ResourceNotFound. Test assertions keep the numeric form via i32::from(error.code). Co-Authored-By: siGit Code v1.6.6-acp <noreply@sigit.si>
Seto Elkahfi committed
Oct 11, 2026 at 14:16 UTC
b7b9c6660c95d3cf0b661aa0d97da26e69638a7c
1 file changed
+43
-29
src/main.rs
+43
-29
@@ -80,13 +80,13 @@ use agent_client_protocol::schema::v1::{
80
ConfigOptionUpdate, ContentBlock, ContentChunk, CreateElicitationRequest,
81
CreateTerminalRequest, CurrentModeUpdate, DeleteSessionRequest, DeleteSessionResponse, Diff,
82
ElicitationAction, ElicitationRequestScope, ElicitationUrlMode, EmbeddedResourceResource,
83
- ForkSessionRequest, ForkSessionResponse, Implementation, InitializeRequest, InitializeResponse,
84
- KillTerminalRequest, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest,
85
- LoadSessionResponse, LogoutCapabilities, LogoutRequest, LogoutResponse, McpCapabilities,
86
- McpServer, MessageId, Meta, NewSessionRequest, NewSessionResponse, PermissionOption,
87
- PermissionOptionKind, Plan, PlanEntry, PlanEntryPriority, PlanEntryStatus, PromptCapabilities,
88
- PromptRequest, PromptResponse, ReadTextFileRequest, ReleaseTerminalRequest, RequestId,
89
- RequestPermissionOutcome, RequestPermissionRequest, ResumeSessionRequest,
83
+ ErrorCode, ForkSessionRequest, ForkSessionResponse, Implementation, InitializeRequest,
84
+ InitializeResponse, KillTerminalRequest, ListSessionsRequest, ListSessionsResponse,
85
+ LoadSessionRequest, LoadSessionResponse, LogoutCapabilities, LogoutRequest, LogoutResponse,
86
+ McpCapabilities, McpServer, MessageId, Meta, NewSessionRequest, NewSessionResponse,
87
+ PermissionOption, PermissionOptionKind, Plan, PlanEntry, PlanEntryPriority, PlanEntryStatus,
88
+ PromptCapabilities, PromptRequest, PromptResponse, ReadTextFileRequest, ReleaseTerminalRequest,
89
+ RequestId, RequestPermissionOutcome, RequestPermissionRequest, ResumeSessionRequest,
90
ResumeSessionResponse, SessionAdditionalDirectoriesCapabilities, SessionCapabilities,
91
SessionCloseCapabilities, SessionConfigOption, SessionConfigOptionCategory,
92
SessionConfigSelectOption, SessionConfigValueId, SessionDeleteCapabilities,
@@ -1431,7 +1431,7 @@ impl SiGitAgent {
1431
// already done — might be a stored error from earlier
1432
if let Some(err) = self.model_load_error.lock().unwrap().as_ref() {
1433
return Err(agent_client_protocol::Error::new(
1434
- -32603,
1434
+ ErrorCode::InternalError.into(),
1435
format!("model load failed: {err}"),
1436
));
1437
}
@@ -1569,7 +1569,7 @@ impl SiGitAgent {
1569
.ok();
1570
1571
return Err(agent_client_protocol::Error::new(
1572
- -32603,
1572
+ ErrorCode::InternalError.into(),
1573
format!("model load failed: {err}"),
1574
));
1575
}
@@ -1865,7 +1865,7 @@ impl SiGitAgent {
1865
let (new_config, max_tokens, new_tool_calling) = resolve_model_config(model_id)
1866
.ok_or_else(|| {
1867
agent_client_protocol::Error::new(
1868
- -32602,
1868
+ ErrorCode::InvalidParams.into(),
1869
format!("unknown or unavailable model: {model_id}"),
1870
)
1871
})?;
@@ -1917,10 +1917,18 @@ impl SiGitAgent {
1917
1918
result_rx
1919
.await
1920
- .map_err(|_| agent_client_protocol::Error::new(-32603, "model loader thread crashed"))?
1920
+ .map_err(|_| {
1921
+ agent_client_protocol::Error::new(
1922
+ ErrorCode::InternalError.into(),
1923
+ "model loader thread crashed",
1924
+ )
1925
+ })?
1926
.map_err(|error| {
1927
log::error!("model switch failed: {error}");
1923
- agent_client_protocol::Error::new(-32603, format!("model switch failed: {error}"))
1928
+ agent_client_protocol::Error::new(
1929
+ ErrorCode::InternalError.into(),
1930
+ format!("model switch failed: {error}"),
1931
+ )
1932
})?;
1933
1934
self.startup_model_load_started
@@ -2173,13 +2181,13 @@ fn validate_session_roots(
2181
) -> agent_client_protocol::Result<()> {
2182
if !cwd.is_absolute() {
2183
return Err(agent_client_protocol::Error::new(
2176
- -32602,
2184
+ ErrorCode::InvalidParams.into(),
2185
format!("cwd must be an absolute path, got {}", cwd.display()),
2186
));
2187
}
2188
if let Some(relative) = additional.iter().find(|dir| !dir.is_absolute()) {
2189
return Err(agent_client_protocol::Error::new(
2182
- -32602,
2190
+ ErrorCode::InvalidParams.into(),
2191
format!(
2192
"additionalDirectories entries must be absolute paths, got {}",
2193
relative.display()
@@ -2343,7 +2351,7 @@ impl SiGitAgent {
2351
2352
if req.method_id.0.as_ref() != AUTH_METHOD_ID {
2353
return Err(agent_client_protocol::Error::new(
2346
- -32602,
2354
+ ErrorCode::InvalidParams.into(),
2355
format!(
2356
"unknown auth method {}; the only one offered is {AUTH_METHOD_ID}",
2357
req.method_id.0
@@ -2366,7 +2374,7 @@ impl SiGitAgent {
2374
let flow = browser_auth::begin();
2375
if !flow.is_loopback() {
2376
return Err(agent_client_protocol::Error::new(
2369
- -32603,
2377
+ ErrorCode::InternalError.into(),
2378
"Could not open a local port to receive the sign-in. \
2379
Run `sigit login` in a terminal instead."
2380
.to_string(),
@@ -2389,7 +2397,7 @@ impl SiGitAgent {
2397
Ok(AuthenticateResponse::default())
2398
}
2399
Err(reason) => Err(agent_client_protocol::Error::new(
2392
- -32603,
2400
+ ErrorCode::InternalError.into(),
2401
format!(
2402
"Sign-in did not complete ({reason}). \
2403
Try again, or create an account at https://sigit.si."
@@ -2573,7 +2581,7 @@ impl SiGitAgent {
2581
2582
let Some(state) = self.sessions.lock().unwrap().get(&key).cloned() else {
2583
return Err(agent_client_protocol::Error::new(
2576
- -32002,
2584
+ ErrorCode::ResourceNotFound.into(),
2585
format!(
2586
"unknown session {key}; create it with session/new or restore it with session/load"
2587
),
@@ -2837,7 +2845,7 @@ impl SiGitAgent {
2845
&& !cwd.is_absolute()
2846
{
2847
return Err(agent_client_protocol::Error::new(
2840
- -32602,
2848
+ ErrorCode::InvalidParams.into(),
2849
format!("cwd must be an absolute path, got {}", cwd.display()),
2850
));
2851
}
@@ -2960,7 +2968,7 @@ impl SiGitAgent {
2968
let Some(history) = session_store::load(&session_key).or(in_memory) else {
2969
log::warn!("{method}: no session {session_key}");
2970
return Err(agent_client_protocol::Error::new(
2963
- -32002,
2971
+ ErrorCode::ResourceNotFound.into(),
2972
format!("session {session_key} not found"),
2973
));
2974
};
@@ -3624,7 +3632,10 @@ impl SiGitAgent {
3632
let snapshot = backend.history_snapshot().await;
3633
self.persist_session(cx, &session_id, &snapshot).await;
3634
self.finish_prompt(&session_id, &cancellation);
3627
- return Err(agent_client_protocol::Error::new(-32603, error));
3635
+ return Err(agent_client_protocol::Error::new(
3636
+ ErrorCode::InternalError.into(),
3637
+ error,
3638
+ ));
3639
}
3640
};
3641
@@ -4010,7 +4021,10 @@ impl SiGitAgent {
4021
let _ = self.send_plan_update(cx, session_id.clone(), plan);
4022
}
4023
self.finish_prompt(&session_id, &cancellation);
4013
- return Err(agent_client_protocol::Error::new(-32603, error));
4024
+ return Err(agent_client_protocol::Error::new(
4025
+ ErrorCode::InternalError.into(),
4026
+ error,
4027
+ ));
4028
}
4029
};
4030
self.send_usage(cx, &session_id, backend.as_ref(), &result, context_window)
@@ -4479,7 +4493,7 @@ impl SiGitAgent {
4493
return Ok(());
4494
}
4495
Err(agent_client_protocol::Error::new(
4482
- -32002,
4496
+ ErrorCode::ResourceNotFound.into(),
4497
format!(
4498
"unknown session {key}; create it with session/new or restore it with session/load"
4499
),
@@ -4526,7 +4540,7 @@ impl SiGitAgent {
4540
let key = session_id.to_string();
4541
let Some(message) = mode_id.and_then(|id| apply_permission_mode(&key, id)) else {
4542
return Err(agent_client_protocol::Error::new(
4529
- -32602,
4543
+ ErrorCode::InvalidParams.into(),
4544
format!("unknown permission mode: {mode_id:?}"),
4545
));
4546
};
@@ -4594,14 +4608,14 @@ impl SiGitAgent {
4608
(_, Some(LOCAL_INFERENCE_OFF)) => false,
4609
(_, other) => {
4610
return Err(agent_client_protocol::Error::new(
4597
- -32602,
4611
+ ErrorCode::InvalidParams.into(),
4612
format!("unknown Local Inference value: {other:?}"),
4613
));
4614
}
4615
};
4616
if let Err(error) = settings::set_local_inference(enabled) {
4617
return Err(agent_client_protocol::Error::new(
4604
- -32603,
4618
+ ErrorCode::InternalError.into(),
4619
format!("could not save Local Inference setting: {error}"),
4620
));
4621
}
@@ -4620,14 +4634,14 @@ impl SiGitAgent {
4634
4635
if args.config_id.0.as_ref() != MODEL_CONFIG_ID {
4636
return Err(agent_client_protocol::Error::new(
4623
- -32602,
4637
+ ErrorCode::InvalidParams.into(),
4638
format!("unknown config option: {}", args.config_id.0),
4639
));
4640
}
4641
4642
let Some(model_id) = args.value.as_value_id().map(|v| v.0.as_ref()) else {
4643
return Err(agent_client_protocol::Error::new(
4630
- -32602,
4644
+ ErrorCode::InvalidParams.into(),
4645
format!(
4646
"expected a value-id for {MODEL_CONFIG_ID}, got {:?}",
4647
args.value
@@ -5481,7 +5495,7 @@ async fn exec_slash_acp(
5495
let mut sessions = agent.sessions.lock().unwrap();
5496
let state = sessions.get_mut(&session_key).ok_or_else(|| {
5497
agent_client_protocol::Error::new(
5484
- -32602,
5498
+ ErrorCode::InvalidParams.into(),
5499
format!("cannot clear unknown session {session_key}"),
5500
)
5501
})?;