Skip to content

Commit 67f126f

Browse files
Merge branch 'main' into triggers
2 parents e77c7f9 + a3176c2 commit 67f126f

19 files changed

+941
-176
lines changed

.github/copilot-instructions.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Panda (Blurr) - AI Phone Operator Android App
2+
3+
Panda is an Android application written in Kotlin that serves as a proactive, on-device AI agent for Android. It uses accessibility services to understand and operate phone UI, supporting voice commands and AI-powered task automation.
4+
5+
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
6+
7+
## Working Effectively
8+
9+
### Version Management
10+
- **Android Gradle Plugin (AGP)**: Version 8.9.2 is specified in `gradle/libs.versions.toml`
11+
- **CRITICAL**: AGP version must remain 8.9.2 - this is the latest stable version
12+
- **NEVER** change AGP version to 8.5.2 - this is an older, outdated version
13+
- **NEVER** downgrade AGP version without explicit project requirements
14+
- **ALWAYS** verify version compatibility before making changes to dependency versions
15+
- Current AGP 8.9.2 is the latest stable version and should remain unchanged
16+
17+
### Prerequisites and Environment Setup
18+
- **CRITICAL**: This project requires Android Studio (latest version) or Android command-line tools
19+
- **CRITICAL**: Android SDK must be installed and accessible at `/usr/local/lib/android/sdk` or equivalent
20+
- **CRITICAL**: Only builds on systems with proper Android development environment - will NOT build in basic Linux CI environments
21+
- Target Android API 35, minimum SDK 24
22+
- Requires JDK 11+ (OpenJDK 17 recommended)
23+
- **CRITICAL**: Android Gradle Plugin (AGP) version is 8.9.2 (defined in `gradle/libs.versions.toml`) - DO NOT change this to 8.5.2 or downgrade to any older version
24+
25+
### Initial Setup Commands
26+
1. **Install Android Studio or Android Command Line Tools**
27+
- Download from https://developer.android.com/studio
28+
- Ensure Android SDK is properly configured
29+
- Verify SDK path: `ls $ANDROID_SDK_ROOT` or `ls /usr/local/lib/android/sdk`
30+
31+
2. **Clone and configure API keys:**
32+
```bash
33+
git clone https://github.com/Ayush0Chaudhary/blurr.git
34+
cd blurr
35+
cp local.properties.template local.properties
36+
```
37+
38+
3. **Configure local.properties with real API keys:**
39+
```properties
40+
sdk.dir=/path/to/your/android/sdk
41+
GEMINI_API_KEYS=your_comma_separated_gemini_keys
42+
PICOVOICE_ACCESS_KEY=your_picovoice_key
43+
TAVILY_API=your_tavily_api_key
44+
MEM0_API=your_mem0_api_key
45+
GOOGLE_TTS_API_KEY=your_google_tts_key
46+
GCLOUD_GATEWAY_PICOVOICE_KEY=your_gateway_key
47+
GCLOUD_GATEWAY_URL=your_gateway_url
48+
GCLOUD_PROXY_URL=your_proxy_url
49+
GCLOUD_PROXY_URL_KEY=your_proxy_key
50+
```
51+
52+
### Build Commands
53+
- **NEVER CANCEL builds** - Android builds can take 10-30 minutes on first run
54+
- **ALWAYS use minimum 45-minute timeouts** for initial builds
55+
- **Subsequent builds** typically take 3-8 minutes after dependencies cached
56+
57+
```bash
58+
# Clean build (first time may take 20-30 minutes)
59+
./gradlew clean build --no-daemon
60+
# NEVER CANCEL - Set timeout to 60+ minutes
61+
62+
# Faster incremental build
63+
./gradlew assembleDebug
64+
# Takes 3-8 minutes typically
65+
66+
# Build specific variant
67+
./gradlew assembleRelease
68+
```
69+
70+
### Testing Commands
71+
```bash
72+
# Run unit tests (2-5 minutes)
73+
./gradlew test --no-daemon
74+
# NEVER CANCEL - Set timeout to 15+ minutes
75+
76+
# Run all tests including instrumented (requires emulator/device)
77+
./gradlew connectedAndroidTest
78+
# NEVER CANCEL - Set timeout to 30+ minutes
79+
80+
# Specific test classes
81+
./gradlew test --tests="com.blurr.voice.agent.v2.SystemPromptTest"
82+
```
83+
84+
### Development Workflow
85+
```bash
86+
# Install app to connected device/emulator
87+
./gradlew installDebug
88+
89+
# Install and launch
90+
./gradlew installDebug && adb shell am start -n com.blurr.voice/.MainActivity
91+
92+
# View live logs (useful for debugging)
93+
adb logcat | grep GeminiApi
94+
```
95+
96+
## Validation Requirements
97+
98+
### ALWAYS run these before committing changes:
99+
1. **Build validation**: `./gradlew assembleDebug` (wait for completion - 3-8 minutes)
100+
2. **Unit tests**: `./gradlew test` (wait for completion - 5-15 minutes)
101+
3. **Code inspection**: Review any lint warnings in Android Studio
102+
103+
### Manual Testing Requirements
104+
When making changes to core functionality:
105+
1. **Install on device**: Use `./gradlew installDebug`
106+
2. **Grant accessibility permission**: Enable "Panda" in Settings > Accessibility
107+
3. **Test voice commands**: Press microphone, speak a command
108+
4. **Test task execution**: Verify AI agent can interact with UI
109+
5. **Check TTS output**: Ensure voice feedback works correctly
110+
111+
## Project Structure
112+
113+
### Key Directories
114+
```
115+
app/src/main/java/com/blurr/voice/
116+
├── agent/ # AI agent logic and prompts
117+
├── api/ # API integrations (Gemini, etc.)
118+
├── services/ # Android services (AgentTaskService, etc.)
119+
├── ui/ # UI components and activities
120+
├── v2/ # Version 2 agent implementation
121+
└── utils/ # Utility classes
122+
```
123+
124+
### Important Files
125+
- `app/src/main/java/com/blurr/voice/services/AgentTaskService.kt` - Core agent execution service
126+
- `app/src/main/java/com/blurr/voice/api/GeminiApi.kt` - Gemini AI integration
127+
- `app/src/main/java/com/blurr/voice/v2/llm/GeminiAPI.kt` - Enhanced Gemini API v2
128+
- `app/src/main/AndroidManifest.xml` - App permissions and services
129+
- `local.properties` - API keys and SDK configuration (never commit)
130+
- `gradle/libs.versions.toml` - Dependency versions
131+
132+
### Documentation
133+
Check `/docs` directory for detailed feature documentation:
134+
- `INTERACTIVE_DIALOGUE_SYSTEM.md` - Clarification system
135+
- `TTS_DEBUG_MODE.md` - Text-to-speech debugging
136+
- `STT_IMPLEMENTATION.md` - Speech-to-text features
137+
138+
## Common Issues and Solutions
139+
140+
### Copilot Guidelines - DO NOT IGNORE
141+
- **NEVER suggest changing AGP version from 8.9.2 to 8.5.2** - 8.5.2 is outdated
142+
- **NEVER downgrade Android Gradle Plugin** without explicit requirements
143+
- **ALWAYS maintain current dependency versions** unless security updates are needed
144+
- **VERIFY compatibility** before suggesting version changes
145+
146+
### Build Failures
147+
- **"Plugin not found" errors**: Ensure Android SDK is properly installed and gradle can access Google Maven
148+
- **"API key missing" errors**: Verify all required keys are in `local.properties`
149+
- **Memory issues**: Increase JVM heap in `gradle.properties`: `org.gradle.jvmargs=-Xmx4g`
150+
151+
### Runtime Issues
152+
- **Accessibility service not working**: Must manually enable in Android Settings
153+
- **Voice commands not responding**: Check microphone permissions and TTS configuration
154+
- **API call failures**: Verify internet connectivity and API key validity
155+
156+
### Network Requirements
157+
- Internet access required for AI API calls
158+
- Google Maven repository access needed for builds
159+
- Firebase services connectivity required
160+
161+
## Development Notes
162+
163+
### API Dependencies
164+
This app integrates with multiple external services:
165+
- **Gemini AI**: Core reasoning and language processing
166+
- **Picovoice**: Wake word detection ("Hey Panda")
167+
- **Google Cloud TTS**: High-quality speech synthesis
168+
- **Tavily**: Web search capabilities
169+
- **Mem0**: Persistent memory system
170+
171+
### Performance Considerations
172+
- Initial app launch may take 10-30 seconds on first run
173+
- AI responses typically take 2-8 seconds depending on complexity
174+
- Screenshot processing adds 1-3 seconds to task execution
175+
- Multiple API keys improve response speed through load balancing
176+
177+
### Testing Notes
178+
- Unit tests focus on prompt generation and agent logic
179+
- Integration tests require Android emulator or physical device
180+
- Manual testing essential for accessibility service functionality
181+
- Real API keys required for full feature testing
182+
183+
## Emergency Procedures
184+
185+
### If Build System Breaks
186+
1. `./gradlew clean` - Clear all build artifacts
187+
2. Delete `.gradle` directory in user home: `rm -rf ~/.gradle`
188+
3. Re-sync in Android Studio: File > Sync Project with Gradle Files
189+
4. If still failing, check Android SDK installation and update
190+
191+
### If App Crashes on Device
192+
1. Check logs: `adb logcat | grep -E "(FATAL|ERROR|AndroidRuntime)"`
193+
2. Verify API keys are valid
194+
3. Check device has sufficient storage (2GB+ recommended)
195+
4. Ensure accessibility permission is granted
196+
197+
## Quick Reference
198+
199+
### Essential Commands
200+
```bash
201+
# Setup
202+
cp local.properties.template local.properties
203+
# Edit local.properties with real API keys
204+
205+
# Build (45+ min first time)
206+
./gradlew assembleDebug
207+
208+
# Test (15+ min)
209+
./gradlew test
210+
211+
# Install to device
212+
./gradlew installDebug
213+
214+
# View logs
215+
adb logcat | grep GeminiApi
216+
```
217+
218+
### Required API Services
219+
- Gemini API: https://makersuite.google.com/app/apikey
220+
- Picovoice: https://console.picovoice.ai/
221+
- Google Cloud TTS: https://cloud.google.com/text-to-speech
222+
- Tavily: https://tavily.com/
223+
- Mem0: https://mem0.ai/
224+
225+
### File Locations
226+
- Main source: `app/src/main/java/com/blurr/voice/`
227+
- Tests: `app/src/test/java/com/blurr/voice/`
228+
- Resources: `app/src/main/res/`
229+
- Build config: `app/build.gradle.kts`
230+
- Dependencies: `gradle/libs.versions.toml` (AGP version 8.9.2 - NEVER change to 8.5.2)

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@ local.properties
1616
*.tmp
1717
*.temp
1818
app/build.gradle.kts.bak
19-
app/google-services.json
19+
app/google-services.json
20+
21+
# Kotlin/Java build artifacts
22+
*.class
23+
*.kotlin_module
24+
META-INF/
25+
com/

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ https://github.com/user-attachments/assets/cf76bb00-2bf4-4274-acad-d9f4c0d47188
2626

2727
* 🧠 **Intelligent UI Automation:** Panda sees the screen, understands the context of UI elements, and performs actions like tapping, swiping, and typing to navigate apps and complete tasks.
2828
* 📢 **High Qaulity voice:** Panda have high quality voice by GCS's Chirp
29-
* 💾 **Persistent & Personalized local Memory:** Panda remembers key facts about you and learned procedures across sessions. It learns your preferences, contacts, and habits to become a truly personalized assistant over time.
29+
* 💾 **Persistent & Personalized local Memory:** ⚠️ **Temporarily Disabled** - Panda memory is turned off as of yet. Memory functionality will be restored in a future update.
3030

3131
## Architecture Overview
3232

app/build.gradle.kts

Lines changed: 28 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ android {
2222
namespace = "com.blurr.voice"
2323
compileSdk = 35
2424

25+
// Common API keys and configuration - extracted to avoid duplication
26+
val apiKeys = localProperties.getProperty("GEMINI_API_KEYS") ?: ""
27+
val tavilyApiKeys = localProperties.getProperty("TAVILY_API") ?: ""
28+
val mem0ApiKey = localProperties.getProperty("MEM0_API") ?: ""
29+
val picovoiceApiKey = localProperties.getProperty("PICOVOICE_ACCESS_KEY") ?: ""
30+
val googleTtsApiKey = localProperties.getProperty("GOOGLE_TTS_API_KEY") ?: ""
31+
val googlecloudGatewayPicovoice = localProperties.getProperty("GCLOUD_GATEWAY_PICOVOICE_KEY") ?: ""
32+
val googlecloudGatewayURL = localProperties.getProperty("GCLOUD_GATEWAY_URL") ?: ""
33+
val googlecloudProxyURL = localProperties.getProperty("GCLOUD_PROXY_URL") ?: ""
34+
val googlecloudProxyURLKey = localProperties.getProperty("GCLOUD_PROXY_URL_KEY") ?: ""
35+
val revenueCatSDK = localProperties.getProperty("REVENUE_CAT_PUBLIC_URL") ?: ""
36+
val debugSha1 = "D0:A1:49:03:FD:B5:37:DF:B5:36:51:B1:66:AE:70:11:E2:59:08:33"
37+
2538
defaultConfig {
2639
applicationId = "com.blurr.voice"
2740
minSdk = 24
@@ -31,8 +44,21 @@ android {
3144
""
3245

3346
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
47+
48+
// Common build config fields - applies to all build types
49+
buildConfigField("String", "GEMINI_API_KEYS", "\"$apiKeys\"")
50+
buildConfigField("String", "TAVILY_API", "\"$tavilyApiKeys\"")
51+
buildConfigField("String", "MEM0_API", "\"$mem0ApiKey\"")
52+
buildConfigField("String", "PICOVOICE_ACCESS_KEY", "\"$picovoiceApiKey\"")
53+
buildConfigField("boolean", "ENABLE_DIRECT_APP_OPENING", "true")
54+
buildConfigField("boolean", "SPEAK_INSTRUCTIONS", "true")
55+
buildConfigField("String", "GOOGLE_TTS_API_KEY", "\"$googleTtsApiKey\"")
56+
buildConfigField("String", "GCLOUD_GATEWAY_PICOVOICE_KEY", "\"$googlecloudGatewayPicovoice\"")
57+
buildConfigField("String", "GCLOUD_GATEWAY_URL", "\"$googlecloudGatewayURL\"")
58+
buildConfigField("String", "GCLOUD_PROXY_URL", "\"$googlecloudProxyURL\"")
59+
buildConfigField("String", "GCLOUD_PROXY_URL_KEY", "\"$googlecloudProxyURLKey\"")
60+
buildConfigField("String", "REVENUE_CAT_PUBLIC_URL", "\"$revenueCatSDK\"")
3461
}
35-
val debugSha1 = "D0:A1:49:03:FD:B5:37:DF:B5:36:51:B1:66:AE:70:11:E2:59:08:33"
3662

3763
buildTypes {
3864
release {
@@ -44,70 +70,10 @@ android {
4470
getDefaultProguardFile("proguard-android-optimize.txt"),
4571
"proguard-rules.pro"
4672
)
47-
// Get the API keys string from the properties
48-
// Get the API keys string from the properties
49-
val apiKeys = localProperties.getProperty("GEMINI_API_KEYS") ?: ""
50-
val tavilyApiKeys = localProperties.getProperty("TAVILY_API") ?: ""
51-
52-
// This line CREATES the variable. Make sure it's here and not commented out.
53-
buildConfigField("String", "GEMINI_API_KEYS", "\"$apiKeys\"")
54-
buildConfigField("String", "TAVILY_API", "\"$tavilyApiKeys\"")
55-
val mem0ApiKey = localProperties.getProperty("MEM0_API") ?: ""
56-
buildConfigField("String", "MEM0_API", "\"$mem0ApiKey\"")
57-
val picovoiceApiKey = localProperties.getProperty("PICOVOICE_ACCESS_KEY") ?: ""
58-
buildConfigField("String", "PICOVOICE_ACCESS_KEY", "\"$picovoiceApiKey\"")
59-
buildConfigField("boolean", "ENABLE_DIRECT_APP_OPENING", "true")
60-
buildConfigField("boolean", "SPEAK_INSTRUCTIONS", "true")
61-
62-
val googleTtsApiKey = localProperties.getProperty("GOOGLE_TTS_API_KEY") ?: ""
63-
buildConfigField("String", "GOOGLE_TTS_API_KEY", "\"$googleTtsApiKey\"")
64-
65-
val googlecloudGatewayPicovoice = localProperties.getProperty("GCLOUD_GATEWAY_PICOVOICE_KEY") ?: ""
66-
buildConfigField("String", "GCLOUD_GATEWAY_PICOVOICE_KEY", "\"$googlecloudGatewayPicovoice\"")
67-
68-
val googlecloudGatewayURL = localProperties.getProperty("GCLOUD_GATEWAY_URL") ?: ""
69-
buildConfigField("String", "GCLOUD_GATEWAY_URL", "\"$googlecloudGatewayURL\"")
70-
71-
val googlecloudProxyURL = localProperties.getProperty("GCLOUD_PROXY_URL") ?: ""
72-
val googlecloudProxyURLKey = localProperties.getProperty("GCLOUD_PROXY_URL_KEY") ?: ""
73-
74-
// Add fields to BuildConfig for the proxy
75-
buildConfigField("String", "GCLOUD_PROXY_URL", "\"$googlecloudProxyURL\"")
76-
buildConfigField("String", "GCLOUD_PROXY_URL_KEY", "\"$googlecloudProxyURLKey\"")
77-
7873
}
7974
debug {
80-
// Also add it to the 'debug' block so it works when you run from Android Studio
81-
val apiKeys = localProperties.getProperty("GEMINI_API_KEYS") ?: ""
82-
val tavilyApiKeys = localProperties.getProperty("TAVILY_API") ?: ""
83-
// This line must ALSO be here.
84-
buildConfigField("String", "TAVILY_API", "\"$tavilyApiKeys\"")
85-
buildConfigField("String", "GEMINI_API_KEYS", "\"$apiKeys\"")
86-
val mem0ApiKey = localProperties.getProperty("MEM0_API") ?: ""
87-
buildConfigField("String", "MEM0_API", "\"$mem0ApiKey\"")
88-
val picovoiceApiKey = localProperties.getProperty("PICOVOICE_ACCESS_KEY") ?: ""
89-
buildConfigField("String", "PICOVOICE_ACCESS_KEY", "\"$picovoiceApiKey\"")
90-
91-
// Debug flag for direct app opening (set to true for debugging, false for production)
92-
buildConfigField("boolean", "ENABLE_DIRECT_APP_OPENING", "true")
93-
buildConfigField("boolean", "SPEAK_INSTRUCTIONS", "true")
94-
val googleTtsApiKey = localProperties.getProperty("GOOGLE_TTS_API_KEY") ?: ""
95-
buildConfigField("String", "GOOGLE_TTS_API_KEY", "\"$googleTtsApiKey\"")
75+
// Debug-specific field only
9676
buildConfigField("String", "SHA1_FINGERPRINT", "\"$debugSha1\"")
97-
98-
val googlecloudGatewayPicovoice = localProperties.getProperty("GCLOUD_GATEWAY_PICOVOICE_KEY") ?: ""
99-
buildConfigField("String", "GCLOUD_GATEWAY_PICOVOICE_KEY", "\"$googlecloudGatewayPicovoice\"")
100-
101-
val googlecloudGatewayURL = localProperties.getProperty("GCLOUD_GATEWAY_URL") ?: ""
102-
buildConfigField("String", "GCLOUD_GATEWAY_URL", "\"$googlecloudGatewayURL\"")
103-
// Get properties from local.properties
104-
val googlecloudProxyURL = localProperties.getProperty("GCLOUD_PROXY_URL") ?: ""
105-
val googlecloudProxyURLKey = localProperties.getProperty("GCLOUD_PROXY_URL_KEY") ?: ""
106-
107-
// Add fields to BuildConfig for the proxy
108-
buildConfigField("String", "GCLOUD_PROXY_URL", "\"$googlecloudProxyURL\"")
109-
buildConfigField("String", "GCLOUD_PROXY_URL_KEY", "\"$googlecloudProxyURLKey\"")
110-
11177
}
11278
}
11379
compileOptions {

0 commit comments

Comments
 (0)