child/Start-DpChildProvider.ps1

<#
.SYNOPSIS
    Runs the trusted, independently owned child provider transport.
.DESCRIPTION
    Only this process resolves Engine credentials. It registers no Tools and
    receives commands only from its authenticated Host Server channel. The
    Engine performs counting, admission, HTTP, normalization, and pricing.
.PARAMETER EngineModulePath
    The Host Server verified Engine manifest in the prepared runtime.
.PARAMETER RuntimeAssembly
    The verified assembly containing the bounded authenticated bridge.
.PARAMETER LeaseSeconds
    The independent Host Server lease, never renewed by provider data.
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory)][string]$EngineModulePath,
    [string]$RuntimeAssembly = (Join-Path $PSScriptRoot 'ChildRuntime.dll'),
    [ValidateRange(1,30)][int]$LeaseSeconds = 15
)

$ErrorActionPreference = 'Stop'
$WarningPreference = 'SilentlyContinue'
$ProgressPreference = 'SilentlyContinue'
$bridge = $null
$context = $null
$engine = $null
try {
    Add-Type -Path $RuntimeAssembly -ErrorAction Stop
    $bridge = [DeskPilot.Child.EngineBridge]::Start($LeaseSeconds, 4194304)
    $configuration = $bridge.Configuration | ConvertFrom-Json -AsHashtable -Depth 24
    if ($configuration.profile -cne 'single-child-v3' -or $configuration.budgetMode -cne 'provider-estimate' -or
        $configuration.model -cne 'claude-haiku-4.5') { throw 'Unsupported child provider profile.' }
    Import-Module -Name $EngineModulePath -Force -ErrorAction Stop
    $engine = Get-Module ShellPilot
    . (Join-Path $PSScriptRoot 'ChildTools.ps1')
    $definitions = @(Get-DpChildToolDefinition -File ([bool]$configuration.permissions.file) -Terminal ([bool]$configuration.permissions.terminal) -Writable ($configuration.projectAccess -ceq 'read-write'))
    $parameters = @{
        Model = $configuration.model
        Tools = @($definitions | ForEach-Object { $_.Schema })
        Limits = @{
            MaxInputTokens = $configuration.inputTokens
            MaxTotalTokens = $configuration.totalTokens
            MaxCostUSD = $configuration.costUSD
        }
        MaxRequests = $configuration.iterations
        MaxRequestBytes = $configuration.requestBytes
        MaxResponseBytes = $configuration.outputBytes
        MaxCountBytes = $configuration.eventBytes
        MaxOutputTokens = $configuration.outputTokens
        DurationSeconds = $configuration.durationSeconds
        BeforeGeneration = {
            param($Prepared, $Usage)
            $reserved = @{
                stage = 'reserved'
                requestId = $Prepared.RequestId
                requestDigest = $Prepared.RequestDigest
                usage = $Usage
            } | ConvertTo-Json -Depth 12 -Compress
            $decision = $bridge.Invoke('provider', $reserved) | ConvertFrom-Json -AsHashtable -Depth 8
            $decision.Count -eq 1 -and $decision.admitted -is [bool] -and $decision.admitted
        }
    }
    if ($configuration.tokenPath) { $parameters.TokenPath = [string]$configuration.tokenPath }
    $context = & $engine { param($Parameters) New-ShpChildProviderContext @Parameters } $parameters
    $payload = @{
        stage = 'ready'
        usage = & $engine { param($Context) Get-ShpChildProviderUsage -Context $Context } $context
    }
    while (-not $context.Closed) {
        $command = $bridge.Invoke('provider', ($payload | ConvertTo-Json -Depth 24 -Compress)) |
            ConvertFrom-Json -AsHashtable -Depth 24
        if ($command.Count -ne 2 -or $command.action -cne 'invoke' -or $command.request -isnot [hashtable]) {
            throw 'Unsupported Host Server provider command.'
        }
        $response = & $engine {
            param($Context, $Request)
            Invoke-ShpChildProviderRequest -Context $Context -Request $Request
        } $context $command.request
        $payload = @{
            stage = 'response'
            requestId = $command.request.RequestId
            response = $response
            usage = & $engine { param($Context) Get-ShpChildProviderUsage -Context $Context } $context
        }
    }
} catch {
    $failure = $_
    $code = switch (($failure.FullyQualifiedErrorId -split ',')[0]) {
        'ShpRequestBudgetOverrun' { 'budget-overrun' }
        'ShpRequestUsageUnknown' { 'usage-unknown' }
        'ShpChildAdmissionRevoked' { 'admission-revoked' }
        'ShpRequestPricingUnavailable' { 'pricing-unavailable' }
        'ShpCountShapeUnsupported' { 'unsupported-request' }
        default { 'provider-failed' }
    }
    if ($bridge) {
        $usage = if ($context) { & $engine { param($Context) Get-ShpChildProviderUsage -Context $Context } $context } else { $null }
        $bridge.Complete((@{ status = 'failed'; code = $code; usage = $usage } | ConvertTo-Json -Depth 12 -Compress))
    }
} finally {
    if ($context) {
        $context.Closed = $true
        $context.Cancellation.Cancel()
        $context.Headers.Clear()
        $context.Client.Dispose()
        $context.Cancellation.Dispose()
    }
    if ($bridge) { $bridge.Dispose() }
}