Skip to content
20 changes: 10 additions & 10 deletions PSAI.psd1
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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'
Expand Down
14 changes: 7 additions & 7 deletions PSAI.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 29 additions & 21 deletions Public/New-Agent.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,48 @@ $InteractiveCLI = {
param(
$Message,
$User = 'User',
$Emoji = '😎'
$Emoji = '😎',
$InputReader = { $host.UI.ReadLine() }
)

$agentResponse = $null
if ($Message) {
$this.PrintResponse($Message) | Out-Host
$agentResponse = $this.PrintResponse($Message)
$agentResponse | Out-Host
}

while ($true) {
$message = Read-Host "$Emoji $User"
$message = & $InputReader

if ([string]::IsNullOrEmpty($Message)) {
if ([string]::IsNullOrEmpty($message)) {
Out-BoxedText -Text "Copied to clipboard." -Title "Information" -BoxColor "Green" | Out-Host

$agentResponse | clip
Set-Clipboard -Value $agentResponse
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
}
}

Expand Down
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
<!-- - **Modular Tools Integration**: Agents can leverage various specialized tools, such as:
- **CalculatorTool**: Handles arithmetic and mathematical operations.
- **WebSearchTool**: Retrieves information from the web.
- **StockTickerTool**: Fetches stock information in real time.
- **StockTickerTool**: Fetches stock information in real time. -->

- **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
<!-- ### Creating Your First Agent

Here’s how to create a simple agent using the **CalculatorTool**:

Expand All @@ -147,7 +147,7 @@ The agent will respond with step-by-step calculations, such as:
Multiplying 3 and 5 to get 15
Adding 15 and 6 to get 21
The result of (3 * 5 + 6) is 21, and 21 is not a prime number.
```
``` -->

### Examples: What PSAI Agents Can Do

Expand All @@ -161,7 +161,7 @@ $SecretAgent = New-Agent -Instructions "Recipes should be under 5 ingredients"
$SecretAgent | Get-AgentResponse 'Share a breakfast recipe.'
```

#### **Calculator Tool**
<!-- #### **Calculator Tool**
A calculator agent can solve arithmetic problems and check properties like primality:

```powershell
Expand Down Expand Up @@ -207,7 +207,25 @@ $tools = $(

$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

Expand Down
92 changes: 91 additions & 1 deletion __tests__/New-Agent.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
}
}
}
}
10 changes: 5 additions & 5 deletions __tests__/Register-Tool.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -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!
Expand Down
Loading