5757 1. Install GitHub CLI and authenticate: gh auth login
5858 2. Choose LLM provider:
5959 - For GitHub Models: gh extension install github/gh-models
60+ - For GitHub Copilot: Install GitHub Copilot CLI from https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli
6061 - For OpenAI: `$ env:OPENAI_API_KEY = "your-key"
62+ - For Azure OpenAI: `$ env:AZURE_OPENAI_API_KEY = "your-key" and set LlmBaseUrl in config.ps1
6163 - For others: Set appropriate API key
6264 3. Edit config.ps1 to customize settings
6365"@
@@ -96,21 +98,22 @@ try {
9698 exit 1
9799}
98100
99- # Check LLM API key or GitHub CLI for GitHub Models
101+ # Check LLM API key or GitHub CLI for GitHub Models/Copilot
100102$llmProvider = $Config.LlmProvider
101103$apiKey = switch ($llmProvider ) {
102104 " openai" { $env: OPENAI_API_KEY }
103105 " anthropic" { $env: ANTHROPIC_API_KEY }
104106 " azure-openai" { $env: AZURE_OPENAI_API_KEY }
105107 " github-models" { $null } # No API key needed for GitHub Models
108+ " github-copilot" { $null } # No API key needed for GitHub Copilot CLI
106109 default { $env: OPENAI_API_KEY }
107110}
108111
109112if ($llmProvider -eq " github-models" ) {
110113 # Check if gh-models extension is installed
111114 try {
112- $extensions = gh extension list 2> $null
113- if ($extensions -notmatch " github/gh-models " ) {
115+ $modelsExtension = gh extension list 2> $null | Select-String " gh models "
116+ if (-not $modelsExtension ) {
114117 Write-Error " ❌ GitHub Models extension not found. Install with: gh extension install github/gh-models"
115118 exit 1
116119 }
@@ -119,12 +122,27 @@ if ($llmProvider -eq "github-models") {
119122 Write-Error " ❌ Could not check GitHub Models extension: $ ( $_.Exception.Message ) "
120123 exit 1
121124 }
125+ } elseif ($llmProvider -eq " github-copilot" ) {
126+ # Check if standalone GitHub Copilot CLI is installed
127+ try {
128+ $copilotVersion = copilot -- version 2> $null
129+ if (-not $copilotVersion -or $LASTEXITCODE -ne 0 ) {
130+ Write-Error " ❌ GitHub Copilot CLI not found. Install from: https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli"
131+ exit 1
132+ }
133+ Write-Host " ✅ GitHub Copilot CLI found (version: $ ( $copilotVersion.Split (" `n " )[0 ]) )" - ForegroundColor Green
134+ } catch {
135+ Write-Error " ❌ Could not check GitHub Copilot CLI: $ ( $_.Exception.Message ) "
136+ Write-Error " Install from: https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli"
137+ exit 1
138+ }
122139} elseif (-not $apiKey ) {
123140 Write-Error " ❌ No LLM API key found. Set environment variable:"
124141 Write-Host " For OpenAI: `$ env:OPENAI_API_KEY = 'your-key'"
125142 Write-Host " For Anthropic: `$ env:ANTHROPIC_API_KEY = 'your-key'"
126143 Write-Host " For Azure OpenAI: `$ env:AZURE_OPENAI_API_KEY = 'your-key'"
127144 Write-Host " For GitHub Models: Use 'github-models' provider (no key needed)"
145+ Write-Host " For GitHub Copilot: Install GitHub Copilot CLI from https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli (no key needed)"
128146 exit 1
129147} else {
130148 Write-Host " ✅ LLM API key found ($llmProvider )" - ForegroundColor Green
@@ -216,15 +234,7 @@ function Limit-Text {
216234function Get-UrlEncodedText {
217235 param ([string ]$text )
218236
219- # Basic URL encoding for GitHub issue URLs
220- $encoded = $text -replace ' \r\n' , ' %0A' -replace ' \n' , ' %0A' -replace ' \r' , ' %0A'
221- $encoded = $encoded -replace ' ' , ' %20' -replace ' #' , ' %23' -replace ' &' , ' %26'
222- $encoded = $encoded -replace ' \[' , ' %5B' -replace ' \]' , ' %5D' -replace ' \(' , ' %28' -replace ' \)' , ' %29'
223- $encoded = $encoded -replace ' :' , ' %3A' -replace ' ;' , ' %3B' -replace ' \?' , ' %3F' -replace ' =' , ' %3D'
224- $encoded = $encoded -replace ' @' , ' %40' -replace ' \+' , ' %2B' -replace ' \$' , ' %24'
225- $encoded = $encoded -replace ' "' , ' %22' -replace " '" , ' %27' -replace ' <' , ' %3C' -replace ' >' , ' %3E'
226-
227- return $encoded
237+ return [System.Web.HttpUtility ]::UrlEncode($text )
228238}
229239
230240# Function to fetch issue template from GitHub
@@ -452,66 +462,149 @@ function Invoke-LlmApi {
452462 $ghArgs += @ (" --system-prompt" , $SystemPrompt )
453463 }
454464
455- $response = & gh @ghArgs
465+ $response = gh @ghArgs
456466 return $response -join " `n "
457467 }
458468 catch {
459469 Write-Error " GitHub Models API call failed: $ ( $_.Exception.Message ) "
460470 return $null
461471 }
462472 }
463- default {
464- # Existing API-based providers
465- $headers = @ { ' Content-Type' = ' application/json' }
466- $body = @ {}
467- $endpoint = " "
468-
469- switch ($Config.LlmProvider ) {
470- " openai" {
471- $endpoint = if ($Config.LlmBaseUrl ) { " $ ( $Config.LlmBaseUrl ) /chat/completions" } else { " https://api.openai.com/v1/chat/completions" }
472- $headers [' Authorization' ] = " Bearer $apiKey "
473-
474- $messages = @ ()
475- if ($SystemPrompt ) { $messages += @ { role = " system" ; content = $SystemPrompt } }
476- $messages += @ { role = " user" ; content = $Prompt }
477-
478- $body = @ {
479- model = $Config.LlmModel
480- messages = $messages
481- max_tokens = $MaxTokens
482- temperature = 0.1
483- }
473+ " github-copilot" {
474+ # Use GitHub Copilot CLI in programmatic mode
475+ try {
476+ # Combine system prompt and user prompt, emphasizing text-only response
477+ $fullPrompt = if ($SystemPrompt ) {
478+ " $SystemPrompt `n`n IMPORTANT: Please respond with only the requested text content. Do not create, modify, or execute any files. Just return the text response.`n`n $Prompt "
479+ } else {
480+ " IMPORTANT: Please respond with only the requested text content. Do not create, modify, or execute any files. Just return the text response.`n`n $Prompt "
484481 }
485- " anthropic" {
486- $endpoint = if ($Config.LlmBaseUrl ) { " $ ( $Config.LlmBaseUrl ) /messages" } else { " https://api.anthropic.com/v1/messages" }
487- $headers [' x-api-key' ] = $apiKey
488- $headers [' anthropic-version' ] = " 2023-06-01"
489-
490- $fullPrompt = if ($SystemPrompt ) { " $SystemPrompt `n`n Human: $Prompt `n`n Assistant:" } else { " Human: $Prompt `n`n Assistant:" }
491-
492- $body = @ {
493- model = $Config.LlmModel
494- max_tokens = $MaxTokens
495- messages = @ (@ { role = " user" ; content = $fullPrompt })
496- temperature = 0.1
482+
483+ # Use copilot with -p flag for programmatic mode and suppress logs
484+ $rawResponse = copilot - p $fullPrompt -- log- level none -- allow- all- tools
485+
486+ # Parse the response to extract just the content, removing usage statistics
487+ # The response format typically includes usage stats at the end starting with "Total usage est:"
488+ $lines = $rawResponse -split " `n "
489+ $contentLines = @ ()
490+ $foundUsageStats = $false
491+
492+ foreach ($line in $lines ) {
493+ if ($line -match " ^Total usage est:" -or $line -match " ^Total duration" ) {
494+ $foundUsageStats = $true
495+ break
496+ }
497+ if (-not $foundUsageStats ) {
498+ $contentLines += $line
497499 }
498500 }
501+
502+ # Join the content lines and trim whitespace
503+ $response = ($contentLines -join " `n " ).Trim()
504+ return $response
505+ }
506+ catch {
507+ Write-Error " GitHub Copilot CLI call failed: $ ( $_.Exception.Message ) "
508+ return $null
509+ }
510+ }
511+ " openai" {
512+ # OpenAI API
513+ $endpoint = if ($Config.LlmBaseUrl ) { " $ ( $Config.LlmBaseUrl ) /chat/completions" } else { " https://api.openai.com/v1/chat/completions" }
514+ $headers = @ {
515+ ' Content-Type' = ' application/json'
516+ ' Authorization' = " Bearer $apiKey "
517+ }
518+
519+ $messages = @ ()
520+ if ($SystemPrompt ) { $messages += @ { role = " system" ; content = $SystemPrompt } }
521+ $messages += @ { role = " user" ; content = $Prompt }
522+
523+ $body = @ {
524+ model = $Config.LlmModel
525+ messages = $messages
526+ max_tokens = $MaxTokens
527+ temperature = 0.1
528+ }
529+
530+ try {
531+ $requestJson = $body | ConvertTo-Json - Depth 10
532+ $response = Invoke-RestMethod - Uri $endpoint - Method POST - Headers $headers - Body $requestJson
533+ return $response.choices [0 ].message.content
534+ }
535+ catch {
536+ Write-Error " OpenAI API call failed: $ ( $_.Exception.Message ) "
537+ return $null
538+ }
539+ }
540+ " anthropic" {
541+ # Anthropic API
542+ $endpoint = if ($Config.LlmBaseUrl ) { " $ ( $Config.LlmBaseUrl ) /messages" } else { " https://api.anthropic.com/v1/messages" }
543+ $headers = @ {
544+ ' Content-Type' = ' application/json'
545+ ' x-api-key' = $apiKey
546+ ' anthropic-version' = " 2023-06-01"
547+ }
548+
549+ $fullPrompt = if ($SystemPrompt ) { " $SystemPrompt `n`n Human: $Prompt `n`n Assistant:" } else { " Human: $Prompt `n`n Assistant:" }
550+
551+ $body = @ {
552+ model = $Config.LlmModel
553+ max_tokens = $MaxTokens
554+ messages = @ (@ { role = " user" ; content = $fullPrompt })
555+ temperature = 0.1
499556 }
500557
501558 try {
502559 $requestJson = $body | ConvertTo-Json - Depth 10
503560 $response = Invoke-RestMethod - Uri $endpoint - Method POST - Headers $headers - Body $requestJson
561+ return $response.content [0 ].text
562+ }
563+ catch {
564+ Write-Error " Anthropic API call failed: $ ( $_.Exception.Message ) "
565+ return $null
566+ }
567+ }
568+ " azure-openai" {
569+ # Azure OpenAI API
570+ # Endpoint format: https://{resource}.openai.azure.com/openai/deployments/{deployment}/chat/completions?api-version={api-version}
571+ if (-not $Config.LlmBaseUrl ) {
572+ Write-Error " Azure OpenAI requires LlmBaseUrl to be set in config (e.g., 'https://your-resource.openai.azure.com')"
573+ return $null
574+ }
575+
576+ $apiVersion = if ($Config.AzureApiVersion ) { $Config.AzureApiVersion } else { " 2024-02-15-preview" }
577+ $endpoint = " $ ( $Config.LlmBaseUrl ) /openai/deployments/$ ( $Config.LlmModel ) /chat/completions?api-version=$apiVersion "
578+
579+ $headers = @ {
580+ ' Content-Type' = ' application/json'
581+ ' api-key' = $apiKey
582+ }
504583
505- switch ($Config.LlmProvider ) {
506- " openai" { return $response.choices [0 ].message.content }
507- " anthropic" { return $response.content [0 ].text }
508- }
584+ $messages = @ ()
585+ if ($SystemPrompt ) { $messages += @ { role = " system" ; content = $SystemPrompt } }
586+ $messages += @ { role = " user" ; content = $Prompt }
587+
588+ $body = @ {
589+ messages = $messages
590+ max_tokens = $MaxTokens
591+ temperature = 0.1
592+ }
593+
594+ try {
595+ $requestJson = $body | ConvertTo-Json - Depth 10
596+ $response = Invoke-RestMethod - Uri $endpoint - Method POST - Headers $headers - Body $requestJson
597+ return $response.choices [0 ].message.content
509598 }
510599 catch {
511- Write-Error " LLM API call failed: $ ( $_.Exception.Message ) "
600+ Write-Error " Azure OpenAI API call failed: $ ( $_.Exception.Message ) "
512601 return $null
513602 }
514603 }
604+ default {
605+ Write-Error " Unknown LLM provider: $ ( $Config.LlmProvider ) "
606+ return $null
607+ }
515608 }
516609}
517610
0 commit comments