param(
    [switch]$SelfTest,
    [switch]$ProviderTest
)

# ===================================================================
# AgentOS Production Branch - Optimized Core Orchestrator
# ===================================================================

# --- UI IDENTIFIER ---
try {
    $Host.UI.RawUI.WindowTitle = "AgentOS - Production Multimodal Branch"
} catch {
    # Ignore error in Constrained Language Mode
}

# --- CONFIGURATION ---
$BaseDir = Split-Path $PSScriptRoot -Parent
$ConfigDir = Join-Path $BaseDir "Config"
$ProviderPath = Join-Path $ConfigDir "provider.json"
$ProvidersPath = Join-Path $ConfigDir "providers.json"
$ProviderExamplePath = Join-Path $ConfigDir "provider.example.json"
$KeyDir = Join-Path $ConfigDir "Keys"
$LegacyKeyPath = Join-Path $ConfigDir "GenAI_Key.txt"
$KeyPath = $LegacyKeyPath
$MemFile = Join-Path $BaseDir "Memory\chat_history.json"
$Endpoint = "https://api.example.com/v1/chat/completions"
$CurrentModel = "your-model-id"
$ActiveProviderName = "default"
$HistoryLimit = 30
$MaxAutoLoops = 12

# Startup: run /boot once, limit initial auto-loop to 3, then default to 12
$StartupBootDone = $false
$StartupLoopLimit = 3
$MaxAutoLoops = $StartupLoopLimit
$AutoLoopCount = 0
$AutoTrigger = $false

function Normalize-Endpoint([string]$Value) {
    if ([string]::IsNullOrWhiteSpace($Value)) { return $Value }
    $V = $Value.Trim()
    if ($V -match '/v1/?$') { return ($V.TrimEnd('/') + '/chat/completions') }
    return $V
}

function Write-PortableText([string]$Path, [string]$Value) {
    Set-Content -Path $Path -Value $Value -Encoding UTF8 -Force
}

function Resolve-ProviderKeyPath([string]$RelPath) {
    if ([string]::IsNullOrWhiteSpace($RelPath)) { return $LegacyKeyPath }
    if ($RelPath -match '^[A-Za-z]:\\|^\\\\|^/') { return $RelPath }
    return (Join-Path $BaseDir $RelPath)
}

function Get-RelativeProviderKeyPath([string]$FullPath) {
    if ([string]::IsNullOrWhiteSpace($FullPath)) { return "Config\GenAI_Key.txt" }
    if ($FullPath.StartsWith($BaseDir)) { return $FullPath.Substring($BaseDir.Length).TrimStart('\') }
    return $FullPath
}


function Select-Model {
    if (-not (Test-Path $ProvidersPath)) {
        Write-Host "[ERROR] Config\providers.json not found. Run installer first." -ForegroundColor Red
        return
    }
    $ProviderSet = Get-Content $ProvidersPath -Raw | ConvertFrom-Json
    $ProviderNames = $ProviderSet.providers.PSObject.Properties | ForEach-Object { $_.Name }
    if (-not $ProviderNames) {
        Write-Host "[ERROR] No providers configured." -ForegroundColor Red
        return
    }
    Write-Host "Available providers:" -ForegroundColor Cyan
    for ($i = 0; $i -lt $ProviderNames.Count; $i++) {
        $PData = $ProviderSet.providers.($ProviderNames[$i])
        Write-Host ("  {0}. {1}  ({2})" -f ($i+1), $ProviderNames[$i], $PData.endpoint) -ForegroundColor Yellow
    }
    $PChoice = Read-Host "Select provider (number)"
    try {
        $PIdx = [int]$PChoice - 1
        if ($PIdx -lt 0 -or $PIdx -ge $ProviderNames.Count) { throw }
        $SelectedProvider = $ProviderNames[$PIdx]
    } catch {
        Write-Host "[ERROR] Invalid provider selection." -ForegroundColor Red
        return
    }
    $PData = $ProviderSet.providers.$SelectedProvider
    $Models = @()
    if ($PData.models) {
        $Models = $PData.models
    } elseif ($PData.model) {
        $Models = @($PData.model)
    }
    if (-not $Models) {
        Write-Host ("[ERROR] No models configured for provider '{0}'." -f $SelectedProvider) -ForegroundColor Red
        return
    }
    Write-Host ("Available models for {0}:" -f $SelectedProvider) -ForegroundColor Cyan
    for ($i = 0; $i -lt $Models.Count; $i++) {
        $Marker = if ($Models[$i] -eq $CurrentModel -and $SelectedProvider -eq $ActiveProviderName) { " <-- active" } else { "" }
        Write-Host ("  {0}. {1}{2}" -f ($i+1), $Models[$i], $Marker) -ForegroundColor Yellow
    }
    $MChoice = Read-Host "Select model (number or type name)"
    try {
        $MIdx = [int]$MChoice - 1
        if ($MIdx -lt 0 -or $MIdx -ge $Models.Count) { throw }
        $SelectedModel = $Models[$MIdx]
    } catch {
        $SelectedModel = $MChoice
    }
    Switch-Provider $SelectedProvider
    $CurrentModel = $SelectedModel
    Save-ActiveProviderConfig
    Write-Host ("[SYSTEM] Switched to provider: {0} | model: {1}" -f $ActiveProviderName, $CurrentModel) -ForegroundColor Green
}

function Save-ActiveProviderConfig {
    if (!(Test-Path $ConfigDir)) { New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null }
    $Endpoint = Normalize-Endpoint $Endpoint
    $KeyRel = Get-RelativeProviderKeyPath $KeyPath
    $LegacyProvider = [ordered]@{
        endpoint = $Endpoint
        model = $CurrentModel
        apiKey = ""
        apiKeySet = (Test-Path $KeyPath)
        keyFile = $KeyRel
        activeProvider = $ActiveProviderName
        installedAtUtc = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
    }
    Write-PortableText -Path $ProviderPath -Value (($LegacyProvider | ConvertTo-Json -Depth 8) + "`n")

    $ProviderSet = $null
    if (Test-Path $ProvidersPath) {
        try { $ProviderSet = Get-Content $ProvidersPath -Raw | ConvertFrom-Json } catch { $ProviderSet = $null }
    }
    if ($null -eq $ProviderSet) { $ProviderSet = [pscustomobject]@{ activeProvider = $ActiveProviderName; providers = [pscustomobject]@{} } }
    if ($null -eq $ProviderSet.providers) { $ProviderSet | Add-Member -NotePropertyName providers -NotePropertyValue ([pscustomobject]@{}) -Force }
    $ProviderSet.activeProvider = $ActiveProviderName
    $Entry = [ordered]@{ endpoint = $Endpoint; model = $CurrentModel; keyFile = $KeyRel; apiKeySet = (Test-Path $KeyPath); type = "openai-compatible" }
    $ProviderSet.providers | Add-Member -NotePropertyName $ActiveProviderName -NotePropertyValue $Entry -Force
    Write-PortableText -Path $ProvidersPath -Value (($ProviderSet | ConvertTo-Json -Depth 10) + "`n")
}

function Load-ProviderConfig {
    if (Test-Path $ProvidersPath) {
        try {
            $ProviderSet = Get-Content $ProvidersPath -Raw | ConvertFrom-Json
            if ($ProviderSet.activeProvider) { $script:ActiveProviderName = [string]$ProviderSet.activeProvider }
            $ProviderEntry = $ProviderSet.providers.$ActiveProviderName
            if ($null -eq $ProviderEntry -and $ProviderSet.providers.default) { $script:ActiveProviderName = "default"; $ProviderEntry = $ProviderSet.providers.default }
            if ($ProviderEntry.endpoint) { $script:Endpoint = Normalize-Endpoint ([string]$ProviderEntry.endpoint) }
            if ($ProviderEntry.model) { $script:CurrentModel = [string]$ProviderEntry.model }
            if ($ProviderEntry.keyFile) { $script:KeyPath = Resolve-ProviderKeyPath ([string]$ProviderEntry.keyFile) }
            return
        } catch {
            Write-Host "[WARNING] Could not read Config\providers.json: $($_.Exception.Message)" -ForegroundColor Yellow
        }
    }
    $SingleProviderPath = if (Test-Path $ProviderPath) { $ProviderPath } elseif (Test-Path $ProviderExamplePath) { $ProviderExamplePath } else { $null }
    if ($SingleProviderPath) {
        try {
            $ProviderConfig = Get-Content $SingleProviderPath -Raw | ConvertFrom-Json
            if ($ProviderConfig.endpoint) { $script:Endpoint = Normalize-Endpoint ([string]$ProviderConfig.endpoint) }
            if ($ProviderConfig.model) { $script:CurrentModel = [string]$ProviderConfig.model }
            if ($ProviderConfig.activeProvider) { $script:ActiveProviderName = [string]$ProviderConfig.activeProvider }
            if ($ProviderConfig.keyFile) { $script:KeyPath = Resolve-ProviderKeyPath ([string]$ProviderConfig.keyFile) }
        } catch {
            Write-Host "[WARNING] Could not read provider config: $($_.Exception.Message)" -ForegroundColor Yellow
        }
    }
}

function Switch-Provider([string]$Name) {
    if ([string]::IsNullOrWhiteSpace($Name)) { throw "Provider name is required." }
    if (!(Test-Path $ProvidersPath)) { throw "Config\providers.json not found. Run installer or create providers first." }
    $ProviderSet = Get-Content $ProvidersPath -Raw | ConvertFrom-Json
    $Entry = $ProviderSet.providers.$Name
    if ($null -eq $Entry) { throw "Provider '$Name' not found." }
    $script:ActiveProviderName = $Name
    $script:Endpoint = Normalize-Endpoint ([string]$Entry.endpoint)
    $script:CurrentModel = [string]$Entry.model
    if ($Entry.keyFile) { $script:KeyPath = Resolve-ProviderKeyPath ([string]$Entry.keyFile) } else { $script:KeyPath = $LegacyKeyPath }
    Save-ActiveProviderConfig
}

Load-ProviderConfig
$Uri = Normalize-Endpoint $Endpoint

function Invoke-AgentSelfTest {
    $Required = @(
        "Config\agent_config.json",
        "Config\provider.example.json",
        "Skills\PowerShell\Get-SkillsManifest.ps1",
        "Skills\PowerShell\Parse-DroppedFile.ps1",
        "Skills\Python\parse_binary_file.py"
    )
    $Missing = @()
    foreach ($Rel in $Required) {
        if (!(Test-Path (Join-Path $BaseDir $Rel))) { $Missing += $Rel }
    }
    if ($Missing.Count -gt 0) {
        Write-Host "SELFTEST FAIL: missing $($Missing -join ', ')" -ForegroundColor Red
        exit 1
    }
    Write-Host "SELFTEST PASS: workspace files present; provider=$ActiveProviderName; endpoint=$Endpoint; model=$CurrentModel" -ForegroundColor Green
    exit 0
}
if ($SelfTest) { Invoke-AgentSelfTest }

if ($ProviderTest) {
    Write-Host "[SYSTEM] Provider test target: $Endpoint | provider: $ActiveProviderName | model: $CurrentModel | keyFile: $KeyPath" -ForegroundColor Cyan
}

# --- API HEADERS ---
try {
    $ApiKey = ""
    if (Test-Path $KeyPath) {
        $RawApiKey = Get-Content $KeyPath -Raw
        if ($null -ne $RawApiKey) { $ApiKey = $RawApiKey.Trim() }
    } elseif (Test-Path $LegacyKeyPath) {
        $RawApiKey = Get-Content $LegacyKeyPath -Raw
        if ($null -ne $RawApiKey) { $ApiKey = $RawApiKey.Trim() }
    }
    $Headers = @{ "Content-Type"="application/json" }
    if (-not [string]::IsNullOrWhiteSpace($ApiKey)) { $Headers["Authorization"] = "Bearer $ApiKey" }
} catch {
    Write-Host "CRITICAL ERROR: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "Run Install Mix of Agents.bat and enter endpoint, model, and optional API key." -ForegroundColor Yellow
    exit 1
}

# --- FUNCTIONS ---
function Get-WorkspaceMap {
    $Manifest = "CURRENT WORKSPACE FILE MANIFEST:`n"
    Get-ChildItem -Path $BaseDir -Recurse -File | ForEach-Object {
        $Rel = $_.FullName.Replace("$BaseDir\", "")
        if ($Rel -notmatch 'Memory\\chat_history\.json|GenAI_Key\.txt|Config\\Keys|AgentOS.*?\.ps1') {
            $Manifest += "- $Rel`n"
        }
    }
    return $Manifest
}

function Get-BootPayload {
    $Payload = "[SYSTEM BOOT SEQUENCE]`n"
    foreach ($f in @("Config\identity.txt", "Config\user_profile.txt", "Config\environment.txt", "Memory\long_term_context.md")) {
        $path = Join-Path $BaseDir $f
        if (Test-Path $path) { $Payload += "--- $f ---`n" + (Get-Content $path -Raw) + "`n" }
    }
    $ManifestScript = Join-Path $BaseDir "Skills\PowerShell\Get-SkillsManifest.ps1"
    if (Test-Path $ManifestScript) {
        $Payload += "--- DYNAMIC SKILLS REGISTRY ---`n" + (& $ManifestScript) + "`n"
    }
    $ScriptPath = $MyInvocation.MyCommand.Path
    if ($ScriptPath -and (Test-Path $ScriptPath)) {
        $Payload += "--- $($MyInvocation.MyCommand.Name) (Source Code) ---`n" + (Get-Content $ScriptPath -Raw) + "`n"
    }
    $Payload += "--- WORKSPACE MAP ---`n" + (Get-WorkspaceMap) + "`n"
    return $Payload
}

# --- INITIALIZATION ---
if (!(Test-Path "$BaseDir\Memory")) { New-Item -ItemType Directory -Path "$BaseDir\Memory" -Force | Out-Null }

if (Test-Path $MemFile) {
    $ChatHistory = Get-Content $MemFile -Raw | ConvertFrom-Json
    Write-Host "AgentOS Online (Restored)." -ForegroundColor Green
} else {
    $ChatHistory = @()
}

Write-Host "AgentOS Online." -ForegroundColor Green
Write-Host "Provider: $ActiveProviderName | Model: $CurrentModel" -ForegroundColor DarkGray
Write-Host "Commands: /help, /exit, /boot, /map, /load, /providers, /provider, /endpoint, /model, /key, /session, /paste, /selftest" -ForegroundColor DarkGray
$ScriptName = if ($MyInvocation.MyCommand.Name) { $MyInvocation.MyCommand.Name.Replace(".ps1", "") } else { "AgentOS" }
Write-Host "------------------------------------------------------------------"

# Run initial bootstrap as if /boot was called, but only once
$BootPayload = Get-BootPayload
$ChatHistory = @(
    @{ "role" = "user"; "content" = "$BootPayload`nAcknowledge." },
    @{ "role" = "assistant"; "content" = "Context pinned to Index 0." }
)
$StartupBootDone = $true
# After initial bootstrap, set the default loop budget
$MaxAutoLoops = 12
$AutoLoopCount = 0
$AutoTrigger = $false

while ($true) {
    if ($AutoTrigger -and $AutoLoopCount -lt $MaxAutoLoops) {
        Write-Host "`n[SYSTEM] Auto-Chaining Execution (Loop $($AutoLoopCount + 1)/$MaxAutoLoops)..." -ForegroundColor Yellow
        $UserInput = ""
        $AutoLoopCount++
        $AutoTrigger = $false 
    } else {
        if ($AutoLoopCount -ge $MaxAutoLoops) {
            Write-Host "`n[WARNING] Max auto-loops ($MaxAutoLoops) reached. Returning control to user." -ForegroundColor DarkYellow
        }
        $AutoLoopCount = 0
        $AutoTrigger = $false
        $UserInput = Read-Host "`nYou"
    }

    # --- SLASH COMMANDS & DRAG-AND-DROP ---
    if ($UserInput.StartsWith("/")) {
        if ($UserInput.Trim() -eq "/selftest") { Invoke-AgentSelfTest }
        if ($UserInput.Trim() -eq "/exit") {
            Write-Host "[SYSTEM] Terminating AgentOS Session..." -ForegroundColor DarkGray
            break
        }
        elseif ($UserInput.Trim() -eq "/help") {
            Write-Host "`nAVAILABLE COMMANDS:" -ForegroundColor Cyan
            Write-Host "/boot    - Injects core system profiles, source code, and workspace map."
            Write-Host "/map     - Injects a manifest of all files in the workspace."
            Write-Host "/load X  - Manually injects file 'X' into context."
            Write-Host "/providers - Lists configured endpoint/model/key profiles."
            Write-Host "/provider X - Switches active provider profile."
            Write-Host "/endpoint URL - Switches active endpoint and persists it."
            Write-Host "/model   - Interactive provider+model picker."
            Write-Host "/model X - Switches active model and persists it."
            Write-Host "/key - Prompts for API key for the active provider. Blank keys are allowed for local endpoints."
            Write-Host "/session - Wipes current memory (no autoboot). Run /boot to reload context."
            Write-Host "/paste   - Injects multi-line text directly from your clipboard."
            Write-Host "/selftest - Verifies local reconstructed workspace without network."
            Write-Host "/exit    - Closes AgentOS."
            continue
        }
        elseif ($UserInput.Trim() -eq "/session") {
            # Wipe session only; no autobootstrap. User runs /boot if desired.
            if (Test-Path $MemFile) { Remove-Item $MemFile -Force }
            $ChatHistory = @()
            $StatePath = Join-Path $BaseDir "Config\active_state.json"
            if (Test-Path $StatePath) {
                $BlankState = @{ current_project = "Session Reset"; current_goal = "Awaiting input"; timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") } | ConvertTo-Json
                Set-Content -Path $StatePath -Value $BlankState -Force -Encoding UTF8
            }
            Write-Host "[SYSTEM] Session wiped. Memory and Active State purged." -ForegroundColor Yellow
            continue
        }
        elseif ($UserInput.Trim() -eq "/providers") {
            if (Test-Path $ProvidersPath) {
                $ProviderSet = Get-Content $ProvidersPath -Raw | ConvertFrom-Json
                Write-Host "[SYSTEM] Active provider: $ActiveProviderName" -ForegroundColor Green
                $ProviderSet.providers.PSObject.Properties | ForEach-Object { Write-Host (" - {0}: {1} | {2}" -f $_.Name, $_.Value.endpoint, $_.Value.model) -ForegroundColor Cyan }
            } else {
                Write-Host "[SYSTEM] No Config\providers.json found. Active endpoint: $Endpoint | model: $CurrentModel" -ForegroundColor Yellow
            }
            continue
        }
        elseif ($UserInput.Trim().StartsWith("/provider ")) {
            $Name = $UserInput.Substring(10).Trim()
            try {
                Switch-Provider $Name
                $Uri = Normalize-Endpoint $Endpoint
                Write-Host "[SYSTEM] Active provider switched to: $ActiveProviderName | $Endpoint | $CurrentModel" -ForegroundColor Green
            } catch { Write-Host "[ERROR] $($_.Exception.Message)" -ForegroundColor Red }
            continue
        }
        elseif ($UserInput.Trim().StartsWith("/endpoint ")) {
            $Endpoint = Normalize-Endpoint ($UserInput.Substring(10).Trim())
            $Uri = Normalize-Endpoint $Endpoint
            Save-ActiveProviderConfig
            Write-Host "[SYSTEM] Active endpoint switched to: $Endpoint" -ForegroundColor Green
            continue
        }
        elseif ($UserInput.Trim().StartsWith("/model ")) {
            $CurrentModel = $UserInput.Substring(7).Trim()
            Save-ActiveProviderConfig
            Write-Host "[SYSTEM] Active model switched to: $CurrentModel" -ForegroundColor Green
            continue
        }
        elseif ($UserInput.Trim() -eq "/model") {
            Select-Model
            continue
        }
        elseif ($UserInput.Trim() -eq "/key") {
            if (!(Test-Path $KeyDir)) { New-Item -ItemType Directory -Path $KeyDir -Force | Out-Null }
            if ($KeyPath -eq $LegacyKeyPath) { $KeyPath = Join-Path $KeyDir ($ActiveProviderName + ".key.txt") }
            $SecureKey = Read-Host "API key for provider '$ActiveProviderName' (leave blank for no Authorization header)" -AsSecureString
            $Ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureKey)
            try { $NewApiKey = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($Ptr) }
            finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($Ptr) }
            Write-PortableText -Path $KeyPath -Value (($NewApiKey.Trim()) + "`n")
            $ApiKey = $NewApiKey.Trim()
            $Headers = @{ "Content-Type"="application/json" }
            if (-not [string]::IsNullOrWhiteSpace($ApiKey)) { $Headers["Authorization"] = "Bearer $ApiKey" }
            Save-ActiveProviderConfig
            Write-Host "[SYSTEM] API key updated for provider: $ActiveProviderName" -ForegroundColor Green
            continue
        }
        elseif ($UserInput.Trim().StartsWith("/load ")) {
            $LoadPath = $UserInput.Substring(6).Trim()
            if (Test-Path $LoadPath) {
                $LoadContent = Get-Content $LoadPath -Raw
                $ChatHistory += @{ "role"="user"; "content"=("[INJECTED FILE: $LoadPath]`n" + $LoadContent) }
                Write-Host "[SYSTEM] File $LoadPath loaded into context." -ForegroundColor Green
            } else {
                Write-Host "[ERROR] File not found: $LoadPath" -ForegroundColor Red
            }
            continue
        }
        elseif ($UserInput.Trim() -eq "/map") {
            $ChatHistory += @{ "role"="user"; "content"=("[WORKSPACE MAP INJECTION]`n" + (Get-WorkspaceMap)) }
            Write-Host "[SYSTEM] Workspace map loaded into context." -ForegroundColor Green
            continue
        }
        elseif ($UserInput.Trim() -eq "/boot") {
            Write-Host "[SYSTEM] Bootstrapping AgentOS Context (Config, Source, Map)..." -ForegroundColor Yellow
            $BootPayload = Get-BootPayload
            # --- CONTEXT PINNING FIX ---
            $ChatHistory[0] = @{ "role" = "user"; "content" = "$BootPayload`nAcknowledge." }
            $ChatHistory += @{ "role" = "assistant"; "content" = "Context pinned to Index 0." }
            Write-Host "[SYSTEM] Context loaded." -ForegroundColor Green
        }
        elseif ($UserInput.Trim() -eq "/paste") {
            Write-Host "[SYSTEM] Reading from clipboard..." -ForegroundColor Yellow
            $ClipText = Get-Clipboard -Raw -ErrorAction SilentlyContinue
            if ($ClipText) {
                # Sanitize text
                $ClipText = $ClipText -replace '[^\x09\x0A\x0D\x20-\x7E]', ''
                
                # Check length threshold
                if ($ClipText.Length -gt 25000) {
                    Write-Host "[WARNING] Paste payload too large ($($ClipText.Length) chars)." -ForegroundColor DarkYellow
                    $PastePath = Join-Path $BaseDir "Mailbox\Large_Paste.txt"
                    Set-Content -Path $PastePath -Value $ClipText -Encoding UTF8 -Force
                    $ChatHistory += @{ "role"="user"; "content"="[SYSTEM] User attempted a massive paste ($($ClipText.Length) chars). Saved to Mailbox\Large_Paste.txt." }
                } else {
                    $ChatHistory += @{ "role"="user"; "content"=("[PASTED SNIPPET]`n" + $ClipText) }
                    Write-Host "[SYSTEM] Multi-line clipboard data sanitized and injected." -ForegroundColor Green
                }
            } else {
                Write-Host "[ERROR] Clipboard is empty or contains non-text data." -ForegroundColor Red
                continue
            }
        }
        else {
            Write-Host "[ERROR] Unknown slash command. Type /help for options." -ForegroundColor Red
            continue
        }
    } 
    # --- CHECK FOR DRAG AND DROP (File Path Detection) ---
    elseif ($UserInput.Trim() -match '^\s*"(.:\\[^"]+)"\s*$' -or $UserInput.Trim() -match '^\s*(.:\\[^\s]+\.\w+)\s*$') {
        $DroppedPath = $matches[1].Replace('"', '').Trim()
        Write-Host "[SYSTEM] Drag-and-Drop detected. Parsing: $DroppedPath" -ForegroundColor Yellow
        
        $ParserPath = Join-Path $BaseDir "Skills\PowerShell\Parse-DroppedFile.ps1"
        if (Test-Path $ParserPath) {
            try {
                $ResultJson = & $ParserPath -FilePath $DroppedPath
                $ResultObj = $ResultJson | ConvertFrom-Json
                
                if ($null -ne $ResultObj.error) {
                    Write-Host "[ERROR] Parser Skill Failed: $($ResultObj.error)" -ForegroundColor Red
                    continue
                } elseif ($null -ne $ResultObj.text_payload) {
                    $ChatHistory += @{ "role"="user"; "content"=$ResultObj.text_payload }
                } else {
                    $ChatHistory += @{ "role"="user"; "content"=$ResultObj }
                }
                Write-Host "[SYSTEM] File successfully injected via Parse-DroppedFile skill. Sending to AgentOS..." -ForegroundColor Green
            } catch {
                Write-Host "[ERROR] Execution of Parser Skill failed: $($_.Exception.Message)" -ForegroundColor Red
                continue
            }
        } else {
            Write-Host "[ERROR] Parse-DroppedFile.ps1 skill missing." -ForegroundColor Red
            continue
        }
    }
    elseif ([string]::IsNullOrWhiteSpace($UserInput)) {
        # Allow blank enter for sequential actions
    } else {
        $ChatHistory += @{ "role" = "user"; "content" = $UserInput }
    }

    # --- API CALL WITH RETRY AND LOADING ANIMATION (SAFE FOR PS 5.1 & CLM) ---
    $FinalMessages = $ChatHistory
    if ($ChatHistory.Count -gt 60) { $FinalMessages = @($ChatHistory[0..1]) + @($ChatHistory[-58..-1]) }

    $RetryCount = 0
    $Success = $false
    $Response = $null
    $Reply = $null

    while (-not $Success -and $RetryCount -lt 3) {
        try {
            $Body = @{ "model"=$CurrentModel; "messages"=$FinalMessages } | ConvertTo-Json -Depth 10
            
            # Use standard background Job which is native to PS 5.1 and CLM compliant
            $Job = $null
            try {
                $Job = Start-Job -ScriptBlock {
                    param($Uri, $Headers, $Body)
                    Invoke-RestMethod -Uri $Uri -Method POST -Headers $Headers -Body $Body -ContentType "application/json; charset=utf-8"
                } -ArgumentList $Uri, $Headers, $Body -ErrorAction Stop
                
                $Frames = @(
                    "<-= [ .     ] =-->",
                    "<-= [ .o    ] =-->",
                    "<-= [ .o*   ] =-->",
                    "<-= [  o*O  ] =-->",
                    "<-= [   *O. ] =-->",
                    "<-= [    O..] =-->",
                    "<-= [     . ] =-->",
                    "<-= [      .] =-->",
                    "<-= [     . ] =-->",
                    "<-= [    O..] =-->",
                    "<-= [   *O. ] =-->",
                    "<-= [  o*O  ] =-->",
                    "<-= [ .o*   ] =-->",
                    "<-= [ .o    ] =-->"
                )
                $Spinner = @("|", "/", "-", "\")
                $i = 0
                
                # Animate while the background process executes the API call
                while ($Job.State -eq "Running") {
                    $frame = $Frames[$i % $Frames.Count]
                    $spin = $Spinner[$i % $Spinner.Count]
                    Write-Host "`r[SYSTEM] Querying model $spin $frame" -NoNewline -ForegroundColor Yellow
                    Start-Sleep -Milliseconds 100
                    $i++
                }
                
                # Clear loading line completely
                Write-Host "`r                                                       `r" -NoNewline
                
                $Response = Receive-Job -Job $Job
                Remove-Job -Job $Job -Force
                
                if ($null -ne $Response) {
                    # Handle response from Job
                    if ($null -ne $Response.choices -and $Response.choices.Count -gt 0) {
                        $Reply = $Response.choices[0].message.content
                        if ($null -ne $Reply) {
                            $Success = $true
                        }
                    }
                }
            } catch {
                # Safeguard Fallback: If Start-Job fails or is blocked, instantly run synchronously
                if ($Job) { Remove-Job -Job $Job -Force -ErrorAction SilentlyContinue }
                Write-Host "`r[SYSTEM] Loading animation bypassed. Querying model synchronously..." -ForegroundColor Yellow
                $Response = Invoke-RestMethod -Uri $Uri -Method POST -Headers $Headers -Body $Body -ContentType "application/json; charset=utf-8"
                if ($null -ne $Response -and $null -ne $Response.choices -and $Response.choices.Count -gt 0) {
                    $Reply = $Response.choices[0].message.content
                    if ($null -ne $Reply) {
                        $Success = $true
                    }
                }
            }

            if (-not $Success) {
                throw "Empty or malformed API response received."
            }
        } catch {
            $RetryCount++
            $LastErrorMsg = $_.Exception.Message
            Write-Host "`n[WARNING] API Call failed (Attempt $RetryCount/3): $LastErrorMsg" -ForegroundColor Yellow
            if ($RetryCount -lt 3) {
                Write-Host "[SYSTEM] Retrying in 3 seconds..." -ForegroundColor DarkYellow
                Start-Sleep -Seconds 3
            }
        }
    }

    if (-not $Success) {
        Write-Host "`n[WARNING] API unavailable after 3 attempts. Last error: $LastErrorMsg" -ForegroundColor Yellow
        continue
    }

    try {
        Write-Host "`n${ScriptName}:" -ForegroundColor Cyan
        $DisplayLines = $Reply -split "`r?`n"
        
        foreach ($line in $DisplayLines) {
            if ($line -match '\[ACTION_REQUIRED\]') {
                Write-Host "$([char]27)[38;5;208m$line$([char]27)[0m"
            } else {
                Write-Host $line -ForegroundColor Cyan
            }
        }
        $ChatHistory += @{ "role" = "assistant"; "content" = $Reply }

        $BatchResponse = ""

        # ====================================================================
        # 1. PROCESS ALL FILE SAVES & HARD VERIFICATION
        # ====================================================================
        $saveRegex = '(?s)\[\s*SAVE_FILE\s*:\s*([^\]\x60]+)\]\s*(.*?)\s*(?:\[\s*/SAVE_FILE\s*\]|\x60{3}|$)'
        $saveMatches = [regex]::Matches($Reply, $saveRegex)

        foreach ($match in $saveMatches) {
            $FilePathShort = $match.Groups[1].Value.Trim().Replace("/", "\")
            $FileContent = $match.Groups[2].Value.Trim()
            $FileContent = $FileContent -replace '^\x60{3}[a-zA-Z]*\s*', '' -replace '\x60{3}$', ''

            $FullSavePath = Join-Path $BaseDir $FilePathShort
            Write-Host "`n[SYSTEM LOG] SAVE_FILE matched. Writing: $FilePathShort" -ForegroundColor DarkCyan

            try {
                $TargetDir = Split-Path $FullSavePath
                if (!(Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null }
                Set-Content -Path $FullSavePath -Value $FileContent -Force -Encoding UTF8
                
                # HARD VERIFICATION LOGIC
                $VerificationLines = Get-Content -Path $FullSavePath
                $LineCount = $VerificationLines.Count
                
                $Head = if ($LineCount -gt 5) { ($VerificationLines[0..4] -join "`n") } else { ($VerificationLines -join "`n") }
                $Tail = if ($LineCount -gt 5) { ($VerificationLines[($LineCount-5)..($LineCount-1)] -join "`n") } else { "" }
                
                $VerificationPayload = "--- HARD VERIFICATION PREVIEW (HEAD & TAIL) ---`n$Head"
                if ($LineCount -gt 5) { $VerificationPayload += "`n...[TRUNCATED $LineCount LINES]...`n$Tail" }
                $VerificationPayload += "`n--- END VERIFICATION ---"

                $FileInfo = Get-Item $FullSavePath
                $FileHash = (Get-FileHash $FullSavePath).Hash
                
                Write-Host "[SYSTEM] File Saved & Verified ($($FileInfo.Length) bytes)." -ForegroundColor Green
                $BatchResponse += "[SYSTEM: File '$FilePathShort' saved successfully. Size: $($FileInfo.Length) bytes, SHA256: $FileHash]`n$VerificationPayload`n`n"
                $AutoTrigger = $true
            } catch {
                Write-Host "[ERROR] Write Failed: $($_.Exception.Message)" -ForegroundColor Red
                $BatchResponse += "[SYSTEM: Failed to save '$FilePathShort': $($_.Exception.Message)]`n`n"
                $AutoTrigger = $true
            }
        }

        # ====================================================================
        # 2. PROCESS FILE DELETIONS (AUTONOMOUS CLEANUP)
        # ====================================================================
        $delRegex = '\[\s*DELETE_FILE\s*:\s*([^\]\x60]+)\]'
        $delMatches = [regex]::Matches($Reply, $delRegex)

        foreach ($match in $delMatches) {
            $FilePathShort = $match.Groups[1].Value.Trim().Replace("/", "\")
            $FullDelPath = Join-Path $BaseDir $FilePathShort
            
            if (Test-Path $FullDelPath) {
                try {
                    Remove-Item $FullDelPath -Force
                    Write-Host "`n[SYSTEM LOG] Deleted: $FilePathShort" -ForegroundColor Yellow
                    $BatchResponse += "[SYSTEM: Successfully deleted '$FilePathShort']`n`n"
                    $AutoTrigger = $true
                } catch {
                    $BatchResponse += "[SYSTEM: Failed to delete '$FilePathShort': $($_.Exception.Message)]`n`n"
                    $AutoTrigger = $true
                }
            }
        }

        # ====================================================================
        # 3. PROCESS ALL FILE READS
        # ====================================================================
        $readRegex = '\[\s*READ_FILE\s*:\s*([^\]\x60]+)\]'
        $readMatches = [regex]::Matches($Reply, $readRegex)

        foreach ($match in $readMatches) {
            $FilePathShort = $match.Groups[1].Value.Trim().Replace("/", "\")
            $FullReadPath = Join-Path $BaseDir $FilePathShort
            Write-Host "`n[SYSTEM LOG] READ_FILE matched. Fetching: $FilePathShort" -ForegroundColor DarkCyan

            if (Test-Path $FullReadPath) {
                try {
                    $FileContent = Get-Content $FullReadPath -Encoding UTF8 -Raw
                    $BatchResponse += "[DATA: $FilePathShort]`n$FileContent`n`n"
                    Write-Host "[SYSTEM] File read successfully." -ForegroundColor Magenta
                    $AutoTrigger = $true
                } catch {
                    Write-Host "[ERROR] Read Failed: $($_.Exception.Message)" -ForegroundColor Red
                    $BatchResponse += "[SYSTEM: Failed to read '$FilePathShort': $($_.Exception.Message)]`n`n"
                    $AutoTrigger = $true
                }
            } else {
                $BatchResponse += "[SYSTEM: File '$FilePathShort' not found.]`n`n"
                $AutoTrigger = $true
            }
        }

        # ====================================================================
        # 4. PROCESS ALL SKILL RUNS
        # ====================================================================
        $runRegex = '\[\s*RUN_SKILL\s*:\s*([^\]\x60]+)\]'
        $runMatches = [regex]::Matches($Reply, $runRegex)

        foreach ($match in $runMatches) {
            $SkillPathShort = $match.Groups[1].Value.Trim().Replace("/", "\")
            $FullSkillPath = Join-Path $BaseDir $SkillPathShort
            Write-Host "`n[SYSTEM LOG] Executing: $SkillPathShort" -ForegroundColor DarkCyan

            if (Test-Path $FullSkillPath) {
                try {
                    $out = & $FullSkillPath 2>&1 | Out-String
                    $BatchResponse += "[SYSTEM: Skill Result for '$SkillPathShort':`n$out]`n`n"
                    Write-Host "[SYSTEM] Skill Executed." -ForegroundColor Magenta
                    $AutoTrigger = $true
                } catch {
                    $BatchResponse += "[SYSTEM: Skill execution failed for '$SkillPathShort': $($_.Exception.Message)]`n`n"
                    $AutoTrigger = $true
                }
            } else {
                if ($SkillPathShort -notmatch "your_script") {
                    $BatchResponse += "[SYSTEM: Skill file '$SkillPathShort' not found.]`n`n"
                    $AutoTrigger = $true
                }
            }
        }

        # ====================================================================
        # 5. SYNTAX FALLBACK & AUTO-CORRECTION
        # ====================================================================
        $SyntaxWarning = ""
        if ($Reply -match 'SAVE_FILE' -and $saveMatches.Count -eq 0) { $SyntaxWarning += "[SYSTEM SYNTAX ERROR: S A V E _ F I L E detected but failed to parse. Check brackets and ensure no markdown wrappers are used.]`n`n" }
        if ($Reply -match 'READ_FILE' -and $readMatches.Count -eq 0) { $SyntaxWarning += "[SYSTEM SYNTAX ERROR: R E A D _ F I L E detected but failed to parse. Check brackets.]`n`n" }
        if ($Reply -match 'RUN_SKILL' -and $runMatches.Count -eq 0) { $SyntaxWarning += "[SYSTEM SYNTAX ERROR: R U N _ S K I L L detected but failed to parse. Check brackets.]`n`n" }
        if ($Reply -match 'DELETE_FILE' -and $delMatches.Count -eq 0) { $SyntaxWarning += "[SYSTEM SYNTAX ERROR: D E L E T E _ F I L E detected but failed to parse. Check brackets.]`n`n" }

        if ($SyntaxWarning) {
            if ($Reply -notmatch "Modified print loop block inside AgentOS") {
                Write-Host "`n[SYSTEM WARNING] Near-miss syntax detected. Auto-triggering correction chain." -ForegroundColor DarkYellow
                $BatchResponse += $SyntaxWarning
                $AutoTrigger = $true
            }
        }

        # ====================================================================
        # 6. DYNAMIC LOOP CONTROL & BUDGETING
        # ====================================================================
        if ($Reply -match '\[\s*SET_BUDGET\s*:\s*(\d+)\s*\]') {
            $MaxAutoLoops = [int]$matches[1]
            $BatchResponse += "[SYSTEM: Auto-loop budget dynamically set to $MaxAutoLoops]`n`n"
            Write-Host "`n[SYSTEM] Auto-execution budget updated to $MaxAutoLoops." -ForegroundColor DarkCyan
        }
        if ($Reply -match '\[\s*PAUSE_LOOP\s*\]') {
            $AutoTrigger = $false
            Write-Host "`n[SYSTEM] PAUSE_LOOP executed. Control explicitly returned to user." -ForegroundColor DarkYellow
        }

        # Append batched payload as a single user message
        if ($AutoTrigger -and !([string]::IsNullOrWhiteSpace($BatchResponse))) {
            $ChatHistory += @{ "role" = "user"; "content" = $BatchResponse.TrimEnd() }
        }

        # Save memory
        $JsonStr = $ChatHistory | ConvertTo-Json -Depth 10; $JsonStr = [System.Text.RegularExpressions.Regex]::Replace($JsonStr, "[^\x09\x0A\x0D\x20-\x7E]", ""); $JsonStr | Set-Content -Path $MemFile -Encoding UTF8
    } catch {
        Write-Host "`nAPI Error: $($_.Exception.Message)" -ForegroundColor Red
        if(-not $UserInput.StartsWith("/")){ $ChatHistory = $ChatHistory[0..($ChatHistory.Count - 2)] }
    }
}