UNPKG

al-development-collection

Version:

AI Native AL Development toolkit for Microsoft Dynamics 365 Business Central with GitHub Copilot integration

375 lines (285 loc) 11.7 kB
--- agent: agent description: 'Register a new Copilot capability in Business Central. Creates enum extension, install codeunit, and isolated storage wrapper for Azure OpenAI integration.' tools: ['runCommands', 'runTasks', 'edit', 'runNotebooks', 'search', 'new', 'Microsoft Docs/*', 'Azure MCP/search', 'extensions', 'runSubagent', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'openSimpleBrowser', 'fetch', 'githubRepo', 'ms-dynamics-smb.al/al_build', 'ms-dynamics-smb.al/al_insert_event', 'ms-dynamics-smb.al/al_incremental_publish', 'ms-vscode.vscode-websearchforcopilot/websearch', 'todos', 'runTests'] model: Claude Sonnet 4.5 --- # Copilot Capability Registration Workflow Complete workflow to register a new Copilot capability in Business Central, including enum extension, capability registration, and Azure OpenAI configuration. ## Objective Create all necessary components to register a custom Copilot capability that can be used with Azure OpenAI services in Business Central. ## Context Loading Phase Before starting, review: - [Existing Copilot implementations in codebase] - [Microsoft Docs: Build Copilot Capability](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/ai-build-capability-in-al) - [Registered Copilot capabilities](https://github.com/microsoft/BCTech/blob/master/samples/AzureOpenAI/2-ItemSubstitution/CopilotCodeunits/CapabilitiesSetup.Codeunit.al) - [app.json for object ID ranges] - [Existing enum extensions] ## Prerequisites - Business Central AL workspace - Available object ID range - Azure OpenAI resource (development) or commitment to use Microsoft managed resources (production) - Understanding of Copilot feature to be implemented ## Step-by-Step Process ### Phase 1: Gather Information Ask the user for: 1. **Capability Name**: What is the name of this Copilot capability? - Example: "Sales Analysis", "Inventory Optimization", "Invoice Matching" 2. **Capability Purpose**: What will this Copilot do? - Brief description of the feature 3. **Object ID Range**: What object IDs should be used? - Check app.json for available ranges - Suggest appropriate IDs based on existing objects 4. **Namespace**: What namespace/prefix to use? - Example: "MyCompany.CopilotFeatures" 5. **Azure OpenAI Setup**: Will you use: - Microsoft managed resources (recommended for production) - Own Azure OpenAI subscription (required for development) ### Phase 2: Create Enum Extension Generate the enum extension file: **File**: `<CapabilityName>.EnumExt.al` **Template**: ```al namespace <Namespace>; using System.AI; enumextension <ObjectID> "<Enum Extension Name>" extends "Copilot Capability" { value(<Value>; "<Capability Name>") { Caption = '<User-Friendly Caption>'; } } ``` **Validation**: - [ ] Enum value is within object ID range - [ ] Caption is user-friendly and descriptive - [ ] Namespace is correctly defined - [ ] File name follows naming convention ### Phase 3: Create Install Codeunit Generate the install codeunit for capability registration: **File**: `<CapabilityName>Setup.Codeunit.al` **Template**: ```al namespace <Namespace>; using System.AI; codeunit <ObjectID> "<Capability Name> Setup" { Subtype = Install; InherentEntitlements = X; InherentPermissions = X; Access = Internal; trigger OnInstallAppPerDatabase() begin RegisterCapability(); SetupSecrets(); end; local procedure RegisterCapability() var CopilotCapability: Codeunit "Copilot Capability"; LearnMoreUrlTxt: Label 'https://learn.microsoft.com/dynamics365/business-central/', Locked = true; begin if not CopilotCapability.IsCapabilityRegistered(Enum::"Copilot Capability"::"<Capability Name>") then CopilotCapability.RegisterCapability( Enum::"Copilot Capability"::"<Capability Name>", Enum::"Copilot Availability"::Preview, LearnMoreUrlTxt); end; local procedure SetupSecrets() var IsolatedStorageWrapper: Codeunit "Isolated Storage Wrapper"; begin // IMPORTANT: Configure Azure OpenAI secrets // For development: Set up your own Azure OpenAI credentials // For production: Use Microsoft's managed resources Error('Configure your Azure OpenAI secrets before publishing. See IsolatedStorageWrapper codeunit.'); // Development configuration (uncomment and configure): // IsolatedStorageWrapper.SetSecretKey('YOUR_AZURE_OPENAI_KEY'); // IsolatedStorageWrapper.SetDeployment('gpt-4o'); // IsolatedStorageWrapper.SetEndpoint('https://your-resource.openai.azure.com/'); end; } ``` **Validation**: - [ ] Codeunit ID is within range - [ ] Capability name matches enum extension - [ ] Error message reminds developer to configure secrets - [ ] Access is set to Internal - [ ] Subtype is Install ### Phase 4: Create or Update Isolated Storage Wrapper Check if `IsolatedStorageWrapper` codeunit exists. If not, create it: **File**: `IsolatedStorageWrapper.Codeunit.al` **Template**: ```al namespace <Namespace>; codeunit <ObjectID> "Isolated Storage Wrapper" { Access = Internal; procedure GetSecretKey(): Text var Secret: Text; begin if IsolatedStorage.Get('AzureOpenAIKey', DataScope::Module, Secret) then exit(Secret); Error('Azure OpenAI key not configured. Configure in install codeunit.'); end; procedure SetSecretKey(NewKey: Text) begin IsolatedStorage.Set('AzureOpenAIKey', NewKey, DataScope::Module); end; procedure GetDeployment(): Text var Deployment: Text; begin if IsolatedStorage.Get('AzureOpenAIDeployment', DataScope::Module, Deployment) then exit(Deployment); exit('gpt-4o'); // Default deployment end; procedure SetDeployment(NewDeployment: Text) begin IsolatedStorage.Set('AzureOpenAIDeployment', NewDeployment, DataScope::Module); end; procedure GetEndpoint(): Text var Endpoint: Text; begin if IsolatedStorage.Get('AzureOpenAIEndpoint', DataScope::Module, Endpoint) then exit(Endpoint); Error('Azure OpenAI endpoint not configured. Configure in install codeunit.'); end; procedure SetEndpoint(NewEndpoint: Text) begin IsolatedStorage.Set('AzureOpenAIEndpoint', NewEndpoint, DataScope::Module); end; } ``` **Validation**: - [ ] Codeunit uses IsolatedStorage for security - [ ] Error messages are helpful - [ ] Default deployment is modern (gpt-4o) - [ ] Access is Internal ### Phase 5: Update Permission Set Add permissions for the new objects: **File**: Update existing permission set or create new one **Template**: ```al permissionset <ObjectID> "<Capability Name> Permissions" { Assignable = true; Caption = '<Capability Name> Copilot'; Permissions = codeunit "<Capability Name> Setup" = X, codeunit "Isolated Storage Wrapper" = X; // Add more permissions as needed for pages, tables, etc. } ``` **Validation**: - [ ] All created codeunits are included - [ ] Permission set is assignable - [ ] Caption is user-friendly ### Phase 6: Build and Test 1. **Compile the code**: ``` Use al_build tool ``` 2. **Check for errors**: ``` Review problems panel ``` 3. **Publish to development environment**: ``` Use al_incremental_publish tool ``` 4. **Verify capability registration**: - Open Business Central - Search for "Copilot AI Capabilities" - Verify your capability appears ### Phase 7: Document the Setup Create a README or comment block with: ```markdown # <Capability Name> Copilot Capability ## Setup Instructions ### Development Environment 1. Obtain Azure OpenAI resource: - Create resource in Azure Portal - Get endpoint URL, deployment name, and API key 2. Configure secrets: - Open `<Capability Name>Setup.Codeunit.al` - Uncomment and configure SetSecretKey, SetDeployment, SetEndpoint - Remove or comment the Error() call 3. Publish extension ### Production Environment For production, use Microsoft's managed Azure OpenAI resources: - No secret configuration needed - Use SetManagedResourceAuthorization in your code - Automatic scaling and reliability ## Next Steps - Create PromptDialog page: Use `@workspace use al-copilot-promptdialog` - Implement AI logic - Add tests: Use `@workspace use al-copilot-test` ``` ## Structured Output Requirements Deliver the following files: - [ ] `<CapabilityName>.EnumExt.al` - Enum extension - [ ] `<CapabilityName>Setup.Codeunit.al` - Install codeunit - [ ] `IsolatedStorageWrapper.Codeunit.al` - Secrets management (if not exists) - [ ] Permission set updates - [ ] Setup documentation ## Human Validation Gate 🚨 **STOP**: Before proceeding, confirm with the user: - [ ] Object IDs are correct and available - [ ] Capability name is approved - [ ] Azure OpenAI resource availability confirmed (dev) or managed resources approved (prod) - [ ] Files compile without errors - [ ] Capability appears in "Copilot AI Capabilities" page ## Common Issues & Solutions ### Issue: "Object ID already in use" **Solution**: Check app.json idRanges and choose available ID ### Issue: "Capability already registered" **Solution**: Check if enum value name conflicts with existing capability ### Issue: "Azure OpenAI key not configured" error **Solution**: - For development: Configure secrets in install codeunit - For production: Use SetManagedResourceAuthorization instead ### Issue: Permission errors **Solution**: Ensure permission set includes all created objects ## Next Steps After capability registration: 1. Create PromptDialog page: `@workspace use al-copilot-promptdialog` 2. Implement AI generation logic 3. Add testing: `@workspace use al-copilot-test` ## Success Criteria - [ ] Enum extension created and compiles - [ ] Install codeunit created and compiles - [ ] IsolatedStorage wrapper available - [ ] Permission set updated - [ ] Code builds successfully - [ ] Capability visible in BC admin interface - [ ] Documentation provided ### Solution example namespace CopilotToolkitDemo.ItemSubstitution; using System.AI; codeunit 54310 "Capabilities Setup" { Subtype = Install; InherentEntitlements = X; InherentPermissions = X; Access = Internal; trigger OnInstallAppPerDatabase() begin RegisterCapability(); end; local procedure RegisterCapability() var CopilotCapability: Codeunit "Copilot Capability"; LearnMoreUrlTxt: Label 'https://example.com/CopilotToolkit', Locked = true; begin if not CopilotCapability.IsCapabilityRegistered(Enum::"Copilot Capability"::"Find Item Substitutions") then CopilotCapability.RegisterCapability(Enum::"Copilot Capability"::"Find Item Substitutions", Enum::"Copilot Availability"::Preview, Enum::"Copilot Billing Type"::"Microsoft Billed", 'https://about:none'); end; } ### --- **Framework Compliance**: This workflow implements AI-Native Instructions Architecture Layer 2 (Agent Primitives - Agentic Workflows) with Context Loading, Human Validation Gates, and Structured Output Requirements.