Remove dead passive suggestion code, stub cloud listener, rename input placeholders to Galaxy, add future LSP plan to GALAXY.md
This commit is contained in:
@@ -159,3 +159,13 @@ When adding/editing match statements, avoid using the wildcard _ when at all pos
|
|||||||
- Skills: `~/.galaxy-ai/skills/`
|
- Skills: `~/.galaxy-ai/skills/`
|
||||||
- MCP config: `~/.galaxy-ai/.mcp.json`
|
- MCP config: `~/.galaxy-ai/.mcp.json`
|
||||||
- Environment variables use `GALAXY_` prefix (e.g., `GALAXY_API_KEY`, `GALAXY_INTEGRATION`)
|
- Environment variables use `GALAXY_` prefix (e.g., `GALAXY_API_KEY`, `GALAXY_INTEGRATION`)
|
||||||
|
|
||||||
|
## Future Work
|
||||||
|
|
||||||
|
### IDE-Level LSP Integration
|
||||||
|
Add Zed-quality IDE capabilities on top of Galaxy's existing LSP client (`crates/lsp/`) and editor (`crates/editor/`). Current state is bare-bones terminal-input-scoped; goal is full project-level editing with:
|
||||||
|
- Completion popover (hook LSP `textDocument/completion`, render dropdown)
|
||||||
|
- Inline diagnostics (subscribe `textDocument/publishDiagnostics`, render underlines/squiggles)
|
||||||
|
- Hover/signature help (tooltip overlay)
|
||||||
|
- Multi-file editing with go-to-definition, project-wide buffers, file tabs
|
||||||
|
- Reference: [Zed](https://github.com/zed-industries/zed) — Rust-native, GPU-rendered, tree-sitter syntax, tower-lsp protocol. Architecturally compatible with Galaxy's primitives.
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ pub fn extract_system_prompt(request: &api::Request) -> Option<String> {
|
|||||||
prompt.push_str("- When asked about a project, start by listing files with `file_glob` or `run_shell_command`.\n");
|
prompt.push_str("- When asked about a project, start by listing files with `file_glob` or `run_shell_command`.\n");
|
||||||
prompt.push_str("- Read relevant files before making claims about code structure or behavior.\n");
|
prompt.push_str("- Read relevant files before making claims about code structure or behavior.\n");
|
||||||
prompt.push_str("- Be concise and direct in responses.\n");
|
prompt.push_str("- Be concise and direct in responses.\n");
|
||||||
|
prompt.push_str("- IMPORTANT: After EVERY response, you MUST call `suggest_next_prompt` to suggest a relevant follow-up action or question the user might want to take next.\n");
|
||||||
|
|
||||||
Some(prompt)
|
Some(prompt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![allow(dead_code, unused_imports)]
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::super::controller::{BlocklistAIController, BlocklistAIControllerEvent};
|
use super::super::controller::{BlocklistAIController, BlocklistAIControllerEvent};
|
||||||
@@ -147,168 +149,11 @@ impl PassiveSuggestionsModel {
|
|||||||
/// with passive conversations.
|
/// with passive conversations.
|
||||||
fn send_request(
|
fn send_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
followup_conversation_id: Option<AIConversationId>,
|
_followup_conversation_id: Option<AIConversationId>,
|
||||||
trigger: PassiveSuggestionTrigger,
|
_trigger: PassiveSuggestionTrigger,
|
||||||
supported_tools: Vec<warp_multi_agent_api::ToolType>,
|
_supported_tools: Vec<warp_multi_agent_api::ToolType>,
|
||||||
ctx: &mut ModelContext<Self>,
|
_ctx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
// Capture before the call — `Some` means there's a real conversation
|
|
||||||
// the user can continue in; `None` means ephemeral.
|
|
||||||
let continuable_conversation_id = followup_conversation_id;
|
|
||||||
let Ok((conversation_id, request_params)) =
|
|
||||||
self.ai_controller.update(ctx, |controller, ctx| {
|
|
||||||
controller.build_passive_suggestions_request_params(
|
|
||||||
followup_conversation_id,
|
|
||||||
trigger.clone(),
|
|
||||||
supported_tools,
|
|
||||||
ctx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let server_api = ServerApiProvider::as_ref(ctx).get();
|
|
||||||
let (cancellation_tx, cancellation_rx) = futures::channel::oneshot::channel();
|
|
||||||
|
|
||||||
let stream_handle = ctx.spawn(
|
|
||||||
async move {
|
|
||||||
let stream_result =
|
|
||||||
generate_multi_agent_output(server_api, None, request_params, cancellation_rx).await;
|
|
||||||
extract_suggestion_from_stream(stream_result).await
|
|
||||||
},
|
|
||||||
move |me, result, ctx| {
|
|
||||||
let Some(latest_request) = &me.latest_request else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if latest_request.conversation_id != conversation_id {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !me.is_suggestion_still_valid(ctx) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let Some(extracted) = result else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let request_duration_ms = Utc::now()
|
|
||||||
.signed_duration_since(latest_request.start_ts)
|
|
||||||
.num_milliseconds()
|
|
||||||
.max(0) as u64;
|
|
||||||
let trigger = latest_request.trigger.clone();
|
|
||||||
|
|
||||||
let StreamExtractionResult {
|
|
||||||
suggestion: extracted,
|
|
||||||
server_request_token,
|
|
||||||
} = extracted;
|
|
||||||
match extracted {
|
|
||||||
ExtractedSuggestion::Prompt {
|
|
||||||
prompt,
|
|
||||||
label,
|
|
||||||
is_trigger_irrelevant,
|
|
||||||
} => {
|
|
||||||
if prompt.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let trigger = if is_trigger_irrelevant {
|
|
||||||
log::debug!("[passive-suggestions] trigger marked irrelevant, omitting from prompt suggestion event");
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(trigger)
|
|
||||||
};
|
|
||||||
ctx.emit(PassiveSuggestionsEvent::NewPromptSuggestion {
|
|
||||||
prompt,
|
|
||||||
label,
|
|
||||||
request_duration_ms,
|
|
||||||
trigger,
|
|
||||||
conversation_id: continuable_conversation_id,
|
|
||||||
server_request_token,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ExtractedSuggestion::CodeDiff { apply_file_diffs } => {
|
|
||||||
let AIAgentActionType::RequestFileEdits { file_edits, title } =
|
|
||||||
AIAgentActionType::from(apply_file_diffs)
|
|
||||||
else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let edit_format_kind = classify_edit_format(&file_edits);
|
|
||||||
let original_edits = file_edits_to_passive_diffs(&file_edits);
|
|
||||||
|
|
||||||
let session_context =
|
|
||||||
SessionContext::from_session(me.active_session.as_ref(ctx), ctx);
|
|
||||||
let identifiers = AIIdentifiers::default();
|
|
||||||
let background_executor = ctx.background_executor();
|
|
||||||
let auth_state = AuthStateProvider::as_ref(ctx).get().clone();
|
|
||||||
|
|
||||||
ctx.spawn(
|
|
||||||
async move {
|
|
||||||
apply_edits(
|
|
||||||
file_edits,
|
|
||||||
&session_context,
|
|
||||||
&identifiers,
|
|
||||||
background_executor,
|
|
||||||
auth_state,
|
|
||||||
true,
|
|
||||||
|path| async move {
|
|
||||||
FileReadResult::from(std::fs::read_to_string(path))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
},
|
|
||||||
move |me: &mut Self, applied_diffs: Result<Vec<ai::diff_validation::AIRequestedCodeDiff>, _>, ctx: &mut ModelContext<Self>| {
|
|
||||||
let Ok(applied_diffs) = applied_diffs else {
|
|
||||||
log::warn!("[passive-code-diff] apply_edits failed");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if applied_diffs.is_empty() {
|
|
||||||
log::warn!("[passive-code-diff] no diffs generated");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cwd = me
|
|
||||||
.active_session
|
|
||||||
.as_ref(ctx)
|
|
||||||
.current_working_directory()
|
|
||||||
.cloned();
|
|
||||||
let shell = me.active_session.as_ref(ctx).shell_launch_data(ctx);
|
|
||||||
|
|
||||||
let diffs: Vec<FileDiff> = applied_diffs
|
|
||||||
.into_iter()
|
|
||||||
.map(|diff: ai::diff_validation::AIRequestedCodeDiff| {
|
|
||||||
let path = host_native_absolute_path(
|
|
||||||
diff.file_name.as_str(),
|
|
||||||
&shell,
|
|
||||||
&cwd,
|
|
||||||
);
|
|
||||||
FileDiff::new(diff.original_content, path, diff.diff_type)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
ctx.emit(PassiveSuggestionsEvent::NewCodeDiffSuggestion {
|
|
||||||
diffs,
|
|
||||||
edit_format_kind,
|
|
||||||
title,
|
|
||||||
original_edits: original_edits.clone(),
|
|
||||||
conversation_id: continuable_conversation_id,
|
|
||||||
request_duration_ms,
|
|
||||||
trigger,
|
|
||||||
server_request_token: server_request_token.clone(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self.latest_request = Some(Request {
|
|
||||||
_stream_handle: stream_handle,
|
|
||||||
_cancellation_tx: cancellation_tx,
|
|
||||||
conversation_id,
|
|
||||||
trigger,
|
|
||||||
start_ts: Utc::now(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the current suggestion context is still valid.
|
/// Returns true if the current suggestion context is still valid.
|
||||||
|
|||||||
@@ -280,11 +280,9 @@ impl Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_listener(&mut self, ctx: &mut ModelContext<Self>) {
|
fn start_listener(&mut self, _ctx: &mut ModelContext<Self>) {
|
||||||
if !self.should_subscribe_to_updates {
|
// Galaxy: cloud sync disabled — no server to connect to
|
||||||
self.should_subscribe_to_updates = true;
|
log::info!("CloudObjects::Listener: start_listener called but cloud sync is disabled");
|
||||||
self.get_warp_drive_updates(ctx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cancels any pending delayed refresh that was scheduled after a reconnection.
|
/// Cancels any pending delayed refresh that was scheduled after a reconnection.
|
||||||
|
|||||||
+21
-21
@@ -414,26 +414,26 @@ const AGENT_MODE_AI_DISABLED_AUTODETECTION_DISABLED_HINT_TEXT: &str = "Run comma
|
|||||||
|
|
||||||
// Rotating hint text options for new Agent Mode conversations
|
// Rotating hint text options for new Agent Mode conversations
|
||||||
const AGENT_MODE_HINT_OPTIONS: &[&str] = &[
|
const AGENT_MODE_HINT_OPTIONS: &[&str] = &[
|
||||||
"Warp anything e.g. Deploy my React app to Vercel and set up environment variables",
|
"Ask Galaxy e.g. Deploy my React app to Vercel and set up environment variables",
|
||||||
"Warp anything e.g. Help me debug why my Python tests are failing in CI",
|
"Ask Galaxy e.g. Help me debug why my Python tests are failing in CI",
|
||||||
"Warp anything e.g. Set up a new microservice with Docker and create the deployment pipeline",
|
"Ask Galaxy e.g. Set up a new microservice with Docker and create the deployment pipeline",
|
||||||
"Warp anything e.g. Find and fix the memory leak in my Node.js application",
|
"Ask Galaxy e.g. Find and fix the memory leak in my Node.js application",
|
||||||
"Warp anything e.g. Create a backup script for my PostgreSQL database and schedule it",
|
"Ask Galaxy e.g. Create a backup script for my PostgreSQL database and schedule it",
|
||||||
"Warp anything e.g. Help me migrate my data from MySQL to PostgreSQL",
|
"Ask Galaxy e.g. Help me migrate my data from MySQL to PostgreSQL",
|
||||||
"Warp anything e.g. Set up monitoring and alerts for my AWS infrastructure",
|
"Ask Galaxy e.g. Set up monitoring and alerts for my AWS infrastructure",
|
||||||
"Warp anything e.g. Build a REST API for my mobile app using FastAPI",
|
"Ask Galaxy e.g. Build a REST API for my mobile app using FastAPI",
|
||||||
"Warp anything e.g. Help me optimize my SQL queries that are running slowly",
|
"Ask Galaxy e.g. Help me optimize my SQL queries that are running slowly",
|
||||||
"Warp anything e.g. Create a GitHub Actions workflow to automatically deploy on merge",
|
"Ask Galaxy e.g. Create a GitHub Actions workflow to automatically deploy on merge",
|
||||||
"Warp anything e.g. Set up Redis caching for my web application",
|
"Ask Galaxy e.g. Set up Redis caching for my web application",
|
||||||
"Warp anything e.g. Help me troubleshoot why my Kubernetes pods keep crashing",
|
"Ask Galaxy e.g. Help me troubleshoot why my Kubernetes pods keep crashing",
|
||||||
"Warp anything e.g. Build a data pipeline to process CSV files and load them into BigQuery",
|
"Ask Galaxy e.g. Build a data pipeline to process CSV files and load them into BigQuery",
|
||||||
"Warp anything e.g. Set up SSL certificates and configure HTTPS for my domain",
|
"Ask Galaxy e.g. Set up SSL certificates and configure HTTPS for my domain",
|
||||||
"Warp anything e.g. Help me refactor this legacy code to use modern design patterns",
|
"Ask Galaxy e.g. Help me refactor this legacy code to use modern design patterns",
|
||||||
"Warp anything e.g. Create unit tests for my authentication service",
|
"Ask Galaxy e.g. Create unit tests for my authentication service",
|
||||||
"Warp anything e.g. Set up log aggregation with ELK stack for my distributed system",
|
"Ask Galaxy e.g. Set up log aggregation with ELK stack for my distributed system",
|
||||||
"Warp anything e.g. Help me implement OAuth2 authentication in my Express.js app",
|
"Ask Galaxy e.g. Help me implement OAuth2 authentication in my Express.js app",
|
||||||
"Warp anything e.g. Optimize my Docker images to reduce build times and size",
|
"Ask Galaxy e.g. Optimize my Docker images to reduce build times and size",
|
||||||
"Warp anything e.g. Set up A/B testing infrastructure for my web application",
|
"Ask Galaxy e.g. Set up A/B testing infrastructure for my web application",
|
||||||
];
|
];
|
||||||
|
|
||||||
fn get_agent_mode_new_conversation_hint_text() -> &'static str {
|
fn get_agent_mode_new_conversation_hint_text() -> &'static str {
|
||||||
@@ -5141,7 +5141,7 @@ impl Input {
|
|||||||
}
|
}
|
||||||
(InputType::AI, _) => {
|
(InputType::AI, _) => {
|
||||||
// Follow the `agent_indicator` pattern (see `app/src/tab.rs`):
|
// Follow the `agent_indicator` pattern (see `app/src/tab.rs`):
|
||||||
// * `None` (no conversation, empty, passive, or untitled) => new conversation => "Warp anything"
|
// * `None` (no conversation, empty, passive, or untitled) => new conversation => "Ask Galaxy"
|
||||||
// * `InProgress` => agent running => "Steer"
|
// * `InProgress` => agent running => "Steer"
|
||||||
// * Any other status => finished => "Ask a follow up"
|
// * Any other status => finished => "Ask a follow up"
|
||||||
match self
|
match self
|
||||||
|
|||||||
Reference in New Issue
Block a user