Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ jobs:

- name: Configure SSH for cargo git dependencies
uses: webfactory/ssh-agent@v0.9.0
if: env.DEPLOY_KEY != ''
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
ssh-private-key: ${{ env.DEPLOY_KEY }}

- uses: dtolnay/rust-toolchain@stable
with:
Expand Down Expand Up @@ -154,8 +157,11 @@ jobs:

- name: Configure SSH for cargo git dependencies
uses: webfactory/ssh-agent@v0.9.0
if: env.DEPLOY_KEY != ''
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
ssh-private-key: ${{ env.DEPLOY_KEY }}

- uses: dtolnay/rust-toolchain@stable
with:
Expand Down Expand Up @@ -394,8 +400,11 @@ jobs:

- name: Configure SSH for cargo git dependencies
uses: webfactory/ssh-agent@v0.9.0
if: env.DEPLOY_KEY != ''
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
ssh-private-key: ${{ env.DEPLOY_KEY }}

- uses: ilammy/msvc-dev-cmd@v1
with:
Expand Down Expand Up @@ -647,8 +656,11 @@ jobs:

- name: Configure SSH for cargo git dependencies
uses: webfactory/ssh-agent@v0.9.0
if: env.DEPLOY_KEY != ''
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
ssh-private-key: ${{ env.DEPLOY_KEY }}

- uses: dtolnay/rust-toolchain@stable
with:
Expand Down
35 changes: 18 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 11 additions & 6 deletions crates/jcode-app-core/src/agent_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1896,12 +1896,17 @@ fn empty_post_tool_response_gets_more_than_one_retry() {
// transient hiccup, not a finished task. With only one retry allowed, a
// single empty response (observed once in 43 turns) ended a 20-hour agent
// run with the work half-done and the submission unoptimized.
assert!(
Agent::MAX_EMPTY_POST_TOOL_CONTINUATION_ATTEMPTS > 1,
"a single retry lets one transient empty response end a long run"
);
// Bounded, so a genuinely finished agent still exits instead of looping.
assert!(Agent::MAX_EMPTY_POST_TOOL_CONTINUATION_ATTEMPTS <= 10);
// assertions_on_constants fires because both bounds are compile-known; the
// guard is kept as a readable regression test, not dead code.
#[allow(clippy::assertions_on_constants)]
{
assert!(
Agent::MAX_EMPTY_POST_TOOL_CONTINUATION_ATTEMPTS > 1,
"a single retry lets one transient empty response end a long run"
);
// Bounded, so a genuinely finished agent still exits instead of looping.
assert!(Agent::MAX_EMPTY_POST_TOOL_CONTINUATION_ATTEMPTS <= 10);
}
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions crates/jcode-app-core/src/network_retry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ pub fn wait_plan() -> NetworkWaitPlan {
}
#[cfg(target_os = "macos")]
{
return NetworkWaitPlan {
NetworkWaitPlan {
reason: "stream interrupted by a likely network disconnect".to_string(),
listener_summary:
"listening for macOS route/interface changes via `route -n monitor`; also verifying with reconnect probes"
.to_string(),
};
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
Expand Down
70 changes: 35 additions & 35 deletions crates/jcode-app-core/src/server/background_tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,41 @@ fn cap_chars(s: &str, cap: usize) -> String {
out
}

pub(super) async fn dispatch_ui_activity(
activity: &crate::bus::UiActivity,
swarm_members: &Arc<RwLock<HashMap<String, SwarmMember>>>,
) {
if activity.message.trim().is_empty() {
return;
}
let Some(session_id) = activity.session_id.as_deref() else {
return;
};

if fanout_session_event(
swarm_members,
session_id,
ServerEvent::Notification {
from_session: "jcode".to_string(),
from_name: Some("Jcode".to_string()),
notification_type: NotificationType::Message {
scope: Some(activity.kind.scope().to_string()),
channel: None,
tldr: None,
},
message: activity.message.clone(),
},
)
.await
== 0
{
crate::logging::warn(&format!(
"Failed to notify attached clients for UI activity on session {}",
session_id
));
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -673,38 +708,3 @@ mod tests {
assert!(!update_active_todo_batch_progress(&mut items, &progress));
}
}

pub(super) async fn dispatch_ui_activity(
activity: &crate::bus::UiActivity,
swarm_members: &Arc<RwLock<HashMap<String, SwarmMember>>>,
) {
if activity.message.trim().is_empty() {
return;
}
let Some(session_id) = activity.session_id.as_deref() else {
return;
};

if fanout_session_event(
swarm_members,
session_id,
ServerEvent::Notification {
from_session: "jcode".to_string(),
from_name: Some("Jcode".to_string()),
notification_type: NotificationType::Message {
scope: Some(activity.kind.scope().to_string()),
channel: None,
tldr: None,
},
message: activity.message.clone(),
},
)
.await
== 0
{
crate::logging::warn(&format!(
"Failed to notify attached clients for UI activity on session {}",
session_id
));
}
}
6 changes: 2 additions & 4 deletions crates/jcode-app-core/src/server/client_lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1300,10 +1300,8 @@ pub(super) async fn handle_client(
active_turn_registered,
session_connection_busy,
);
if start {
if let Some(info) = connections.get_mut(&client_connection_id) {
info.is_processing = true;
}
if start && let Some(info) = connections.get_mut(&client_connection_id) {
info.is_processing = true;
}
start
};
Expand Down
1 change: 1 addition & 0 deletions crates/jcode-app-core/src/server/client_lifecycle_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::await_holding_lock)] // env guards held across async test bodies
use super::*;
use crate::message::{ContentBlock, Message, StreamEvent, ToolDefinition};
use crate::provider::{EventStream, Provider};
Expand Down
8 changes: 4 additions & 4 deletions crates/jcode-app-core/src/server/comm_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,10 +549,6 @@ async fn register_visible_spawned_member(
broadcast_swarm_status(swarm_id, swarm_members, swarms_by_id).await;
}

#[expect(
clippy::too_many_arguments,
reason = "server-side swarm spawning needs session, swarm state, provider, and event sinks together"
)]
/// Resolve the reasoning effort for a spawned swarm worker (#1165).
///
/// Precedence mirrors the model path: an explicit `effort` on the spawn call
Expand All @@ -571,6 +567,10 @@ pub(super) fn resolve_swarm_spawn_effort(
clean(requested_effort).or_else(|| clean(configured_swarm_effort))
}

#[expect(
clippy::too_many_arguments,
reason = "server-side swarm spawning needs session, swarm state, provider, and event sinks together"
)]
pub(super) async fn spawn_swarm_agent(
req_session_id: &str,
swarm_id: &str,
Expand Down
2 changes: 1 addition & 1 deletion crates/jcode-app-core/src/server/debug_command_exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ mod tests {
use jcode_agent_runtime::InterruptSignal;
use std::collections::HashMap;
use std::ffi::OsString;
use std::sync::{Arc, Mutex, OnceLock};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::{Mutex as AsyncMutex, RwLock};

Expand Down
Loading
Loading