refactor: remove legacy responder + agent_ux, add Gitea integration tests

Legacy removal:
- DELETE src/brain/responder.rs (900 lines) — replaced by orchestrator
- DELETE src/agent_ux.rs (184 lines) — UX moved to transport bridges
- EXTRACT chat_blocking() to src/brain/chat.rs (standalone utility)
- sync.rs: uses ConversationRegistry directly (no responder)
- main.rs: holds ToolRegistry + Personality directly (no Responder wrapper)
- research.rs: progress updates via tracing (no AgentProgress)

Gitea integration testing:
- docker-compose: added Gitea service with healthcheck
- bootstrap-gitea.sh: creates admin, org, mirrors 6 real repos from
  src.sunbeam.pt (sol, cli, proxy, storybook, admin-ui, mistralai-client-rs)
- PAT provisioning for SDK testing without Vault
- code_index/gitea.rs: fixed directory listing (direct API calls instead
  of SDK's single-object parser), proper base64 file decoding

New integration tests:
- Gitea: list_repos, get_repo, get_file, directory listing, code indexing
- Web search: SearXNG query with result verification
- Conversation registry: lifecycle + send_message round-trip
- Evaluator: rule matching (DM, own message)
- gRPC bridge: event filtering, tool call mapping, thinking→status
This commit is contained in:
2026-03-24 11:45:43 +00:00
parent ec55984fd8
commit 495c465a01
15 changed files with 578 additions and 901 deletions

View File

@@ -19,7 +19,8 @@ use crate::archive::indexer::Indexer;
use crate::archive::schema::ArchiveDocument;
use crate::brain::conversation::{ContextMessage, ConversationManager};
use crate::brain::evaluator::{Engagement, Evaluator};
use crate::brain::responder::Responder;
use crate::brain::personality::Personality;
use crate::tools::ToolRegistry;
use crate::config::Config;
use crate::context::{self, ResponseContext};
use crate::conversations::ConversationRegistry;
@@ -30,7 +31,8 @@ pub struct AppState {
pub config: Arc<Config>,
pub indexer: Arc<Indexer>,
pub evaluator: Arc<Evaluator>,
pub responder: Arc<Responder>,
pub tools: Arc<ToolRegistry>,
pub personality: Arc<Personality>,
pub conversations: Arc<Mutex<ConversationManager>>,
pub mistral: Arc<mistralai_client::v1::client::Client>,
pub opensearch: OpenSearch,
@@ -365,41 +367,36 @@ async fn handle_message(
None
};
let response = if state.config.agents.use_conversations_api {
state
.responder
.generate_response_conversations(
&body,
display_sender,
&room_id,
&room_name,
is_dm,
is_spontaneous,
&state.mistral,
&room,
&response_ctx,
&state.conversation_registry,
image_data_uri.as_deref(),
context_hint,
event.event_id.clone().into(),
)
.await
} else {
state
.responder
.generate_response(
&context,
&body,
display_sender,
&room_name,
&members,
is_spontaneous,
&state.mistral,
&room,
&response_ctx,
image_data_uri.as_deref(),
)
.await
// Generate response via ConversationRegistry (Conversations API path).
// The legacy manual chat path has been removed — Conversations API is now mandatory.
let input_text = {
let tc = crate::time_context::TimeContext::now();
let mut header = format!("{}\n[room: {} ({})]", tc.message_line(), room_name, room_id);
// TODO: inject memory notes + breadcrumbs here (like the orchestrator does)
let user_msg = if is_dm {
body.clone()
} else {
format!("<{}> {}", response_ctx.matrix_user_id, body)
};
format!("{header}\n{user_msg}")
};
let input = mistralai_client::v1::conversations::ConversationInput::Text(input_text);
let conv_result = state
.conversation_registry
.send_message(&room_id, input, is_dm, &state.mistral, context_hint.as_deref())
.await;
let response = match conv_result {
Ok(conv_response) => {
// Simple path: extract text (no tool loop for Matrix — tools handled by orchestrator)
// TODO: wire full orchestrator + Matrix bridge for tool support
conv_response.assistant_text()
}
Err(e) => {
error!("Conversation API failed: {e}");
None
}
};
if let Some(text) = response {