Fix tool results visibility, dynamic system prompt, rebrand Galaxy AI to Galaxy
- Rewrite extract_system_prompt to dynamically include CWD, OS, shell, git, project rules, and tool usage guidance from request context - Fix extract_tool_result_content and format_tool_call_result to properly handle Grep, FileGlobV2, and ApplyFileDiffs results (were returning empty 'Tool completed successfully' strings - model never saw file lists) - Rename all 'Galaxy AI' references to just 'Galaxy' (menu, window title, bundle names, plist, welcome text, about) - Update smoke test with file visibility test prompt - Suppress dead_code warnings on unused smoke test functions
This commit is contained in:
+10
-10
@@ -934,8 +934,8 @@ cloud_mode_input_v2 = ["cloud_mode"]
|
|||||||
[package.metadata.bundle.bin.warp-oss]
|
[package.metadata.bundle.bin.warp-oss]
|
||||||
category = "public.app-category.developer-tools"
|
category = "public.app-category.developer-tools"
|
||||||
copyright = "© 2025, Denver Technologies, Inc"
|
copyright = "© 2025, Denver Technologies, Inc"
|
||||||
identifier = "dev.warp.WarpOss"
|
identifier = "dev.galaxy.GalaxyOss"
|
||||||
name = "WarpOss"
|
name = "Galaxy"
|
||||||
resources = ["assets/onboarding"]
|
resources = ["assets/onboarding"]
|
||||||
icon = ["channels/oss/icon/no-padding/512x512.png", "channels/oss/icon/no-padding/icon.ico"]
|
icon = ["channels/oss/icon/no-padding/512x512.png", "channels/oss/icon/no-padding/icon.ico"]
|
||||||
short_description = "The open-source, cloud-backed terminal for individuals and teams."
|
short_description = "The open-source, cloud-backed terminal for individuals and teams."
|
||||||
@@ -943,8 +943,8 @@ short_description = "The open-source, cloud-backed terminal for individuals and
|
|||||||
[package.metadata.bundle.bin.stable]
|
[package.metadata.bundle.bin.stable]
|
||||||
category = "public.app-category.developer-tools"
|
category = "public.app-category.developer-tools"
|
||||||
copyright = "© 2025, Denver Technologies, Inc"
|
copyright = "© 2025, Denver Technologies, Inc"
|
||||||
identifier = "dev.warp.Warp-Stable"
|
identifier = "dev.galaxy.Galaxy-Stable"
|
||||||
name = "Warp"
|
name = "Galaxy"
|
||||||
osx_frameworks = [
|
osx_frameworks = [
|
||||||
"frameworks/default/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework",
|
"frameworks/default/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework",
|
||||||
]
|
]
|
||||||
@@ -954,8 +954,8 @@ short_description = "The cloud-backed terminal for individuals and teams, stable
|
|||||||
[package.metadata.bundle.bin.preview]
|
[package.metadata.bundle.bin.preview]
|
||||||
category = "public.app-category.developer-tools"
|
category = "public.app-category.developer-tools"
|
||||||
copyright = "© 2025, Denver Technologies, Inc"
|
copyright = "© 2025, Denver Technologies, Inc"
|
||||||
identifier = "dev.warp.Warp-Preview"
|
identifier = "dev.galaxy.Galaxy-Preview"
|
||||||
name = "WarpPreview"
|
name = "GalaxyPreview"
|
||||||
osx_frameworks = [
|
osx_frameworks = [
|
||||||
"frameworks/default/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework",
|
"frameworks/default/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework",
|
||||||
]
|
]
|
||||||
@@ -965,8 +965,8 @@ short_description = "The cloud-backed terminal for individuals and teams, featur
|
|||||||
[package.metadata.bundle.bin.dev]
|
[package.metadata.bundle.bin.dev]
|
||||||
category = "public.app-category.developer-tools"
|
category = "public.app-category.developer-tools"
|
||||||
copyright = "© 2025, Denver Technologies, Inc"
|
copyright = "© 2025, Denver Technologies, Inc"
|
||||||
identifier = "dev.warp.Warp-Dev"
|
identifier = "dev.galaxy.Galaxy-Dev"
|
||||||
name = "WarpDev"
|
name = "GalaxyDev"
|
||||||
osx_frameworks = [
|
osx_frameworks = [
|
||||||
"frameworks/dev/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework",
|
"frameworks/dev/Sentry-Dynamic-WithARM64e.xcframework/macos-arm64_arm64e_x86_64/Sentry.framework",
|
||||||
]
|
]
|
||||||
@@ -976,8 +976,8 @@ short_description = "The cloud-backed terminal for individuals and teams, develo
|
|||||||
[package.metadata.bundle.bin.warp]
|
[package.metadata.bundle.bin.warp]
|
||||||
category = "public.app-category.developer-tools"
|
category = "public.app-category.developer-tools"
|
||||||
copyright = "© 2025, Denver Technologies, Inc"
|
copyright = "© 2025, Denver Technologies, Inc"
|
||||||
identifier = "dev.warp.Warp-Local"
|
identifier = "dev.galaxy.Galaxy-Local"
|
||||||
name = "WarpLocal"
|
name = "GalaxyLocal"
|
||||||
resources = ["assets/onboarding"]
|
resources = ["assets/onboarding"]
|
||||||
short_description = "The cloud-backed terminal for individuals and teams, developer build."
|
short_description = "The cloud-backed terminal for individuals and teams, developer build."
|
||||||
|
|
||||||
|
|||||||
@@ -551,8 +551,80 @@ fn ensure_tool_results_paired(messages: &mut Vec<ConversationMessage>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_system_prompt(_request: &api::Request) -> Option<String> {
|
pub fn extract_system_prompt(request: &api::Request) -> Option<String> {
|
||||||
Some("You are a helpful AI coding assistant. You help users with software engineering tasks including writing code, debugging, and explaining concepts.".to_string())
|
let mut prompt = String::with_capacity(2048);
|
||||||
|
|
||||||
|
prompt.push_str("You are Galaxy, an AI coding assistant embedded in a terminal application. You help users with software engineering tasks including writing code, debugging, explaining concepts, and navigating codebases.\n\n");
|
||||||
|
|
||||||
|
if let Some(input) = &request.input {
|
||||||
|
if let Some(context) = &input.context {
|
||||||
|
prompt.push_str("## Environment\n");
|
||||||
|
if let Some(dir) = &context.directory {
|
||||||
|
if !dir.pwd.is_empty() {
|
||||||
|
prompt.push_str(&format!("- Working directory: {}\n", dir.pwd));
|
||||||
|
}
|
||||||
|
if !dir.home.is_empty() {
|
||||||
|
prompt.push_str(&format!("- Home directory: {}\n", dir.home));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(os) = &context.operating_system {
|
||||||
|
if !os.platform.is_empty() {
|
||||||
|
prompt.push_str(&format!("- OS: {}\n", os.platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(shell) = &context.shell {
|
||||||
|
if !shell.name.is_empty() {
|
||||||
|
prompt.push_str(&format!("- Shell: {}", shell.name));
|
||||||
|
if !shell.version.is_empty() {
|
||||||
|
prompt.push_str(&format!(" {}", shell.version));
|
||||||
|
}
|
||||||
|
prompt.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(git) = &context.git {
|
||||||
|
if !git.branch.is_empty() {
|
||||||
|
prompt.push_str(&format!("- Git branch: {}\n", git.branch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ts) = &context.current_time {
|
||||||
|
prompt.push_str(&format!("- Current time (UTC): {}\n", ts));
|
||||||
|
}
|
||||||
|
prompt.push('\n');
|
||||||
|
|
||||||
|
if !context.project_rules.is_empty() {
|
||||||
|
prompt.push_str("## Project Rules\n");
|
||||||
|
for rules in &context.project_rules {
|
||||||
|
if !rules.root_path.is_empty() {
|
||||||
|
prompt.push_str(&format!("### Rules from {}\n", rules.root_path));
|
||||||
|
}
|
||||||
|
for file in &rules.active_rule_files {
|
||||||
|
if !file.content.is_empty() {
|
||||||
|
prompt.push_str(&file.content);
|
||||||
|
prompt.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prompt.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt.push_str("## Tools\nYou have access to the following tools. Use them proactively to explore codebases and complete tasks:\n");
|
||||||
|
prompt.push_str("- `run_shell_command`: Execute shell commands. Use absolute paths based on the working directory.\n");
|
||||||
|
prompt.push_str("- `read_files`: Read file contents. Pass all files you need in a single call.\n");
|
||||||
|
prompt.push_str("- `apply_file_diffs`: Apply search/replace edits to files.\n");
|
||||||
|
prompt.push_str("- `grep`: Search for patterns in files. Pass all patterns in one call.\n");
|
||||||
|
prompt.push_str("- `file_glob`: Find files matching glob patterns. Pass all patterns in one call.\n");
|
||||||
|
prompt.push_str("- `get_tool_documentation`: Get detailed documentation for any tool or system capabilities.\n\n");
|
||||||
|
|
||||||
|
prompt.push_str("## Guidelines\n");
|
||||||
|
prompt.push_str("- ALWAYS use tools to explore the codebase before answering questions about code.\n");
|
||||||
|
prompt.push_str("- Use absolute paths based on the working directory shown above.\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("- Be concise and direct in responses.\n");
|
||||||
|
|
||||||
|
Some(prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_tools(request: &api::Request) -> Vec<ToolDefinition> {
|
pub fn extract_tools(request: &api::Request) -> Vec<ToolDefinition> {
|
||||||
@@ -773,7 +845,11 @@ fn extract_tool_result_content(result: &api::request::input::ToolCallResult) ->
|
|||||||
api::request::input::tool_call_result::Result::RunShellCommand(cmd_result) => {
|
api::request::input::tool_call_result::Result::RunShellCommand(cmd_result) => {
|
||||||
match &cmd_result.result {
|
match &cmd_result.result {
|
||||||
Some(api::run_shell_command_result::Result::CommandFinished(finished)) => {
|
Some(api::run_shell_command_result::Result::CommandFinished(finished)) => {
|
||||||
finished.output.clone()
|
if finished.output.is_empty() {
|
||||||
|
format!("Exit code: {}\n(no output)", finished.exit_code)
|
||||||
|
} else {
|
||||||
|
format!("Exit code: {}\n{}", finished.exit_code, finished.output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(api::run_shell_command_result::Result::LongRunningCommandSnapshot(
|
Some(api::run_shell_command_result::Result::LongRunningCommandSnapshot(
|
||||||
snapshot,
|
snapshot,
|
||||||
@@ -803,6 +879,78 @@ fn extract_tool_result_content(result: &api::request::input::ToolCallResult) ->
|
|||||||
_ => "Failed to read files.".to_string(),
|
_ => "Failed to read files.".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
api::request::input::tool_call_result::Result::Grep(grep_result) => {
|
||||||
|
match &grep_result.result {
|
||||||
|
Some(api::grep_result::Result::Success(success)) => {
|
||||||
|
if success.matched_files.is_empty() {
|
||||||
|
"No matches found.".to_string()
|
||||||
|
} else {
|
||||||
|
success
|
||||||
|
.matched_files
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let lines: String = f
|
||||||
|
.matched_lines
|
||||||
|
.iter()
|
||||||
|
.map(|l| format!(" line {}", l.line_number))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
format!("{} (matches at: {})", f.file_path, lines)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(api::grep_result::Result::Error(error)) => {
|
||||||
|
format!("Grep error: {}", error.message)
|
||||||
|
}
|
||||||
|
None => "Grep completed (no result).".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api::request::input::tool_call_result::Result::FileGlobV2(glob_result) => {
|
||||||
|
match &glob_result.result {
|
||||||
|
Some(api::file_glob_v2_result::Result::Success(success)) => {
|
||||||
|
if success.matched_files.is_empty() {
|
||||||
|
"No files matched.".to_string()
|
||||||
|
} else {
|
||||||
|
success
|
||||||
|
.matched_files
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.file_path.as_str())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(api::file_glob_v2_result::Result::Error(error)) => {
|
||||||
|
format!("File glob error: {}", error.message)
|
||||||
|
}
|
||||||
|
None => "File glob completed (no result).".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api::request::input::tool_call_result::Result::ApplyFileDiffs(diff_result) => {
|
||||||
|
match &diff_result.result {
|
||||||
|
Some(api::apply_file_diffs_result::Result::Success(success)) => {
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
for f in &success.updated_files_v2 {
|
||||||
|
if let Some(file) = &f.file {
|
||||||
|
parts.push(format!("Updated: {}", file.file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for f in &success.deleted_files {
|
||||||
|
parts.push(format!("Deleted: {}", f.file_path));
|
||||||
|
}
|
||||||
|
if parts.is_empty() {
|
||||||
|
"Diffs applied successfully.".to_string()
|
||||||
|
} else {
|
||||||
|
parts.join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(api::apply_file_diffs_result::Result::Error(error)) => {
|
||||||
|
format!("Apply diffs error: {}", error.message)
|
||||||
|
}
|
||||||
|
None => "Apply diffs completed.".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => "Tool completed successfully.".to_string(),
|
_ => "Tool completed successfully.".to_string(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -816,10 +964,14 @@ fn format_tool_call_result(result: &api::message::ToolCallResult) -> String {
|
|||||||
api::message::tool_call_result::Result::RunShellCommand(cmd_result) => {
|
api::message::tool_call_result::Result::RunShellCommand(cmd_result) => {
|
||||||
match &cmd_result.result {
|
match &cmd_result.result {
|
||||||
Some(api::run_shell_command_result::Result::CommandFinished(finished)) => {
|
Some(api::run_shell_command_result::Result::CommandFinished(finished)) => {
|
||||||
format!(
|
if finished.output.is_empty() {
|
||||||
"Exit code: {}\nOutput: {}",
|
format!("Exit code: {}\n(no output)", finished.exit_code)
|
||||||
finished.exit_code, finished.output
|
} else {
|
||||||
)
|
format!(
|
||||||
|
"Exit code: {}\n{}",
|
||||||
|
finished.exit_code, finished.output
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(api::run_shell_command_result::Result::LongRunningCommandSnapshot(
|
Some(api::run_shell_command_result::Result::LongRunningCommandSnapshot(
|
||||||
snapshot,
|
snapshot,
|
||||||
@@ -840,6 +992,78 @@ fn format_tool_call_result(result: &api::message::ToolCallResult) -> String {
|
|||||||
_ => "Read files completed.".to_string(),
|
_ => "Read files completed.".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
api::message::tool_call_result::Result::Grep(grep_result) => {
|
||||||
|
match &grep_result.result {
|
||||||
|
Some(api::grep_result::Result::Success(success)) => {
|
||||||
|
if success.matched_files.is_empty() {
|
||||||
|
"No matches found.".to_string()
|
||||||
|
} else {
|
||||||
|
success
|
||||||
|
.matched_files
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let lines: String = f
|
||||||
|
.matched_lines
|
||||||
|
.iter()
|
||||||
|
.map(|l| format!(" line {}", l.line_number))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
format!("{} (matches at: {})", f.file_path, lines)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(api::grep_result::Result::Error(error)) => {
|
||||||
|
format!("Grep error: {}", error.message)
|
||||||
|
}
|
||||||
|
None => "Grep completed (no result).".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api::message::tool_call_result::Result::FileGlobV2(glob_result) => {
|
||||||
|
match &glob_result.result {
|
||||||
|
Some(api::file_glob_v2_result::Result::Success(success)) => {
|
||||||
|
if success.matched_files.is_empty() {
|
||||||
|
"No files matched.".to_string()
|
||||||
|
} else {
|
||||||
|
success
|
||||||
|
.matched_files
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.file_path.as_str())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(api::file_glob_v2_result::Result::Error(error)) => {
|
||||||
|
format!("File glob error: {}", error.message)
|
||||||
|
}
|
||||||
|
None => "File glob completed (no result).".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api::message::tool_call_result::Result::ApplyFileDiffs(diff_result) => {
|
||||||
|
match &diff_result.result {
|
||||||
|
Some(api::apply_file_diffs_result::Result::Success(success)) => {
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
for f in &success.updated_files_v2 {
|
||||||
|
if let Some(file) = &f.file {
|
||||||
|
parts.push(format!("Updated: {}", file.file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for f in &success.deleted_files {
|
||||||
|
parts.push(format!("Deleted: {}", f.file_path));
|
||||||
|
}
|
||||||
|
if parts.is_empty() {
|
||||||
|
"Diffs applied successfully.".to_string()
|
||||||
|
} else {
|
||||||
|
parts.join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(api::apply_file_diffs_result::Result::Error(error)) => {
|
||||||
|
format!("Apply diffs error: {}", error.message)
|
||||||
|
}
|
||||||
|
None => "Apply diffs completed.".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
api::message::tool_call_result::Result::Server(server_result) => {
|
api::message::tool_call_result::Result::Server(server_result) => {
|
||||||
server_result.serialized_result.clone()
|
server_result.serialized_result.clone()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const CAPABILITIES_DOC: &str = r#"# Galaxy AI — System Capabilities
|
const CAPABILITIES_DOC: &str = r#"# Galaxy — System Capabilities
|
||||||
|
|
||||||
You are Galaxy, an AI coding assistant embedded in a terminal application with direct filesystem and shell access.
|
You are Galaxy, an AI coding assistant embedded in a terminal application with direct filesystem and shell access.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! AI Assistant has since been renamed to "Galaxy AI" in the product.
|
//! AI Assistant has since been renamed to "Galaxy" in the product.
|
||||||
use std::{collections::HashSet, sync::Arc};
|
use std::{collections::HashSet, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -34,8 +34,8 @@ mod test_util;
|
|||||||
/// This is also roughly the limit at which the editor starts degrading.
|
/// This is also roughly the limit at which the editor starts degrading.
|
||||||
pub const PROMPT_CHARACTER_LIMIT: usize = 1000;
|
pub const PROMPT_CHARACTER_LIMIT: usize = 1000;
|
||||||
|
|
||||||
pub const AI_ASSISTANT_FEATURE_NAME: &str = "Galaxy AI";
|
pub const AI_ASSISTANT_FEATURE_NAME: &str = "Galaxy";
|
||||||
pub const ASK_AI_ASSISTANT_TEXT: &str = "Ask Galaxy AI";
|
pub const ASK_AI_ASSISTANT_TEXT: &str = "Ask Galaxy";
|
||||||
|
|
||||||
pub const AI_ASSISTANT_SVG_PATH: &str = "bundled/svg/ai-assistant.svg";
|
pub const AI_ASSISTANT_SVG_PATH: &str = "bundled/svg/ai-assistant.svg";
|
||||||
|
|
||||||
|
|||||||
@@ -165,14 +165,14 @@ pub fn init(app: &mut AppContext) {
|
|||||||
.with_key_binding(cmd_or_ctrl_shift("l")),
|
.with_key_binding(cmd_or_ctrl_shift("l")),
|
||||||
EditableBinding::new(
|
EditableBinding::new(
|
||||||
"ai_assistant_panel:reset_context",
|
"ai_assistant_panel:reset_context",
|
||||||
"Restart Galaxy AI",
|
"Restart Galaxy",
|
||||||
AIAssistantAction::ResetContext,
|
AIAssistantAction::ResetContext,
|
||||||
)
|
)
|
||||||
.with_context_predicate(id!("AIAssistantPanel"))
|
.with_context_predicate(id!("AIAssistantPanel"))
|
||||||
.with_key_binding("ctrl-l"),
|
.with_key_binding("ctrl-l"),
|
||||||
EditableBinding::new(
|
EditableBinding::new(
|
||||||
"ai_assistant_panel:reset_context",
|
"ai_assistant_panel:reset_context",
|
||||||
"Restart Galaxy AI",
|
"Restart Galaxy",
|
||||||
AIAssistantAction::ResetContext,
|
AIAssistantAction::ResetContext,
|
||||||
)
|
)
|
||||||
.with_context_predicate(id!("AIAssistantPanel"))
|
.with_context_predicate(id!("AIAssistantPanel"))
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ fn make_new_app_menu(ctx: &AppContext) -> Menu {
|
|||||||
None,
|
None,
|
||||||
)));
|
)));
|
||||||
menu_items.push(MenuItem::Standard(StandardAction::Quit));
|
menu_items.push(MenuItem::Standard(StandardAction::Quit));
|
||||||
Menu::new("Galaxy AI", menu_items)
|
Menu::new("Galaxy", menu_items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_new_file_menu(ctx: &AppContext) -> Menu {
|
fn make_new_file_menu(ctx: &AppContext) -> Menu {
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ use crate::workspace::Workspace;
|
|||||||
use crate::BlocklistAIHistoryModel;
|
use crate::BlocklistAIHistoryModel;
|
||||||
|
|
||||||
const TARGET_DIR: &str = "~/GIT/stitcher/stitcher";
|
const TARGET_DIR: &str = "~/GIT/stitcher/stitcher";
|
||||||
|
|
||||||
|
const FILE_VISIBILITY_QUERY: &str = r#"/agent Okay, let's try again. Can you see files now? List the files in the current directory using your tools. Then respond with EXACTLY this structured format:
|
||||||
|
|
||||||
|
results: yes
|
||||||
|
file_count: <number of files/directories you found>
|
||||||
|
|
||||||
|
If you cannot see any files or your tools fail, respond with:
|
||||||
|
|
||||||
|
results: no
|
||||||
|
file_count: 0
|
||||||
|
|
||||||
|
You MUST use the file_glob or run_shell_command tool to check the directory contents first, then provide the structured response."#;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
const AGENT_QUERY: &str = r#"/agent Analyze this project and respond with EXACTLY this structured format at the end of your response:
|
const AGENT_QUERY: &str = r#"/agent Analyze this project and respond with EXACTLY this structured format at the end of your response:
|
||||||
|
|
||||||
Answer: <a 2-3 sentence summary of how this project handles video uploads and media conversions>
|
Answer: <a 2-3 sentence summary of how this project handles video uploads and media conversions>
|
||||||
@@ -49,11 +63,89 @@ fn run_cd(ctx: &mut galaxyui::ViewContext<Workspace>, window_id: WindowId) {
|
|||||||
ctx.spawn(
|
ctx.spawn(
|
||||||
async move { Timer::after(CD_SETTLE_DELAY).await },
|
async move { Timer::after(CD_SETTLE_DELAY).await },
|
||||||
move |_ws: &mut Workspace, _, ctx| {
|
move |_ws: &mut Workspace, _, ctx| {
|
||||||
submit_query(ctx, window_id);
|
submit_file_visibility_test(ctx, window_id);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn submit_file_visibility_test(ctx: &mut galaxyui::ViewContext<Workspace>, window_id: WindowId) {
|
||||||
|
log::info!("[smoke-test] === FILE VISIBILITY TEST ===");
|
||||||
|
log::info!("[smoke-test] Submitting file visibility query...");
|
||||||
|
|
||||||
|
let terminal_view = get_terminal_view(ctx, window_id);
|
||||||
|
terminal_view.update(ctx, |view, ctx| {
|
||||||
|
let input = view.input().clone();
|
||||||
|
input.update(ctx, |input, ctx| {
|
||||||
|
input.submit_queued_prompt(FILE_VISIBILITY_QUERY.to_string(), ctx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
poll_file_visibility(ctx, window_id, std::time::Instant::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_file_visibility(
|
||||||
|
ctx: &mut galaxyui::ViewContext<Workspace>,
|
||||||
|
window_id: WindowId,
|
||||||
|
start: std::time::Instant,
|
||||||
|
) {
|
||||||
|
ctx.spawn(
|
||||||
|
async move { Timer::after(POLL_INTERVAL).await },
|
||||||
|
move |_ws: &mut Workspace, _, ctx| {
|
||||||
|
let elapsed = start.elapsed();
|
||||||
|
if elapsed > MAX_WAIT {
|
||||||
|
log::error!("[smoke-test] FILE VISIBILITY TEST TIMEOUT after {:?}", elapsed);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let terminal_view = get_terminal_view(ctx, window_id);
|
||||||
|
if let Some(full_text) = get_finished_text(ctx, &terminal_view) {
|
||||||
|
log::info!("[smoke-test] === FILE VISIBILITY RESULT ({:.1}s) ===", elapsed.as_secs_f64());
|
||||||
|
|
||||||
|
let results = extract_field(&full_text, "results:");
|
||||||
|
let file_count = extract_field(&full_text, "file_count:");
|
||||||
|
|
||||||
|
match (&results, &file_count) {
|
||||||
|
(Some(r), Some(c)) => {
|
||||||
|
log::info!("[smoke-test] results: {}", r);
|
||||||
|
log::info!("[smoke-test] file_count: {}", c);
|
||||||
|
|
||||||
|
if *r == "yes" {
|
||||||
|
let count: u32 = c.parse().unwrap_or(0);
|
||||||
|
if count > 0 {
|
||||||
|
log::info!("[smoke-test] === FILE VISIBILITY TEST PASSED (found {} files) ===", count);
|
||||||
|
log::info!("[smoke-test] LLM can see files. Proceeding to main test...");
|
||||||
|
std::process::exit(0);
|
||||||
|
} else {
|
||||||
|
log::error!("[smoke-test] === FILE VISIBILITY TEST FAILED (results=yes but file_count=0) ===");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::error!("[smoke-test] === FILE VISIBILITY TEST FAILED (results=no) ===");
|
||||||
|
log::error!("[smoke-test] The LLM cannot see files in {}", TARGET_DIR);
|
||||||
|
log::error!("[smoke-test] Full response:");
|
||||||
|
for line in full_text.lines() {
|
||||||
|
log::error!("[smoke-test] {}", line);
|
||||||
|
}
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
log::error!("[smoke-test] === FILE VISIBILITY TEST FAILED (missing structured fields) ===");
|
||||||
|
log::error!("[smoke-test] Full response:");
|
||||||
|
for line in full_text.lines() {
|
||||||
|
log::error!("[smoke-test] {}", line);
|
||||||
|
}
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_file_visibility(ctx, window_id, start);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn submit_query(ctx: &mut galaxyui::ViewContext<Workspace>, window_id: WindowId) {
|
fn submit_query(ctx: &mut galaxyui::ViewContext<Workspace>, window_id: WindowId) {
|
||||||
log::info!("[smoke-test] Submitting query...");
|
log::info!("[smoke-test] Submitting query...");
|
||||||
|
|
||||||
@@ -69,6 +161,7 @@ fn submit_query(ctx: &mut galaxyui::ViewContext<Workspace>, window_id: WindowId)
|
|||||||
poll(ctx, window_id, std::time::Instant::now());
|
poll(ctx, window_id, std::time::Instant::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn poll(
|
fn poll(
|
||||||
ctx: &mut galaxyui::ViewContext<Workspace>,
|
ctx: &mut galaxyui::ViewContext<Workspace>,
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ embed_plist::embed_info_plist_bytes!(r#"
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Galaxy AI</string>
|
<string>Galaxy</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>galaxy-ai</string>
|
<string>galaxy-ai</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -43,7 +43,7 @@ embed_plist::embed_info_plist_bytes!(r#"
|
|||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Galaxy AI</string>
|
<string>Galaxy</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
@@ -55,7 +55,7 @@ embed_plist::embed_info_plist_bytes!(r#"
|
|||||||
<key>UIDesignRequiresCompatibility</key>
|
<key>UIDesignRequiresCompatibility</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array><dict><key>CFBundleURLName</key><string>Galaxy AI</string><key>CFBundleURLSchemes</key><array><string>galaxyai</string></array></dict></array>
|
<array><dict><key>CFBundleURLName</key><string>Galaxy</string><key>CFBundleURLSchemes</key><array><string>galaxyai</string></array></dict></array>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>© 2026, Samsung Electronics Co., Ltd.</string>
|
<string>© 2026, Samsung Electronics Co., Ltd.</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
+3
-3
@@ -39,7 +39,7 @@ embed_plist::embed_info_plist_bytes!(r#"
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Galaxy AI</string>
|
<string>Galaxy</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>galaxy-ai-oss</string>
|
<string>galaxy-ai-oss</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -47,7 +47,7 @@ embed_plist::embed_info_plist_bytes!(r#"
|
|||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Galaxy AI</string>
|
<string>Galaxy</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
@@ -59,7 +59,7 @@ embed_plist::embed_info_plist_bytes!(r#"
|
|||||||
<key>UIDesignRequiresCompatibility</key>
|
<key>UIDesignRequiresCompatibility</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array><dict><key>CFBundleURLName</key><string>Galaxy AI</string><key>CFBundleURLSchemes</key><array><string>galaxyai</string></array></dict></array>
|
<array><dict><key>CFBundleURLName</key><string>Galaxy</string><key>CFBundleURLSchemes</key><array><string>galaxyai</string></array></dict></array>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>© 2026, Samsung Electronics Co., Ltd.</string>
|
<string>© 2026, Samsung Electronics Co., Ltd.</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ impl GetStartedView {
|
|||||||
.finish(),
|
.finish(),
|
||||||
appearance
|
appearance
|
||||||
.ui_builder()
|
.ui_builder()
|
||||||
.paragraph("Welcome to Galaxy AI")
|
.paragraph("Welcome to Galaxy")
|
||||||
.with_style(UiComponentStyles {
|
.with_style(UiComponentStyles {
|
||||||
font_size: Some(20.),
|
font_size: Some(20.),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ use galaxyui::{FocusContext, NextNewWindowsHasThisWindowsBoundsUponClose};
|
|||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
use crate::auth::web_handoff::{WebHandoffEvent, WebHandoffView};
|
use crate::auth::web_handoff::{WebHandoffEvent, WebHandoffView};
|
||||||
|
|
||||||
const WINDOW_TITLE: &str = "Galaxy AI";
|
const WINDOW_TITLE: &str = "Galaxy";
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref FALLBACK_WINDOW_SIZE: Vector2F = vec2f(800.0, 600.0);
|
static ref FALLBACK_WINDOW_SIZE: Vector2F = vec2f(800.0, 600.0);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
const DEFAULT_TITLE: &str = "Galaxy AI";
|
const DEFAULT_TITLE: &str = "Galaxy";
|
||||||
const BASE_APP_PATH: &str = "/app";
|
const BASE_APP_PATH: &str = "/app";
|
||||||
|
|
||||||
pub fn update_browser_url(url: Option<Url>, force_redirect: bool) {
|
pub fn update_browser_url(url: Option<Url>, force_redirect: bool) {
|
||||||
|
|||||||
@@ -1396,7 +1396,7 @@ fn add_open_setting_pages_as_editable_binding(app: &mut AppContext) {
|
|||||||
EditableBinding::new(
|
EditableBinding::new(
|
||||||
"workspace:show_settings_about_page",
|
"workspace:show_settings_about_page",
|
||||||
BindingDescription::new("Open Settings: About")
|
BindingDescription::new("Open Settings: About")
|
||||||
.with_custom_description(bindings::MAC_MENUS_CONTEXT, "About Galaxy AI"),
|
.with_custom_description(bindings::MAC_MENUS_CONTEXT, "About Galaxy"),
|
||||||
WorkspaceAction::ShowSettingsPage(SettingsSection::About),
|
WorkspaceAction::ShowSettingsPage(SettingsSection::About),
|
||||||
)
|
)
|
||||||
.with_group(bindings::BindingGroup::Settings.as_str())
|
.with_group(bindings::BindingGroup::Settings.as_str())
|
||||||
|
|||||||
@@ -545,7 +545,7 @@ const TAB_BAR_PILL_WIDTH: f32 = 100.;
|
|||||||
const PILL_FONT_SIZE: f32 = 12.;
|
const PILL_FONT_SIZE: f32 = 12.;
|
||||||
// We use the word "Warp" in the Update Ready button to make it obvious that the terminal is Warp.
|
// We use the word "Warp" in the Update Ready button to make it obvious that the terminal is Warp.
|
||||||
// This can lead to free advertising when users screen-share Warp when an update is available.
|
// This can lead to free advertising when users screen-share Warp when an update is available.
|
||||||
const UPDATE_READY_TEXT: &str = "Update Galaxy AI";
|
const UPDATE_READY_TEXT: &str = "Update Galaxy";
|
||||||
|
|
||||||
const TAB_BAR_OVERFLOW_MENU_WIDTH: f32 = 300.;
|
const TAB_BAR_OVERFLOW_MENU_WIDTH: f32 = 300.;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user