- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.5k
ChatClient demo with API for secure secret retrieval #659
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Open
      
      
            davidortinau
  wants to merge
  5
  commits into
  main
  
    
      
        
          
  
    
      Choose a base branch
      
     
    
      
        
      
      
        
          
          
        
        
          
            
              
              
              
  
           
        
        
          
            
              
              
           
        
       
     
  
        
          
            
          
            
          
        
       
    
      
from
ai-samples-mobile
  
      
      
   
  
    
  
  
  
 
  
      
    base: main
Could not load branches
            
              
  
    Branch not found: {{ refName }}
  
            
                
      Loading
              
            Could not load tags
            
            
              Nothing to show
            
              
  
            
                
      Loading
              
            Are you sure you want to change the base?
            Some commits from the old base branch may be removed from the timeline,
            and old review comments may become outdated.
          
          
  
     Open
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            5 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      60d6a7f
              
                look ma, it's another demo
              
              
                davidortinau 9aed775
              
                Merge branch 'main' into ai-samples-mobile
              
              
                jfversluis 3266045
              
                Merge branch 'main' into ai-samples-mobile
              
              
                jsuarezruiz a7f7b9d
              
                Merge branch 'main' into ai-samples-mobile
              
              
                jsuarezruiz 6c51a13
              
                Merge branch 'main' into ai-samples-mobile
              
              
                jsuarezruiz File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,306 @@ | ||
| # ChatClientWithMobile (Secure Client-Side AI with Tools) | ||
|  | ||
| A .NET solution showing secure client-side AI with Microsoft.Extensions.AI function calling in .NET MAUI, using a minimal Web API for credential distribution. The MAUI client builds an IChatClient and executes tools locally (Weather, Calculator, File Operations, System Info, Timers). | ||
|  | ||
|  | ||
|  | ||
| ## Architecture Overview | ||
|  | ||
| This sample implements a **client-centric AI architecture** with secure credential management: | ||
|  | ||
| - **Web API Backend** (`ChatMobile.Api`): Simple credential distribution service | ||
| - **MAUI Frontend** (`ChatMobile.Client`): Full AI functionality with Microsoft.Extensions.AI, secure credential storage, and tool execution | ||
|  | ||
| ## Key Benefits | ||
|  | ||
| ### Security | ||
|  | ||
| - **API keys securely stored on device** - using MAUI SecureStorage for encrypted credential storage | ||
| - **Minimal server exposure** - Web API only distributes credentials, no AI processing | ||
| - **Client-side control** - All AI interactions happen locally with direct Azure OpenAI communication | ||
|  | ||
| ### Simplified Architecture | ||
|  | ||
| 1. User opens MAUI app | ||
| 2. App checks for stored credentials using SecureStorage | ||
| 3. If no credentials, user clicks "Setup" → app fetches credentials from Web API once | ||
| 4. Credentials stored securely on device using MAUI SecureStorage | ||
| 5. All subsequent AI interactions bypass server - direct MAUI → Azure OpenAI communication | ||
| 6. AI function calling with Weather, Calculator, File Operations, System Info, and Timer tools executed locally | ||
|  | ||
| ## Project Structure | ||
|  | ||
| ``` | ||
| ChatClientWithMobile/ | ||
| ├── README.md | ||
| ├── images/ | ||
| └── src/ | ||
| ├── ChatClientWithMobile.sln | ||
| ├── ChatMobile.Api/ # ASP.NET Core Web API (Credential Distribution) | ||
| │ ├── Program.cs # Minimal API with credential endpoint | ||
| │ ├── Services/ | ||
| │ │ ├── ICredentialService.cs | ||
| │ │ └── CredentialService.cs | ||
| │ ├── Models/CredentialResponse.cs | ||
| │ └── appsettings.json # Server-side credential storage | ||
| └── ChatMobile.Client/ # .NET MAUI App (Full AI Functionality) | ||
| ├── Views/ | ||
| │ ├── MainPage.xaml # Chat interface | ||
| │ └── SetupPage.xaml # Credential setup UI | ||
| ├── ViewModels/ | ||
| │ ├── ChatViewModel.cs # Chat logic with local AI | ||
| │ └── SetupViewModel.cs # Credential setup logic | ||
| ├── Services/ | ||
| │ ├── IChatService.cs # Local AI chat service | ||
| │ ├── ChatService.cs | ||
| │ ├── ISecureCredentialService.cs # Secure storage interface | ||
| │ ├── SecureCredentialService.cs # MAUI SecureStorage implementation | ||
| │ └── HostingExtensions.cs # DI configuration with IChatClient | ||
| ├── Tools/ # AI Function Tools (AIFunction subclasses) | ||
| │ ├── WeatherTool.cs # Geocode-first → weather by lat/lon | ||
| │ ├── CalculatorTool.cs # Mathematical calculations with percentage support | ||
| │ ├── FileOperationsTool.cs# List directories/files on device (safe paths) | ||
| │ ├── SystemInfoTool.cs # Battery/device info (platform-appropriate) | ||
| │ └── TimerTool.cs # Simple one-shot timers with titles | ||
| ├── Converters/ # XAML value converters | ||
| └── Models/ # Chat and result models | ||
| ``` | ||
|  | ||
| ## Tool Categories | ||
|  | ||
| ### Client-Side AI Tools (MAUI) | ||
|  | ||
| - WeatherTool (`get_weather`): Geocoding first, then weather by coordinates (OpenWeatherMap) | ||
| - CalculatorTool (`calculate`): Expressions, including percentages | ||
| - FileOperationsTool (`list_files`): Enumerate directories/files (bounded results) | ||
| - SystemInfoTool (`system_info`): Battery level/state, device info | ||
| - TimerTool (`set_timer`): One-shot timers with friendly summaries | ||
|  | ||
| All Microsoft.Extensions.AI processing and tool execution happens locally in the MAUI client. The Web API is used only once to supply credentials which are then stored securely. | ||
|  | ||
| ## Prerequisites | ||
|  | ||
| - .NET 10 SDK | ||
| - Azure OpenAI endpoint + API key | ||
| - OpenWeatherMap API key (for weather functionality) | ||
| - Visual Studio 2022 or Visual Studio Code with C# Dev Kit | ||
|  | ||
| ## Setup Instructions | ||
|  | ||
| ### 1. Web API Configuration (One-time) | ||
|  | ||
| Update `appsettings.Development.json` in `ChatMobile.Api`: | ||
|  | ||
| ```json | ||
| { | ||
| "AzureOpenAI": { | ||
| "Endpoint": "https://your-endpoint.openai.azure.com/", | ||
| "ApiKey": "your-api-key-here", | ||
| "Model": "gpt-4o-mini" | ||
| }, | ||
| "WeatherApiKey": "your-openweather-api-key-here" | ||
| } | ||
| ``` | ||
|  | ||
| ### 2. MAUI Client Setup | ||
|  | ||
| The MAUI app will automatically retrieve and store credentials securely: | ||
|  | ||
| 1. Launch the app | ||
| 2. Navigate to the "Setup" tab | ||
| 3. Click "Load from Server" to fetch credentials from the Web API | ||
| 4. Credentials are stored securely using MAUI SecureStorage | ||
| 5. Return to "Chat" tab to start using AI features | ||
|  | ||
| Notes | ||
|  | ||
| - The client’s HttpClient for setup targets `http://127.0.0.1:5132/` (configured in `MauiProgram.cs`). | ||
| - The chat input uses Syncfusion `SfTextInputLayout` with a trailing send icon (`IconSend`). | ||
|  | ||
| ### 3. Alternative: User Secrets (Development) | ||
|  | ||
| For local development, configure the Web API using .NET User Secrets: | ||
|  | ||
| ```powershell | ||
| cd src/ChatMobile.Api | ||
| dotnet user-secrets set "AzureOpenAI:Endpoint" "https://your-endpoint.openai.azure.com/" | ||
| dotnet user-secrets set "AzureOpenAI:ApiKey" "your-api-key-here" | ||
| dotnet user-secrets set "WeatherApiKey" "your-openweather-api-key-here" | ||
| ``` | ||
|  | ||
| ## Running the Sample | ||
|  | ||
| ### Option 1: Visual Studio | ||
|  | ||
| 1. Open `ChatClientWithMobile.sln` | ||
| 2. Set both projects as startup projects: | ||
| - Right-click solution → Properties → Startup Project → Multiple startup projects | ||
| - Set both `ChatMobile.Api` and `ChatMobile.Client` to "Start" | ||
| 3. Press F5 to run both projects | ||
|  | ||
| ### Option 2: Command Line | ||
|  | ||
| Terminal 1 (Web API): | ||
|  | ||
| ```powershell | ||
| cd src/ChatMobile.Api | ||
| dotnet run | ||
| ``` | ||
|  | ||
| Terminal 2 (MAUI - Windows): | ||
|  | ||
| ```powershell | ||
| cd src/ChatMobile.Client | ||
| dotnet build -f net10.0-windows10.0.19041.0 | ||
| dotnet run -f net10.0-windows10.0.19041.0 | ||
| ``` | ||
|  | ||
| The Web API runs on `http://127.0.0.1:5132/` and MAUI connects to fetch credentials once. | ||
|  | ||
| ## Sample Prompts | ||
|  | ||
| Try these prompts to see AI function calling in action: | ||
|  | ||
| ### Weather Tool | ||
|  | ||
| - "What's the weather in Seattle, Washington?" | ||
| - "Check the weather in Tokyo and give me the temperature in Celsius" | ||
| - "Is it raining in London right now?" | ||
|  | ||
| ### Calculator Tool | ||
|  | ||
| - "Calculate 15% tip on $47.50" | ||
| - "What's 25 * 18 + 150?" | ||
| - "Calculate 30% of 250" | ||
| - "What is the square root of 144?" | ||
|  | ||
| ### File Operations (Mobile) | ||
|  | ||
| - "List the files in my Documents folder" | ||
| - "Show the top 10 largest files in Downloads" | ||
|  | ||
| ### System Info (Mobile) | ||
|  | ||
| - "Show me current battery level and state" | ||
| - "What device am I running on?" | ||
|  | ||
| ### Timer (Mobile) | ||
|  | ||
| - "Set a 5-minute timer for my coffee break" | ||
| - "Set a 20-minute focus timer" | ||
|  | ||
| ### General AI Chat | ||
|  | ||
| - "Explain how weather forecasting works" | ||
| - "What's the best way to calculate compound interest?" | ||
| - "Help me plan a trip considering the weather" | ||
|  | ||
| ## API Endpoints | ||
|  | ||
| ### Web API (`ChatMobile.Api`) | ||
|  | ||
| - **GET** `/api/credentials` | ||
| - Returns credentials for Azure OpenAI and weather services | ||
| - Used once by MAUI app during initial setup | ||
| - Response: `{ "AzureOpenAI": {...}, "WeatherApiKey": "..." }` | ||
|  | ||
| ## Security Architecture | ||
|  | ||
| ### Credential Flow | ||
|  | ||
| ```text | ||
| Initial Setup: | ||
| MAUI App → Web API `/credentials` → Secure Storage (encrypted) | ||
|  | ||
| Ongoing Usage: | ||
| MAUI App → Secure Storage → Direct Azure OpenAI → AI Response | ||
| ``` | ||
|  | ||
| ### Security Features | ||
|  | ||
| ✅ **Server credentials isolated** - Web API holds master credentials | ||
| ✅ **Client credentials encrypted** - MAUI SecureStorage provides platform-native encryption | ||
| ✅ **Minimal server interaction** - Credentials fetched once, stored securely | ||
| ✅ **Direct AI communication** - No server intermediation for AI requests | ||
| ✅ **Tool execution security** - All function calling happens in controlled client environment | ||
|  | ||
| ### Production Considerations | ||
|  | ||
| - Use Azure Key Vault for Web API credential storage | ||
| - Implement authentication for credential distribution endpoint | ||
| - Consider credential refresh mechanisms for long-lived apps | ||
| - Add certificate pinning for enhanced security | ||
| - Implement proper logging without exposing secrets | ||
|  | ||
| ## Troubleshooting | ||
|  | ||
| ### Common Issues | ||
|  | ||
| 1. **"No credentials configured"** | ||
| - Navigate to Setup tab and click "Load from Server" | ||
| - Ensure Web API is running and accessible | ||
| - Check Web API configuration has valid credentials | ||
|  | ||
| 2. **"Failed to connect to server"** | ||
| - Verify Web API is running on expected port (5132) | ||
| - Check MAUI HttpClient configuration in MauiProgram.cs | ||
| - Try using IP address (127.0.0.1) instead of localhost | ||
|  | ||
| 3. **Weather tool returns mock data** | ||
| - Expected when WeatherApiKey is not configured | ||
| - Add valid OpenWeatherMap API key to Web API configuration | ||
|  | ||
| 4. **AI responses fail** | ||
| - Verify Azure OpenAI endpoint and API key are correct | ||
| - Check network connectivity for direct Azure OpenAI access | ||
| - Review application logs for specific error messages | ||
|  | ||
| ## Architecture Highlights | ||
|  | ||
| ### Client-Centric Design Benefits | ||
|  | ||
| - **Reduced Server Load**: No AI processing on server | ||
| - **Better Performance**: Direct client-to-Azure communication | ||
| - **Enhanced Privacy**: User conversations never traverse your server | ||
| - **Simplified Deployment**: Minimal Web API requirements | ||
| - **Offline Capability**: Once configured, works without constant server connection | ||
|  | ||
| ### Microsoft.Extensions.AI Integration | ||
|  | ||
| ```csharp | ||
| // Build the chat client from Azure OpenAI and enable function invocation | ||
| var client = new ChatClientBuilder(aoaiClient.GetChatClient(model)) | ||
| .UseFunctionInvocation() | ||
| .Build(); | ||
|  | ||
| // Tools are AIFunction subclasses and are provided per request via ChatOptions.Tools | ||
| var tools = new AIFunction[] { weather, calculator, fileOps, systemInfo, timer }; | ||
| var response = await client.RespondAsync(messages, new ChatOptions { Tools = tools }); | ||
| ``` | ||
|  | ||
| ### Technology Stack | ||
|  | ||
| - **AI**: Microsoft.Extensions.AI with Azure OpenAI | ||
| - **Security**: MAUI SecureStorage (platform-native encryption) | ||
| - **Backend**: Minimal ASP.NET Core Web API (.NET 10) | ||
| - **Frontend**: .NET MAUI with CommunityToolkit.Mvvm | ||
| - **UI Framework**: Syncfusion.Maui.Toolkit | ||
| - **Communication**: Direct Azure OpenAI + minimal HTTP for setup | ||
|  | ||
| ### UI Highlights | ||
|  | ||
| - Input: Syncfusion `SfTextInputLayout` (Outlined) with a trailing send `ImageButton` using `IconSend` | ||
| - Resources: `IconSend` defined as `FontImageSource` (Fluent System Icons) in app styles | ||
|  | ||
| ## Related Samples | ||
|  | ||
| - **ChatClientWithTools**: Single-app version with environment variable configuration | ||
| - **SimpleChatClient**: Basic chat without tools for comparison | ||
|  | ||
| --- | ||
|  | ||
| 🔧 **Architecture**: Client-side AI with secure credential distribution | ||
| 🔒 **Security**: Platform-native encrypted credential storage | ||
| 📱 **Platform**: Cross-platform MAUI with Windows focus | ||
| 🤖 **AI**: Microsoft.Extensions.AI function calling with weather and calculator tools | ||
| ⚡ **Performance**: Direct client-to-Azure OpenAI communication | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
|  | ||
| Microsoft Visual Studio Solution File, Format Version 12.00 | ||
| # Visual Studio Version 17 | ||
| VisualStudioVersion = 17.0.31903.59 | ||
| MinimumVisualStudioVersion = 10.0.40219.1 | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatMobile.Api", "ChatMobile.Api\ChatMobile.Api.csproj", "{91261106-406D-419F-AE29-AD44AF79CB07}" | ||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatMobile.Client", "ChatMobile.Client\ChatMobile.Client.csproj", "{905EAD10-D800-4018-9AFC-6F8BFD8A2875}" | ||
| EndProject | ||
| Global | ||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
| Debug|Any CPU = Debug|Any CPU | ||
| Debug|x64 = Debug|x64 | ||
| Debug|x86 = Debug|x86 | ||
| Release|Any CPU = Release|Any CPU | ||
| Release|x64 = Release|x64 | ||
| Release|x86 = Release|x86 | ||
| EndGlobalSection | ||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Debug|x64.Build.0 = Debug|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Debug|x86.Build.0 = Debug|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Release|x64.ActiveCfg = Release|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Release|x64.Build.0 = Release|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {91261106-406D-419F-AE29-AD44AF79CB07}.Release|x86.Build.0 = Release|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Debug|x64.Build.0 = Debug|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Debug|x86.Build.0 = Debug|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Release|x64.ActiveCfg = Release|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Release|x64.Build.0 = Release|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {905EAD10-D800-4018-9AFC-6F8BFD8A2875}.Release|x86.Build.0 = Release|Any CPU | ||
| EndGlobalSection | ||
| GlobalSection(SolutionProperties) = preSolution | ||
| HideSolutionNode = FALSE | ||
| EndGlobalSection | ||
| EndGlobal | 
        
          
          
            13 changes: 13 additions & 0 deletions
          
          13 
        
  10.0/AI/ChatClientWithMobile/src/ChatMobile.Api/ChatMobile.Api.csproj
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|  | ||
| <PropertyGroup> | ||
| <TargetFramework>net10.0</TargetFramework> | ||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|  | ||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-preview.7.25380.108" /> | ||
| </ItemGroup> | ||
|  | ||
| </Project> | 
        
          
          
            14 changes: 14 additions & 0 deletions
          
          14 
        
  10.0/AI/ChatClientWithMobile/src/ChatMobile.Api/Models/CredentialResponse.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| namespace ChatMobile.Api.Models; | ||
|  | ||
| public class CredentialResponse | ||
| { | ||
| public required AzureOpenAICredentials AzureOpenAI { get; set; } | ||
| public required string WeatherApiKey { get; set; } | ||
| } | ||
|  | ||
| public class AzureOpenAICredentials | ||
| { | ||
| public required string Endpoint { get; set; } | ||
| public required string ApiKey { get; set; } | ||
| public required string Model { get; set; } | ||
| } | 
      
      Oops, something went wrong.
        
    
  
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could include a note indication that some tools are fake ones? (not important for the sample), like getting the battery.
Example:
Some tools used in this sample, such as battery level retrieval, are mock implementations and do not reflect actual device APIs. They are included for illustrative purposes only and may not function in a production environment.