From e53a729f01c1137f1a0312b3c8c820eacb3e3338 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 11:34:27 -0400 Subject: [PATCH 1/8] Refactor InteractiveCLI to improve message handling and command processing --- Public/New-Agent.ps1 | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/Public/New-Agent.ps1 b/Public/New-Agent.ps1 index d71dded..6723796 100644 --- a/Public/New-Agent.ps1 +++ b/Public/New-Agent.ps1 @@ -38,37 +38,44 @@ $InteractiveCLI = { $Emoji = '😎' ) + $agentResponse = $null if ($Message) { - $this.PrintResponse($Message) | Out-Host + $agentResponse = $this.PrintResponse($Message) + $agentResponse | Out-Host } while ($true) { $message = Read-Host "$Emoji $User" - if ([string]::IsNullOrEmpty($Message)) { + if ([string]::IsNullOrEmpty($message)) { Out-BoxedText -Text "Copied to clipboard." -Title "Information" -BoxColor "Green" | Out-Host - $agentResponse | clip break } - - $agentResponse = $this.PrintResponse($message) - - $formatParams = @{ - Text = $agentResponse - Title = "Agent Response" - BoxColor = "Blue" + elseif ($message.StartsWith("/")) { + switch ($message.ToLower()) { + "/clear" { Clear-Host } + default { Write-Host "Unknown command: $message" } + } } + else { + $agentResponse = $this.PrintResponse($message) + + $formatParams = @{ + Text = $agentResponse + Title = "Agent Response" + BoxColor = "Blue" + } + Out-BoxedText @formatParams | Out-Host - Out-BoxedText @formatParams | Out-Host - - $nextStepsParams = @{ - Text = "Follow up, Enter to copy & quit, Ctrl+C to quit." - Title = "Next Steps" - BoxColor = "Cyan" + $nextStepsParams = @{ + Text = "Follow up, Enter to copy & quit, Ctrl+C to quit." + Title = "Next Steps" + BoxColor = "Cyan" + } + + Out-BoxedText @nextStepsParams | Out-Host } - - Out-BoxedText @nextStepsParams | Out-Host } } From 0e5cf80ccce4cfcf676423098da9d97dcdc4855d Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:20:01 -0400 Subject: [PATCH 2/8] Add tests for InteractiveCLI slash command handling in New-Agent --- __tests__/New-Agent.tests.ps1 | 92 ++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/__tests__/New-Agent.tests.ps1 b/__tests__/New-Agent.tests.ps1 index 7c303c5..37b5d39 100644 --- a/__tests__/New-Agent.tests.ps1 +++ b/__tests__/New-Agent.tests.ps1 @@ -2,7 +2,6 @@ Describe "New-Agent" -Tag New-Agent { BeforeAll { Import-Module "$PSScriptRoot/../PSAI.psd1" -Force } - It "should have these parameters" { $actual = Get-Command New-Agent -ErrorAction SilentlyContinue @@ -19,4 +18,95 @@ Describe "New-Agent" -Tag New-Agent { $actual.Parameters.ShowToolCalls.SwitchParameter | Should -Be $true } + + Context "InteractiveCLI Slash Commands" { + + It "should handle the /clear command by calling Clear-Host" { + InModuleScope 'PSAI' { + $mockAgent = New-Agent -Name "TestAgent" + $global:callCount = 0 + $inputReader = { if ($global:callCount++ -eq 0) { '/clear' } else { '' } } + Mock Clear-Host { } + Mock Write-Host { } + Mock Out-BoxedText { } + Mock Out-Host { } + InModuleScope 'PSAI' { Mock Set-Clipboard { } } + $global:printResponseCallCount = 0 + $mockAgent | Add-Member -MemberType ScriptMethod -Name "PrintResponse" -Value { $global:printResponseCallCount++; 'Mocked response' } -Force + + # Act + $mockAgent.InteractiveCLI($null, 'User', '😎', $inputReader) + + # Assert + Assert-MockCalled Clear-Host -Exactly 1 + $global:printResponseCallCount | Should -Be 0 + } + } + + It "should handle unknown slash commands by writing an error message" { + InModuleScope 'PSAI' { + $mockAgent = New-Agent -Name "TestAgent" + $global:callCount = 0 + $inputReader = { if ($global:callCount++ -eq 0) { '/unknown' } else { '' } } + Mock Clear-Host { } + Mock Write-Host { } + Mock Out-BoxedText { } + Mock Out-Host { } + InModuleScope 'PSAI' { Mock Set-Clipboard { } } + $global:printResponseCallCount = 0 + $mockAgent | Add-Member -MemberType ScriptMethod -Name "PrintResponse" -Value { $global:printResponseCallCount++; 'Mocked response' } -Force + + # Act + $mockAgent.InteractiveCLI($null, 'User', '😎', $inputReader) + + # Assert + Assert-MockCalled Write-Host -Exactly 1 -ParameterFilter { $Object -eq 'Unknown command: /unknown' } + $global:printResponseCallCount | Should -Be 0 + } + } + + It "should handle empty input by copying to clipboard and exiting" { + InModuleScope 'PSAI' { + $mockAgent = New-Agent -Name "TestAgent" + $inputReader = { '' } + Mock Clear-Host { } + Mock Write-Host { } + Mock Out-BoxedText { } + Mock Out-Host { } + InModuleScope 'PSAI' { Mock Set-Clipboard { } } + $global:printResponseCallCount = 0 + $mockAgent | Add-Member -MemberType ScriptMethod -Name "PrintResponse" -Value { $global:printResponseCallCount++; 'Mocked response' } -Force + + # Act + $mockAgent.InteractiveCLI($null, 'User', '😎', $inputReader) + + # Assert + InModuleScope 'PSAI' { Assert-MockCalled Set-Clipboard -Exactly 1 } + Assert-MockCalled Out-BoxedText -Exactly 1 + $global:printResponseCallCount | Should -Be 0 + } + } + + It "should handle normal messages by calling PrintResponse and displaying output" { + InModuleScope 'PSAI' { + $mockAgent = New-Agent -Name "TestAgent" + $global:callCount = 0 + $inputReader = { if ($global:callCount++ -eq 0) { 'Hello' } else { '' } } + Mock Clear-Host { } + Mock Write-Host { } + Mock Out-BoxedText { } + Mock Out-Host { } + InModuleScope 'PSAI' { Mock Set-Clipboard { } } + $global:printResponseCallCount = 0 + $mockAgent | Add-Member -MemberType ScriptMethod -Name "PrintResponse" -Value { $global:printResponseCallCount++; 'Mocked response' } -Force + + # Act + $mockAgent.InteractiveCLI($null, 'User', '😎', $inputReader) + + # Assert + Assert-MockCalled Out-BoxedText -Exactly 3 + $global:printResponseCallCount | Should -Be 1 + } + } + } } \ No newline at end of file From 3fbb35ae243b3ed2a878ea2d2c43f7d7f8fa1c68 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:20:10 -0400 Subject: [PATCH 3/8] Add InputReader parameter to InteractiveCLI for customizable input handling --- Public/New-Agent.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Public/New-Agent.ps1 b/Public/New-Agent.ps1 index 6723796..1a7324c 100644 --- a/Public/New-Agent.ps1 +++ b/Public/New-Agent.ps1 @@ -35,7 +35,8 @@ $InteractiveCLI = { param( $Message, $User = 'User', - $Emoji = '😎' + $Emoji = '😎', + $InputReader = { $host.UI.ReadLine() } ) $agentResponse = $null @@ -45,11 +46,11 @@ $InteractiveCLI = { } while ($true) { - $message = Read-Host "$Emoji $User" + $message = & $InputReader if ([string]::IsNullOrEmpty($message)) { Out-BoxedText -Text "Copied to clipboard." -Title "Information" -BoxColor "Green" | Out-Host - $agentResponse | clip + Set-Clipboard -Value $agentResponse break } elseif ($message.StartsWith("/")) { From 28b9f8296355b53bb669d14910a5cb42de593f06 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:21:12 -0400 Subject: [PATCH 4/8] Bump module version to 0.5.1 and comment out agent tool and assistant imports --- PSAI.psd1 | 2 +- PSAI.psm1 | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/PSAI.psd1 b/PSAI.psd1 index 0a3ace0..cb5480c 100644 --- a/PSAI.psd1 +++ b/PSAI.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSAI.psm1' - ModuleVersion = '0.5.0' + ModuleVersion = '0.5.1' GUID = '68662d19-a8f1-484f-b1b7-3bf0e8a436df' Author = 'Douglas Finke' CompanyName = 'Doug Finke' diff --git a/PSAI.psm1 b/PSAI.psm1 index a4a7557..8aa64ac 100644 --- a/PSAI.psm1 +++ b/PSAI.psm1 @@ -4,14 +4,14 @@ . $PSScriptRoot/Private/Get-MultipartFormData.ps1 . $PSScriptRoot/Private/Get-ToolProperty.ps1 -# Agent Tools -Import-Module $PSScriptRoot/Public/Tools/CalculatorTool.psm1 -Import-Module $PSScriptRoot/Public/Tools/TavilyTool.psm1 -Import-Module $PSScriptRoot/Public/Tools/StockTickerTool.psm1 -Import-Module $PSScriptRoot/Public/Tools/YouTubeTool.psm1 +# # Agent Tools +# Import-Module $PSScriptRoot/Public/Tools/CalculatorTool.psm1 +# Import-Module $PSScriptRoot/Public/Tools/TavilyTool.psm1 +# Import-Module $PSScriptRoot/Public/Tools/StockTickerTool.psm1 +# Import-Module $PSScriptRoot/Public/Tools/YouTubeTool.psm1 -# Agent Assistants -Import-Module $PSScriptRoot/Public/Tools/YouTubeAssistant.psm1 +# # Agent Assistants +# Import-Module $PSScriptRoot/Public/Tools/YouTubeAssistant.psm1 # Public Functions . $PSScriptRoot/Public/Invoke-QuickPrompt.ps1 From bac8eef95a90ece2661713582430fde16acc667f Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:28:33 -0400 Subject: [PATCH 5/8] Add slash command support to InteractiveCLI and update changelog --- README.md | 18 ++++++++++++++++++ changelog.md | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 1237a80..8a60bc8 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,24 @@ $agent = New-Agent -Tools $tools -ShowToolCalls $agent | Get-AgentResponse 'What did Microsoft close at and the latest news for them?' ``` +## Slash Commands + +PSAI Agents now support slash commands in interactive sessions, allowing you to perform quick actions without leaving the conversation flow. + +### Available Commands + +- **`/clear`**: Clears the console screen, providing a clean slate for your interaction. + +### Usage + +In an interactive agent session, simply type a slash command at the prompt: + +``` +/clear +``` + +This will execute the command immediately. Unknown commands will display an error message, and normal input continues the conversation with the agent. + ## Convert Your Repositories to AI-Ready Format The `ConvertTo-AIPrompt` function packages any GitHub repository into an AI-optimized XML format, making it easy to feed your codebase to AI tools like ChatGPT, Claude, or Gemini. diff --git a/changelog.md b/changelog.md index 4e786f0..c688bdc 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +## v0.5.1 + +- Added slash command support to InteractiveCLI +- Refactored InteractiveCLI for improved message handling and command processing +- Added InputReader parameter to InteractiveCLI for customizable input handling +- Added tests for InteractiveCLI slash command handling +- Bumped module version to 0.5.1 + ## v0.4.12 Thank you to https://github.com/jmkloz for the PR! From 678d98401f60a9c80629853a175e46370282f5f1 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:36:09 -0400 Subject: [PATCH 6/8] Update README.md to comment out sections on modular tools and creating agents --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8a60bc8..12d2f52 100644 --- a/README.md +++ b/README.md @@ -117,16 +117,16 @@ Run either of these commands in PowerShell to output all files in a directory. Autonomous agents are AI-driven entities capable of making decisions and completing tasks without continuous human guidance. PSAI Agents combine the scripting power of PowerShell with the intelligence of OpenAI’s models to automate workflows that require both information processing and decision-making capabilities. ### Features of PSAI Agents -- **Modular Tools Integration**: Agents can leverage various specialized tools, such as: + - **Customizable Agents**: Create agents that use predefined tools or add custom ones. Easily expand agent capabilities by registering new tools tailored to specific needs. - **Natural Language Interaction**: Utilize OpenAI models to interpret complex prompts and provide contextual, intelligent responses using natural language. -### Creating Your First Agent + ### Examples: What PSAI Agents Can Do @@ -161,7 +161,7 @@ $SecretAgent = New-Agent -Instructions "Recipes should be under 5 ingredients" $SecretAgent | Get-AgentResponse 'Share a breakfast recipe.' ``` -#### **Calculator Tool** + ## Slash Commands From 11a755ea03f8a1c7d5c0ca64112f6b04cf2c4bc8 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:36:17 -0400 Subject: [PATCH 7/8] Comment out agent tools and assistants in module export list --- PSAI.psd1 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/PSAI.psd1 b/PSAI.psd1 index cb5480c..1e83929 100644 --- a/PSAI.psd1 +++ b/PSAI.psd1 @@ -22,16 +22,16 @@ PSAI brings OpenAI ChatGPT to PowerShell, leveraging advanced AI capabilities in 'Invoke-OAIBeta' 'Get-ToolProperty' - # Agent Tools - 'New-CalculatorTool' - 'New-TavilyAITool' - 'New-StockTickerTool' - 'New-YouTubeTool' + # # Agent Tools + # 'New-CalculatorTool' + # 'New-TavilyAITool' + # 'New-StockTickerTool' + # 'New-YouTubeTool' - # Agent Assistants - 'Invoke-YouTubeAIAssistant' - 'Search-YouTube' - 'Get-YouTubeTranscript' + # # Agent Assistants + # 'Invoke-YouTubeAIAssistant' + # 'Search-YouTube' + # 'Get-YouTubeTranscript' # Public 'Out-BoxedText' From 70a46310bdb3f88283d5c44ff5683dd451298838 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 3 Sep 2025 12:40:56 -0400 Subject: [PATCH 8/8] Comment out CalculatorTool registration test in Register-Tool tests --- __tests__/Register-Tool.tests.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/__tests__/Register-Tool.tests.ps1 b/__tests__/Register-Tool.tests.ps1 index fb2a97d..b87cec3 100644 --- a/__tests__/Register-Tool.tests.ps1 +++ b/__tests__/Register-Tool.tests.ps1 @@ -17,12 +17,12 @@ Describe "Register-Tool" -Tag Register-Tool { $actual.Parameters.Strict.SwitchParameter | Should -Be $true } - it "CalculatorTool should register correctly" { - $actual = New-CalculatorTool + # it "CalculatorTool should register correctly" { + # $actual = New-CalculatorTool - $actual | Should -Not -BeNullOrEmpty - $actual.Count | Should -Be 8 - } + # $actual | Should -Not -BeNullOrEmpty + # $actual.Count | Should -Be 8 + # } it "Get-ChildItem should register correctly" { $actual = Register-Tool "Get-ChildItem"