@noopolis/daimon 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +307 -45
- package/dist/contracts/attentionContract.d.ts +117 -0
- package/dist/contracts/attentionContract.d.ts.map +1 -0
- package/dist/contracts/attentionContract.js +14 -0
- package/dist/contracts/canonicalJson.d.ts +3 -0
- package/dist/contracts/canonicalJson.d.ts.map +1 -0
- package/dist/contracts/canonicalJson.js +54 -0
- package/dist/contracts/grokWorkerContract.d.ts +74 -0
- package/dist/contracts/grokWorkerContract.d.ts.map +1 -0
- package/dist/contracts/grokWorkerContract.js +88 -0
- package/dist/contracts/organizationRuntimeContract.d.ts +765 -0
- package/dist/contracts/organizationRuntimeContract.d.ts.map +1 -0
- package/dist/contracts/organizationRuntimeContract.js +121 -0
- package/dist/contracts/runtimeContractManifest.d.ts +1615 -0
- package/dist/contracts/runtimeContractManifest.d.ts.map +1 -0
- package/dist/contracts/runtimeContractManifest.js +181 -0
- package/dist/core/credentialRedaction.d.ts +4 -0
- package/dist/core/credentialRedaction.d.ts.map +1 -0
- package/dist/core/credentialRedaction.js +28 -0
- package/dist/core/siblingBuildFreshness.d.ts +21 -0
- package/dist/core/siblingBuildFreshness.d.ts.map +1 -0
- package/dist/core/siblingBuildFreshness.js +25 -0
- package/dist/core/types.d.ts +10 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/examples/exampleCausalId.d.ts +3 -0
- package/dist/examples/exampleCausalId.d.ts.map +1 -0
- package/dist/examples/exampleCausalId.js +8 -0
- package/dist/examples/jungian-play-org.js +3 -2
- package/dist/examples/jungian-triad-org.js +3 -2
- package/dist/examples/jungianPlayAgent.d.ts +1 -1
- package/dist/examples/jungianPlayAgent.d.ts.map +1 -1
- package/dist/examples/jungianPlayAgent.js +1 -1
- package/dist/examples/jungianProfiles.d.ts +1 -1
- package/dist/examples/jungianProfiles.d.ts.map +1 -1
- package/dist/examples/jungianTriadProfiles.d.ts +1 -1
- package/dist/examples/jungianTriadProfiles.d.ts.map +1 -1
- package/dist/examples/pi-agent.js +3 -2
- package/dist/examples/pi-memory-org.js +6 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/mcp/toolServer.d.ts +31 -0
- package/dist/mcp/toolServer.d.ts.map +1 -0
- package/dist/mcp/toolServer.js +145 -0
- package/dist/observability/causalEvents.d.ts +118 -0
- package/dist/observability/causalEvents.d.ts.map +1 -0
- package/dist/observability/causalEvents.js +223 -0
- package/dist/observability/controlCausal.d.ts +117 -0
- package/dist/observability/controlCausal.d.ts.map +1 -0
- package/dist/observability/controlCausal.js +107 -0
- package/dist/observability/emitCausalFixture.d.ts +25 -0
- package/dist/observability/emitCausalFixture.d.ts.map +1 -0
- package/dist/observability/emitCausalFixture.js +98 -0
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +2 -0
- package/dist/observability/orgObserver.d.ts.map +1 -1
- package/dist/observability/orgObserver.js +3 -3
- package/dist/pi/agyHeadlessResult.d.ts +60 -0
- package/dist/pi/agyHeadlessResult.d.ts.map +1 -0
- package/dist/pi/agyHeadlessResult.js +95 -0
- package/dist/pi/cliChildOutput.d.ts +67 -0
- package/dist/pi/cliChildOutput.d.ts.map +1 -0
- package/dist/pi/cliChildOutput.js +269 -0
- package/dist/pi/cliEngineRun.d.ts +16 -0
- package/dist/pi/cliEngineRun.d.ts.map +1 -0
- package/dist/pi/cliEngineRun.js +27 -0
- package/dist/pi/cliEngineSpawn.d.ts +55 -0
- package/dist/pi/cliEngineSpawn.d.ts.map +1 -0
- package/dist/pi/cliEngineSpawn.js +164 -0
- package/dist/pi/cliEnvironment.d.ts +12 -0
- package/dist/pi/cliEnvironment.d.ts.map +1 -0
- package/dist/pi/cliEnvironment.js +32 -0
- package/dist/pi/cliMcpRegistration.d.ts +61 -0
- package/dist/pi/cliMcpRegistration.d.ts.map +1 -0
- package/dist/pi/cliMcpRegistration.js +75 -0
- package/dist/pi/cliProcess.d.ts +7 -0
- package/dist/pi/cliProcess.d.ts.map +1 -0
- package/dist/pi/cliProcess.js +132 -0
- package/dist/pi/cliSession.d.ts +106 -0
- package/dist/pi/cliSession.d.ts.map +1 -0
- package/dist/pi/cliSession.js +379 -0
- package/dist/pi/cliTurnMetering.d.ts +60 -0
- package/dist/pi/cliTurnMetering.d.ts.map +1 -0
- package/dist/pi/cliTurnMetering.js +60 -0
- package/dist/pi/codexFilesystemRules.d.ts +3 -0
- package/dist/pi/codexFilesystemRules.d.ts.map +1 -0
- package/dist/pi/codexFilesystemRules.js +28 -0
- package/dist/pi/codexHeadlessResult.d.ts +68 -0
- package/dist/pi/codexHeadlessResult.d.ts.map +1 -0
- package/dist/pi/codexHeadlessResult.js +122 -0
- package/dist/pi/codexRolloutUsage.d.ts +95 -0
- package/dist/pi/codexRolloutUsage.d.ts.map +1 -0
- package/dist/pi/codexRolloutUsage.js +221 -0
- package/dist/pi/engineWakeLimits.d.ts +39 -0
- package/dist/pi/engineWakeLimits.d.ts.map +1 -0
- package/dist/pi/engineWakeLimits.js +55 -0
- package/dist/pi/grokHeadlessResult.d.ts +36 -0
- package/dist/pi/grokHeadlessResult.d.ts.map +1 -0
- package/dist/pi/grokHeadlessResult.js +118 -0
- package/dist/pi/grokHomeMcpRegistration.d.ts +21 -0
- package/dist/pi/grokHomeMcpRegistration.d.ts.map +1 -0
- package/dist/pi/grokHomeMcpRegistration.js +57 -0
- package/dist/pi/grokSandbox.d.ts +11 -0
- package/dist/pi/grokSandbox.d.ts.map +1 -0
- package/dist/pi/grokSandbox.js +216 -0
- package/dist/pi/grokStreamUsage.d.ts +31 -0
- package/dist/pi/grokStreamUsage.d.ts.map +1 -0
- package/dist/pi/grokStreamUsage.js +51 -0
- package/dist/pi/index.d.ts +5 -0
- package/dist/pi/index.d.ts.map +1 -1
- package/dist/pi/index.js +5 -0
- package/dist/pi/memoryTools.d.ts +55 -1
- package/dist/pi/memoryTools.d.ts.map +1 -1
- package/dist/pi/memoryTools.js +144 -24
- package/dist/pi/modelRegistry.d.ts +13 -0
- package/dist/pi/modelRegistry.d.ts.map +1 -0
- package/dist/pi/modelRegistry.js +19 -0
- package/dist/pi/piAgentHandle.d.ts +46 -0
- package/dist/pi/piAgentHandle.d.ts.map +1 -0
- package/dist/pi/piAgentHandle.js +351 -0
- package/dist/pi/piAgentWakeSupport.d.ts +103 -0
- package/dist/pi/piAgentWakeSupport.d.ts.map +1 -0
- package/dist/pi/piAgentWakeSupport.js +151 -0
- package/dist/pi/piHarness.d.ts +40 -5
- package/dist/pi/piHarness.d.ts.map +1 -1
- package/dist/pi/piHarness.js +151 -256
- package/dist/pi/prompts.d.ts +10 -0
- package/dist/pi/prompts.d.ts.map +1 -0
- package/dist/pi/prompts.js +63 -0
- package/dist/pi/rawTrainingCapture.d.ts +59 -0
- package/dist/pi/rawTrainingCapture.d.ts.map +1 -0
- package/dist/pi/rawTrainingCapture.js +175 -0
- package/dist/pi/turnCausal.d.ts +73 -0
- package/dist/pi/turnCausal.d.ts.map +1 -0
- package/dist/pi/turnCausal.js +75 -0
- package/dist/pi/turnTrace.d.ts +128 -0
- package/dist/pi/turnTrace.d.ts.map +1 -0
- package/dist/pi/turnTrace.js +138 -0
- package/dist/pi/wakeAcceptance.d.ts +49 -0
- package/dist/pi/wakeAcceptance.d.ts.map +1 -0
- package/dist/pi/wakeAcceptance.js +281 -0
- package/dist/pi/wakeAcceptanceFs.d.ts +44 -0
- package/dist/pi/wakeAcceptanceFs.d.ts.map +1 -0
- package/dist/pi/wakeAcceptanceFs.js +318 -0
- package/dist/pi/wakeAcceptanceSchema.d.ts +75 -0
- package/dist/pi/wakeAcceptanceSchema.d.ts.map +1 -0
- package/dist/pi/wakeAcceptanceSchema.js +265 -0
- package/dist/pi/wakeModes.d.ts +9 -0
- package/dist/pi/wakeModes.d.ts.map +1 -0
- package/dist/pi/wakeModes.js +19 -0
- package/dist/pi/worldNudge.d.ts +22 -0
- package/dist/pi/worldNudge.d.ts.map +1 -0
- package/dist/pi/worldNudge.js +62 -0
- package/dist/pi/worldToolProtocol.d.ts +13 -0
- package/dist/pi/worldToolProtocol.d.ts.map +1 -0
- package/dist/pi/worldToolProtocol.js +49 -0
- package/dist/pi/worldTools.d.ts +32 -0
- package/dist/pi/worldTools.d.ts.map +1 -0
- package/dist/pi/worldTools.js +373 -0
- package/dist/pi/worldTrajectory.d.ts +52 -0
- package/dist/pi/worldTrajectory.d.ts.map +1 -0
- package/dist/pi/worldTrajectory.js +131 -0
- package/dist/runtime/agySubscriptionBootstrap.d.ts +16 -0
- package/dist/runtime/agySubscriptionBootstrap.d.ts.map +1 -0
- package/dist/runtime/agySubscriptionBootstrap.js +80 -0
- package/dist/runtime/agySubscriptionRealm.d.ts +38 -0
- package/dist/runtime/agySubscriptionRealm.d.ts.map +1 -0
- package/dist/runtime/agySubscriptionRealm.js +242 -0
- package/dist/runtime/attention.d.ts +21 -0
- package/dist/runtime/attention.d.ts.map +1 -0
- package/dist/runtime/attention.js +36 -0
- package/dist/runtime/attentionDispatcher.d.ts +66 -0
- package/dist/runtime/attentionDispatcher.d.ts.map +1 -0
- package/dist/runtime/attentionDispatcher.js +271 -0
- package/dist/runtime/cli.d.ts +7 -0
- package/dist/runtime/cli.d.ts.map +1 -0
- package/dist/runtime/cli.js +251 -0
- package/dist/runtime/codexSandboxProjection.d.ts +17 -0
- package/dist/runtime/codexSandboxProjection.d.ts.map +1 -0
- package/dist/runtime/codexSandboxProjection.js +40 -0
- package/dist/runtime/contract-manifest.json +1 -0
- package/dist/runtime/contract-manifest.sha256 +1 -0
- package/dist/runtime/contractManifest.d.ts +8 -0
- package/dist/runtime/contractManifest.d.ts.map +1 -0
- package/dist/runtime/contractManifest.js +4 -0
- package/dist/runtime/engineBrokerCapabilities.d.ts +30 -0
- package/dist/runtime/engineBrokerCapabilities.d.ts.map +1 -0
- package/dist/runtime/engineBrokerCapabilities.js +59 -0
- package/dist/runtime/engineBrokerControlClient.d.ts +44 -0
- package/dist/runtime/engineBrokerControlClient.d.ts.map +1 -0
- package/dist/runtime/engineBrokerControlClient.js +132 -0
- package/dist/runtime/engineBrokerCredentialJournal.d.ts +10 -0
- package/dist/runtime/engineBrokerCredentialJournal.d.ts.map +1 -0
- package/dist/runtime/engineBrokerCredentialJournal.js +17 -0
- package/dist/runtime/engineBrokerInferenceProtocol.d.ts +52 -0
- package/dist/runtime/engineBrokerInferenceProtocol.d.ts.map +1 -0
- package/dist/runtime/engineBrokerInferenceProtocol.js +65 -0
- package/dist/runtime/engineBrokerMcpCallLog.d.ts +160 -0
- package/dist/runtime/engineBrokerMcpCallLog.d.ts.map +1 -0
- package/dist/runtime/engineBrokerMcpCallLog.js +219 -0
- package/dist/runtime/engineBrokerMcpFacade.d.ts +56 -0
- package/dist/runtime/engineBrokerMcpFacade.d.ts.map +1 -0
- package/dist/runtime/engineBrokerMcpFacade.js +343 -0
- package/dist/runtime/engineBrokerNativeClient.d.ts +52 -0
- package/dist/runtime/engineBrokerNativeClient.d.ts.map +1 -0
- package/dist/runtime/engineBrokerNativeClient.js +151 -0
- package/dist/runtime/engineBrokerProtocol.d.ts +135 -0
- package/dist/runtime/engineBrokerProtocol.d.ts.map +1 -0
- package/dist/runtime/engineBrokerProtocol.js +274 -0
- package/dist/runtime/engineBrokerSealLedger.d.ts +70 -0
- package/dist/runtime/engineBrokerSealLedger.d.ts.map +1 -0
- package/dist/runtime/engineBrokerSealLedger.js +123 -0
- package/dist/runtime/engineBrokerService.d.ts +37 -0
- package/dist/runtime/engineBrokerService.d.ts.map +1 -0
- package/dist/runtime/engineBrokerService.js +138 -0
- package/dist/runtime/engineBrokerServiceCli.d.ts +5 -0
- package/dist/runtime/engineBrokerServiceCli.d.ts.map +1 -0
- package/dist/runtime/engineBrokerServiceCli.js +32 -0
- package/dist/runtime/engineBrokerServiceConfig.d.ts +50 -0
- package/dist/runtime/engineBrokerServiceConfig.d.ts.map +1 -0
- package/dist/runtime/engineBrokerServiceConfig.js +92 -0
- package/dist/runtime/engineBrokerSingleflight.d.ts +13 -0
- package/dist/runtime/engineBrokerSingleflight.d.ts.map +1 -0
- package/dist/runtime/engineBrokerSingleflight.js +24 -0
- package/dist/runtime/engineBrokerTurnAccounting.d.ts +76 -0
- package/dist/runtime/engineBrokerTurnAccounting.d.ts.map +1 -0
- package/dist/runtime/engineBrokerTurnAccounting.js +108 -0
- package/dist/runtime/engineBrokerTurnRegistry.d.ts +57 -0
- package/dist/runtime/engineBrokerTurnRegistry.d.ts.map +1 -0
- package/dist/runtime/engineBrokerTurnRegistry.js +158 -0
- package/dist/runtime/engineDispatcher.d.ts +36 -0
- package/dist/runtime/engineDispatcher.d.ts.map +1 -0
- package/dist/runtime/engineDispatcher.js +216 -0
- package/dist/runtime/engineReadiness.d.ts +23 -0
- package/dist/runtime/engineReadiness.d.ts.map +1 -0
- package/dist/runtime/engineReadiness.js +222 -0
- package/dist/runtime/grokAuthenticationError.d.ts +8 -0
- package/dist/runtime/grokAuthenticationError.d.ts.map +1 -0
- package/dist/runtime/grokAuthenticationError.js +20 -0
- package/dist/runtime/grokBrokerCredentialAuthority.d.ts +22 -0
- package/dist/runtime/grokBrokerCredentialAuthority.d.ts.map +1 -0
- package/dist/runtime/grokBrokerCredentialAuthority.js +124 -0
- package/dist/runtime/grokBrokerCredentialReader.d.ts +5 -0
- package/dist/runtime/grokBrokerCredentialReader.d.ts.map +1 -0
- package/dist/runtime/grokBrokerCredentialReader.js +37 -0
- package/dist/runtime/grokBrokerModelPolicy.d.ts +23 -0
- package/dist/runtime/grokBrokerModelPolicy.d.ts.map +1 -0
- package/dist/runtime/grokBrokerModelPolicy.js +28 -0
- package/dist/runtime/grokBrokerProjection.d.ts +106 -0
- package/dist/runtime/grokBrokerProjection.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProjection.js +94 -0
- package/dist/runtime/grokBrokerProxy.d.ts +55 -0
- package/dist/runtime/grokBrokerProxy.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProxy.js +262 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts +30 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProxyRequest.js +74 -0
- package/dist/runtime/grokBrokerRealmLease.d.ts +4 -0
- package/dist/runtime/grokBrokerRealmLease.d.ts.map +1 -0
- package/dist/runtime/grokBrokerRealmLease.js +33 -0
- package/dist/runtime/grokBrokerRefresh.d.ts +2 -0
- package/dist/runtime/grokBrokerRefresh.d.ts.map +1 -0
- package/dist/runtime/grokBrokerRefresh.js +15 -0
- package/dist/runtime/grokBrokerTurnMeter.d.ts +128 -0
- package/dist/runtime/grokBrokerTurnMeter.d.ts.map +1 -0
- package/dist/runtime/grokBrokerTurnMeter.js +251 -0
- package/dist/runtime/grokBrokerWorkerConfig.d.ts +86 -0
- package/dist/runtime/grokBrokerWorkerConfig.d.ts.map +1 -0
- package/dist/runtime/grokBrokerWorkerConfig.js +135 -0
- package/dist/runtime/grokEngineBroker.d.ts +48 -0
- package/dist/runtime/grokEngineBroker.d.ts.map +1 -0
- package/dist/runtime/grokEngineBroker.js +114 -0
- package/dist/runtime/grokEngineBrokerLedger.d.ts +52 -0
- package/dist/runtime/grokEngineBrokerLedger.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerLedger.js +114 -0
- package/dist/runtime/grokEngineBrokerMetering.d.ts +51 -0
- package/dist/runtime/grokEngineBrokerMetering.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerMetering.js +34 -0
- package/dist/runtime/grokEngineBrokerTurn.d.ts +58 -0
- package/dist/runtime/grokEngineBrokerTurn.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerTurn.js +165 -0
- package/dist/runtime/grokInferenceClientConfig.d.ts +41 -0
- package/dist/runtime/grokInferenceClientConfig.d.ts.map +1 -0
- package/dist/runtime/grokInferenceClientConfig.js +62 -0
- package/dist/runtime/grokInferenceGrants.d.ts +77 -0
- package/dist/runtime/grokInferenceGrants.d.ts.map +1 -0
- package/dist/runtime/grokInferenceGrants.js +116 -0
- package/dist/runtime/grokInferenceProxy.d.ts +29 -0
- package/dist/runtime/grokInferenceProxy.d.ts.map +1 -0
- package/dist/runtime/grokInferenceProxy.js +82 -0
- package/dist/runtime/grokInferenceProxyRequest.d.ts +23 -0
- package/dist/runtime/grokInferenceProxyRequest.d.ts.map +1 -0
- package/dist/runtime/grokInferenceProxyRequest.js +63 -0
- package/dist/runtime/grokSlotPreflightReceipt.d.ts +70 -0
- package/dist/runtime/grokSlotPreflightReceipt.d.ts.map +1 -0
- package/dist/runtime/grokSlotPreflightReceipt.js +101 -0
- package/dist/runtime/grokSubscriptionRealm.d.ts +4 -0
- package/dist/runtime/grokSubscriptionRealm.d.ts.map +1 -0
- package/dist/runtime/grokSubscriptionRealm.js +435 -0
- package/dist/runtime/grokSubscriptionRealmTypes.d.ts +26 -0
- package/dist/runtime/grokSubscriptionRealmTypes.d.ts.map +1 -0
- package/dist/runtime/grokSubscriptionRealmTypes.js +1 -0
- package/dist/runtime/grokWorkerAttestation.d.ts +170 -0
- package/dist/runtime/grokWorkerAttestation.d.ts.map +1 -0
- package/dist/runtime/grokWorkerAttestation.js +266 -0
- package/dist/runtime/grokWorkerDenyPlacement.d.ts +80 -0
- package/dist/runtime/grokWorkerDenyPlacement.d.ts.map +1 -0
- package/dist/runtime/grokWorkerDenyPlacement.js +128 -0
- package/dist/runtime/grokWorkerHomeAttestation.d.ts +30 -0
- package/dist/runtime/grokWorkerHomeAttestation.d.ts.map +1 -0
- package/dist/runtime/grokWorkerHomeAttestation.js +69 -0
- package/dist/runtime/grokWorkerSandboxProfile.d.ts +27 -0
- package/dist/runtime/grokWorkerSandboxProfile.d.ts.map +1 -0
- package/dist/runtime/grokWorkerSandboxProfile.js +44 -0
- package/dist/runtime/grokWorkerTmpAttestation.d.ts +55 -0
- package/dist/runtime/grokWorkerTmpAttestation.d.ts.map +1 -0
- package/dist/runtime/grokWorkerTmpAttestation.js +63 -0
- package/dist/runtime/index.d.ts +26 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +23 -0
- package/dist/runtime/inferenceUsageLedger.d.ts +38 -0
- package/dist/runtime/inferenceUsageLedger.d.ts.map +1 -0
- package/dist/runtime/inferenceUsageLedger.js +53 -0
- package/dist/runtime/mcpToolResult.d.ts +127 -0
- package/dist/runtime/mcpToolResult.d.ts.map +1 -0
- package/dist/runtime/mcpToolResult.js +214 -0
- package/dist/runtime/moltnetMachineRead.d.ts +97 -0
- package/dist/runtime/moltnetMachineRead.d.ts.map +1 -0
- package/dist/runtime/moltnetMachineRead.js +183 -0
- package/dist/runtime/native/daimon-engine-broker +0 -0
- package/dist/runtime/organizationRuntime.d.ts +165 -0
- package/dist/runtime/organizationRuntime.d.ts.map +1 -0
- package/dist/runtime/organizationRuntime.js +3 -0
- package/dist/runtime/organizationRuntimeControl.d.ts +42 -0
- package/dist/runtime/organizationRuntimeControl.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeControl.js +235 -0
- package/dist/runtime/organizationRuntimeHost.d.ts +19 -0
- package/dist/runtime/organizationRuntimeHost.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeHost.js +359 -0
- package/dist/runtime/organizationRuntimeParsing.d.ts +6 -0
- package/dist/runtime/organizationRuntimeParsing.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeParsing.js +370 -0
- package/dist/runtime/organizationRuntimeReadiness.d.ts +12 -0
- package/dist/runtime/organizationRuntimeReadiness.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeReadiness.js +59 -0
- package/dist/runtime/physicalReadiness.d.ts +47 -0
- package/dist/runtime/physicalReadiness.d.ts.map +1 -0
- package/dist/runtime/physicalReadiness.js +142 -0
- package/dist/runtime/portableCredentialAuth.d.ts +6 -0
- package/dist/runtime/portableCredentialAuth.d.ts.map +1 -0
- package/dist/runtime/portableCredentialAuth.js +70 -0
- package/dist/runtime/portableCredentialMaterial.d.ts +8 -0
- package/dist/runtime/portableCredentialMaterial.d.ts.map +1 -0
- package/dist/runtime/portableCredentialMaterial.js +169 -0
- package/dist/runtime/productionAgentTools.d.ts +5 -0
- package/dist/runtime/productionAgentTools.d.ts.map +1 -0
- package/dist/runtime/productionAgentTools.js +328 -0
- package/dist/runtime/runtimeHomeLayout.d.ts +48 -0
- package/dist/runtime/runtimeHomeLayout.d.ts.map +1 -0
- package/dist/runtime/runtimeHomeLayout.js +84 -0
- package/dist/runtime/schedule.d.ts +40 -0
- package/dist/runtime/schedule.d.ts.map +1 -0
- package/dist/runtime/schedule.js +371 -0
- package/dist/runtime/storeCoordination.d.ts +23 -0
- package/dist/runtime/storeCoordination.d.ts.map +1 -0
- package/dist/runtime/storeCoordination.js +94 -0
- package/dist/runtime/toolResultSpill.d.ts +152 -0
- package/dist/runtime/toolResultSpill.d.ts.map +1 -0
- package/dist/runtime/toolResultSpill.js +351 -0
- package/dist/runtime/turnRequestLedger.d.ts +160 -0
- package/dist/runtime/turnRequestLedger.d.ts.map +1 -0
- package/dist/runtime/turnRequestLedger.js +249 -0
- package/dist/runtime/turnUsageLedger.d.ts +143 -0
- package/dist/runtime/turnUsageLedger.d.ts.map +1 -0
- package/dist/runtime/turnUsageLedger.js +203 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts +17 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.js +50 -0
- package/dist/runtime/wakeAcceptanceReconciliation.d.ts +211 -0
- package/dist/runtime/wakeAcceptanceReconciliation.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceReconciliation.js +289 -0
- package/dist/runtime/wakeAcceptanceRecord.d.ts +23 -0
- package/dist/runtime/wakeAcceptanceRecord.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceRecord.js +56 -0
- package/dist/runtime/wakeAcceptanceRetention.d.ts +12 -0
- package/dist/runtime/wakeAcceptanceRetention.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceRetention.js +12 -0
- package/dist/runtime/wakeAcceptanceStore.d.ts +113 -0
- package/dist/runtime/wakeAcceptanceStore.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceStore.js +558 -0
- package/dist/runtime/wakeAcceptanceTypes.d.ts +179 -0
- package/dist/runtime/wakeAcceptanceTypes.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceTypes.js +95 -0
- package/dist/runtime/wakeFuse.d.ts +69 -0
- package/dist/runtime/wakeFuse.d.ts.map +1 -0
- package/dist/runtime/wakeFuse.js +367 -0
- package/package.json +25 -17
- package/dist/examples/mixed-engine-org.d.ts +0 -2
- package/dist/examples/mixed-engine-org.d.ts.map +0 -1
- package/dist/examples/mixed-engine-org.js +0 -351
- package/dist/examples/mixedEngineCli.d.ts +0 -15
- package/dist/examples/mixedEngineCli.d.ts.map +0 -1
- package/dist/examples/mixedEngineCli.js +0 -174
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import { GROK_WORKER_MAX_TURNS } from "../contracts/grokWorkerContract.js";
|
|
4
|
+
import { EngineBrokerCapabilities } from "./engineBrokerCapabilities.js";
|
|
5
|
+
import { EngineBrokerMcpCallLog } from "./engineBrokerMcpCallLog.js";
|
|
6
|
+
/**
|
|
7
|
+
* The brokered worker's only route to its own per-wake Daimon MCP mount. The
|
|
8
|
+
* worker holds a turn capability and nothing else: it never learns the mount's
|
|
9
|
+
* address, and the mount never learns the capability. Every header crossing
|
|
10
|
+
* either way is rebuilt from a closed allowlist, so this stays a boundary and
|
|
11
|
+
* not a transparent proxy — a blanket passthrough would hand the mount the
|
|
12
|
+
* worker's bearer and hand the worker whatever the mount chose to say.
|
|
13
|
+
*
|
|
14
|
+
* The allowlists are exactly the Streamable HTTP transport's own routing
|
|
15
|
+
* headers. Anything outside them (authorization above all, cookies, auth
|
|
16
|
+
* challenges, forwarding and tracing headers) is dropped in both directions.
|
|
17
|
+
*
|
|
18
|
+
* Client -> mount:
|
|
19
|
+
* - `content-type`: the JSON-RPC body's media type; the mount refuses a POST
|
|
20
|
+
* without it.
|
|
21
|
+
* - `accept`: the transport negotiates `application/json, text/event-stream`
|
|
22
|
+
* per request and the mount answers 406 when a POST does not accept both.
|
|
23
|
+
* - `mcp-session-id`: the opaque session the mount issued on `initialize`.
|
|
24
|
+
* Dropping it made the mount answer every later request with HTTP 400
|
|
25
|
+
* `Mcp-Session-Id header is required`, so no tool was ever reachable. It is
|
|
26
|
+
* a routing value, not a secret — and not a value to log either.
|
|
27
|
+
* - `mcp-protocol-version`: the version the handshake settled on. The mount
|
|
28
|
+
* validates it and otherwise assumes a default that can disagree with what
|
|
29
|
+
* the client negotiated.
|
|
30
|
+
* - `last-event-id`: SSE resumability. A reconnecting stream replays from the
|
|
31
|
+
* last event it saw; without it the mount cannot tell where to resume.
|
|
32
|
+
*
|
|
33
|
+
* Mount -> client:
|
|
34
|
+
* - `content-type`: tells the client whether it got JSON or an SSE stream.
|
|
35
|
+
* - `mcp-session-id`: the id minted on `initialize`. The client must learn it
|
|
36
|
+
* or it can never make a second request.
|
|
37
|
+
* - `mcp-protocol-version`: the version the mount confirms for the session.
|
|
38
|
+
* - `cache-control: no-store` is the facade's own, not the mount's.
|
|
39
|
+
*
|
|
40
|
+
* Methods are the three the transport uses: POST for JSON-RPC, GET for the
|
|
41
|
+
* server-to-client SSE stream (notifications and progress arrive only there),
|
|
42
|
+
* and DELETE to end a session. POST alone left the GET stream answering 403.
|
|
43
|
+
*/
|
|
44
|
+
const FORWARDED_REQUEST_HEADERS = ["content-type", "accept", "mcp-session-id", "mcp-protocol-version", "last-event-id"];
|
|
45
|
+
const FORWARDED_RESPONSE_HEADERS = ["content-type", "mcp-session-id", "mcp-protocol-version"];
|
|
46
|
+
const FORWARDED_METHODS = new Set(["POST", "GET", "DELETE"]);
|
|
47
|
+
const MAX_REQUEST_BYTES = 1024 * 1024;
|
|
48
|
+
export const ENGINE_BROKER_MCP_FACADE_PORT = 43_124;
|
|
49
|
+
/** Requests one worker round may legitimately make: its `search_tool`, its `use_tool`, and one spare for a retry or a second discovery. */
|
|
50
|
+
export const ENGINE_BROKER_MCP_ROUND_REQUESTS = 3;
|
|
51
|
+
/** The session's fixed cost, once per turn: `initialize`, `notifications/initialized`, `tools/list`, the standalone GET tunnel, the closing DELETE. */
|
|
52
|
+
export const ENGINE_BROKER_MCP_SESSION_REQUESTS = 5;
|
|
53
|
+
/**
|
|
54
|
+
* Requests one turn capability may spend, across all three methods — *derived*
|
|
55
|
+
* from the compiled turn bound rather than chosen.
|
|
56
|
+
*
|
|
57
|
+
* It was 128, and a legitimate 48-round wake needs ~101 of them: a worker's
|
|
58
|
+
* round is a `search_tool` and a `use_tool`, so the first round that also
|
|
59
|
+
* retries, or looks something up twice, eats the margin. A bound that can be
|
|
60
|
+
* predicted to bite mid-turn is not a bound, it is a 403 storm waiting for a
|
|
61
|
+
* real wake — and a number raised until it feels comfortable is not one
|
|
62
|
+
* either, because the budget exists to cap a *compromised* worker.
|
|
63
|
+
*
|
|
64
|
+
* So the two numbers that must agree are kept in one place: the launcher's
|
|
65
|
+
* `--max-turns` backstop ({@link GROK_WORKER_MAX_TURNS}) times what a round
|
|
66
|
+
* may legitimately spend, plus the session's fixed cost. Raising the turn
|
|
67
|
+
* bound raises this with it, and a compromised worker still gets exactly three
|
|
68
|
+
* MCP calls per round it was compiled to take and not one more. The arithmetic
|
|
69
|
+
* is spelled out rather than folded into a literal so it can be audited: the
|
|
70
|
+
* two multiplicands above each say what they are.
|
|
71
|
+
*/
|
|
72
|
+
export const ENGINE_BROKER_MCP_CAPABILITY_REQUESTS = GROK_WORKER_MAX_TURNS * ENGINE_BROKER_MCP_ROUND_REQUESTS + ENGINE_BROKER_MCP_SESSION_REQUESTS;
|
|
73
|
+
export const ENGINE_BROKER_MCP_CAPABILITY_TTL_MS = 15 * 60_000;
|
|
74
|
+
class FacadeRefusal extends Error {
|
|
75
|
+
}
|
|
76
|
+
export async function startEngineBrokerMcpFacade() {
|
|
77
|
+
const capabilities = new EngineBrokerCapabilities();
|
|
78
|
+
const targets = new Map();
|
|
79
|
+
/** In-flight upstream calls per turn, so a revoke or a close tears down any open SSE tunnel. */
|
|
80
|
+
const inflight = new Map();
|
|
81
|
+
/**
|
|
82
|
+
* What the facade saw of each turn's tool calls. A tool receipt is written
|
|
83
|
+
* only on completion, so without this a call that started and never returned
|
|
84
|
+
* and a call never made are the same absence (`engineBrokerMcpCallLog.ts`).
|
|
85
|
+
*/
|
|
86
|
+
const calls = new EngineBrokerMcpCallLog();
|
|
87
|
+
const server = createServer((request, response) => {
|
|
88
|
+
void route(request, response).catch((error) => {
|
|
89
|
+
if (response.headersSent || response.destroyed) {
|
|
90
|
+
response.destroy();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const status = error instanceof FacadeRefusal ? 403 : 502;
|
|
94
|
+
const body = error instanceof FacadeRefusal ? '{"error":"forbidden"}' : '{"error":"bad_gateway"}';
|
|
95
|
+
response.writeHead(status, { "content-type": "application/json", "cache-control": "no-store" });
|
|
96
|
+
response.end(body);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* A 403 the call log can read, whenever the bearer names a turn.
|
|
101
|
+
*
|
|
102
|
+
* The refusal itself is unchanged — same status, same body, same silence
|
|
103
|
+
* towards the worker — but it is attributed first, through a lookup that
|
|
104
|
+
* does not spend the capability's budget. A bearer no grant matches names no
|
|
105
|
+
* turn and stays unattributed, because guessing whose it was would be
|
|
106
|
+
* inventing the measurement. A capability that is *also* spent or expired
|
|
107
|
+
* reports that instead of the route it asked for: it is the fault the
|
|
108
|
+
* operator can act on.
|
|
109
|
+
*/
|
|
110
|
+
function refuse(bearer, live) {
|
|
111
|
+
const classified = bearer === undefined ? undefined : capabilities.classifyToken(bearer);
|
|
112
|
+
if (classified !== undefined)
|
|
113
|
+
calls.refuse(classified.turnId, classified.state === "live" ? live : classified.state);
|
|
114
|
+
return new FacadeRefusal();
|
|
115
|
+
}
|
|
116
|
+
async function route(request, response) {
|
|
117
|
+
const method = request.method ?? "";
|
|
118
|
+
const bearer = request.headers.authorization?.match(/^Bearer ([A-Za-z0-9_-]{40,})$/u)?.[1];
|
|
119
|
+
if (request.url !== "/mcp" || !FORWARDED_METHODS.has(method))
|
|
120
|
+
throw refuse(bearer, "route");
|
|
121
|
+
if (bearer === undefined)
|
|
122
|
+
throw new FacadeRefusal();
|
|
123
|
+
const scope = capabilities.authorizeToken(bearer);
|
|
124
|
+
// A live grant that authorizes is the only way past here; anything else is
|
|
125
|
+
// classified so an exhausted budget and an expired TTL reach the turn's
|
|
126
|
+
// sealed row as themselves. `live` cannot be the answer on this path —
|
|
127
|
+
// `authorizeToken` read the same grant a moment ago, expiry only moves
|
|
128
|
+
// forward and a budget only spends — so it is the unreachable arm.
|
|
129
|
+
if (!scope)
|
|
130
|
+
throw refuse(bearer, "expired");
|
|
131
|
+
const target = targets.get(scope.turnId);
|
|
132
|
+
if (target === undefined) {
|
|
133
|
+
calls.refuse(scope.turnId, "unrouted");
|
|
134
|
+
throw new FacadeRefusal();
|
|
135
|
+
}
|
|
136
|
+
// Only POST carries a JSON-RPC body; drain anything else so the socket
|
|
137
|
+
// never stalls waiting for a body the facade will not forward.
|
|
138
|
+
let body;
|
|
139
|
+
// A body refused for size is a call the log can never name, and counting
|
|
140
|
+
// it keeps "no tool call started" an honest reading rather than a gap.
|
|
141
|
+
try {
|
|
142
|
+
body = method === "POST" ? await bounded(request) : (request.resume(), undefined);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
calls.undecodable(scope.turnId);
|
|
146
|
+
// A body past the bound is refused, not merely unreadable: the worker
|
|
147
|
+
// gets a 403 for it, so it is counted as one too.
|
|
148
|
+
if (error instanceof FacadeRefusal)
|
|
149
|
+
calls.refuse(scope.turnId, "oversized");
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
const payload = body === undefined ? undefined : body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
153
|
+
const call = calls.begin(scope.turnId, body);
|
|
154
|
+
// The GET SSE tunnel is the session's other channel and the one that
|
|
155
|
+
// outlives every request: it stays open until the worker or the mount ends
|
|
156
|
+
// it, so a turn sealed with one still open is a turn whose worker may be
|
|
157
|
+
// parked on it. Observed only — never closed, timed out or refused here.
|
|
158
|
+
const tunnel = method === "GET" ? calls.openTunnel(scope.turnId) : undefined;
|
|
159
|
+
const controller = new AbortController();
|
|
160
|
+
const open = inflight.get(scope.turnId) ?? new Set();
|
|
161
|
+
open.add(controller);
|
|
162
|
+
inflight.set(scope.turnId, open);
|
|
163
|
+
const abort = () => controller.abort();
|
|
164
|
+
response.on("close", abort);
|
|
165
|
+
try {
|
|
166
|
+
// Answered only on a relay that reached its own end: a tunnel torn down
|
|
167
|
+
// by the worker's death must not mark the call it was blocked on as
|
|
168
|
+
// finished.
|
|
169
|
+
if (await forward(target, method, headersFor(method, request), payload, controller.signal, response, tunnel))
|
|
170
|
+
call.answer();
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
call.close();
|
|
174
|
+
tunnel?.close();
|
|
175
|
+
response.off("close", abort);
|
|
176
|
+
open.delete(controller);
|
|
177
|
+
if (open.size === 0)
|
|
178
|
+
inflight.delete(scope.turnId);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function endTurnStreams(turnId) {
|
|
182
|
+
for (const controller of inflight.get(turnId) ?? [])
|
|
183
|
+
controller.abort();
|
|
184
|
+
inflight.delete(turnId);
|
|
185
|
+
}
|
|
186
|
+
await new Promise((resolve, reject) => {
|
|
187
|
+
server.once("error", reject);
|
|
188
|
+
server.listen(ENGINE_BROKER_MCP_FACADE_PORT, "127.0.0.1", () => { server.off("error", reject); resolve(); });
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
register(agentId, turnId, endpoint) {
|
|
192
|
+
const url = new URL(endpoint);
|
|
193
|
+
if (url.protocol !== "http:" || url.hostname !== "127.0.0.1" || url.pathname !== "/mcp")
|
|
194
|
+
throw new TypeError("invalid scoped MCP mount");
|
|
195
|
+
if (targets.has(turnId))
|
|
196
|
+
throw new Error("MCP turn already registered");
|
|
197
|
+
targets.set(turnId, url.href);
|
|
198
|
+
calls.open(turnId);
|
|
199
|
+
return capabilities.issue(agentId, turnId, ENGINE_BROKER_MCP_CAPABILITY_TTL_MS, ENGINE_BROKER_MCP_CAPABILITY_REQUESTS);
|
|
200
|
+
},
|
|
201
|
+
revoke(turnId) {
|
|
202
|
+
targets.delete(turnId);
|
|
203
|
+
capabilities.revoke(turnId);
|
|
204
|
+
endTurnStreams(turnId);
|
|
205
|
+
calls.close(turnId);
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* What the facade saw of this turn's tool calls, GET tunnels and refusals,
|
|
209
|
+
* or `undefined` for a turn
|
|
210
|
+
* it never registered. Read on the failure path, before `revoke`.
|
|
211
|
+
*/
|
|
212
|
+
observe: (turnId) => calls.observe(turnId),
|
|
213
|
+
close: async () => {
|
|
214
|
+
for (const turnId of [...inflight.keys()])
|
|
215
|
+
endTurnStreams(turnId);
|
|
216
|
+
await new Promise((resolve, reject) => {
|
|
217
|
+
server.close((error) => (error ? reject(error) : resolve()));
|
|
218
|
+
// A GET SSE tunnel keeps its socket open indefinitely, and `close`
|
|
219
|
+
// only stops accepting; without this a shutdown would hang on it.
|
|
220
|
+
server.closeAllConnections();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/** The client -> mount allowlist, with the two defaults the mount requires of a POST. */
|
|
226
|
+
function headersFor(method, request) {
|
|
227
|
+
const headers = {};
|
|
228
|
+
for (const name of FORWARDED_REQUEST_HEADERS) {
|
|
229
|
+
const value = request.headers[name];
|
|
230
|
+
if (typeof value === "string" && value.length > 0)
|
|
231
|
+
headers[name] = value;
|
|
232
|
+
}
|
|
233
|
+
if (method === "POST") {
|
|
234
|
+
headers["content-type"] ??= "application/json";
|
|
235
|
+
headers["accept"] ??= "application/json, text/event-stream";
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
delete headers["content-type"];
|
|
239
|
+
}
|
|
240
|
+
return headers;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Streams the exchange rather than buffering it: a GET stream stays open for
|
|
244
|
+
* the whole session, and a buffered POST would withhold progress
|
|
245
|
+
* notifications until the call had already finished.
|
|
246
|
+
*/
|
|
247
|
+
async function forward(target, method, headers, body, signal, response, tunnel) {
|
|
248
|
+
const upstream = await fetch(target, { method, headers, body, signal, redirect: "manual" });
|
|
249
|
+
// MCP never redirects, and following one would let the mount aim the facade
|
|
250
|
+
// at a host the capability was never scoped to. `manual` also reports an
|
|
251
|
+
// opaque redirect as status 0, which is not a status to relay at all.
|
|
252
|
+
const relayable = (upstream.status >= 200 && upstream.status < 300) || (upstream.status >= 400 && upstream.status <= 599);
|
|
253
|
+
if (!relayable)
|
|
254
|
+
throw new Error("unexpected MCP mount status");
|
|
255
|
+
const outbound = { "cache-control": "no-store" };
|
|
256
|
+
for (const name of FORWARDED_RESPONSE_HEADERS) {
|
|
257
|
+
const value = upstream.headers.get(name);
|
|
258
|
+
if (value !== null && value.length > 0)
|
|
259
|
+
outbound[name] = value;
|
|
260
|
+
}
|
|
261
|
+
outbound["content-type"] ??= "application/json";
|
|
262
|
+
response.writeHead(upstream.status, outbound);
|
|
263
|
+
if (upstream.body === null) {
|
|
264
|
+
response.end();
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
const stream = Readable.fromWeb(upstream.body);
|
|
268
|
+
let delivered = false;
|
|
269
|
+
try {
|
|
270
|
+
for await (const chunk of stream) {
|
|
271
|
+
// The first byte the mount pushes: a tunnel that carried frames is a
|
|
272
|
+
// different fact from one held open having delivered nothing.
|
|
273
|
+
if (!delivered) {
|
|
274
|
+
delivered = true;
|
|
275
|
+
tunnel?.deliver();
|
|
276
|
+
}
|
|
277
|
+
if (response.destroyed || response.writableEnded)
|
|
278
|
+
throw new Error("MCP tunnel closed");
|
|
279
|
+
if (!response.write(chunk))
|
|
280
|
+
await awaitMcpTunnelDrain(response, signal);
|
|
281
|
+
}
|
|
282
|
+
response.end();
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// The client hung up or the mount's stream broke: tear the tunnel down
|
|
287
|
+
// rather than leaving a half-written response open.
|
|
288
|
+
response.destroy();
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
stream.destroy();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Waits for a backpressured tunnel to drain, or for the tunnel to end —
|
|
297
|
+
* whichever happens first, but always one of them.
|
|
298
|
+
*
|
|
299
|
+
* A bare `once("drain")` never settles for a client that hung up mid-write:
|
|
300
|
+
* `drain` cannot fire on a socket nobody is reading, and neither the
|
|
301
|
+
* response's own `close` nor the turn's abort woke that await. The GET SSE
|
|
302
|
+
* tunnel stays open for a whole session, so the handler — and the upstream
|
|
303
|
+
* call it was relaying — leaked for the life of the broker process, with no
|
|
304
|
+
* refusal, no status and no line anywhere to read. Every outcome settles this
|
|
305
|
+
* now, and every outcome but an actual drain *rejects*, so the caller tears
|
|
306
|
+
* the tunnel down instead of writing into a socket that is gone.
|
|
307
|
+
*
|
|
308
|
+
* Exported for its own test: a hang is only observable from inside.
|
|
309
|
+
*/
|
|
310
|
+
export function awaitMcpTunnelDrain(response, signal) {
|
|
311
|
+
if (response.destroyed || response.writableEnded)
|
|
312
|
+
return Promise.reject(new Error("MCP tunnel closed"));
|
|
313
|
+
if (signal.aborted)
|
|
314
|
+
return Promise.reject(new Error("MCP tunnel aborted"));
|
|
315
|
+
return new Promise((resolve, reject) => {
|
|
316
|
+
const settle = (finish) => () => {
|
|
317
|
+
response.off("drain", onDrain);
|
|
318
|
+
response.off("close", onClosed);
|
|
319
|
+
response.off("error", onClosed);
|
|
320
|
+
signal.removeEventListener("abort", onAborted);
|
|
321
|
+
finish();
|
|
322
|
+
};
|
|
323
|
+
const onDrain = settle(resolve);
|
|
324
|
+
const onClosed = settle(() => reject(new Error("MCP tunnel closed")));
|
|
325
|
+
const onAborted = settle(() => reject(new Error("MCP tunnel aborted")));
|
|
326
|
+
response.once("drain", onDrain);
|
|
327
|
+
response.once("close", onClosed);
|
|
328
|
+
response.once("error", onClosed);
|
|
329
|
+
signal.addEventListener("abort", onAborted, { once: true });
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
async function bounded(request) {
|
|
333
|
+
const chunks = [];
|
|
334
|
+
let bytes = 0;
|
|
335
|
+
for await (const chunk of request) {
|
|
336
|
+
const value = Buffer.from(chunk);
|
|
337
|
+
bytes += value.length;
|
|
338
|
+
if (bytes > MAX_REQUEST_BYTES)
|
|
339
|
+
throw new FacadeRefusal();
|
|
340
|
+
chunks.push(value);
|
|
341
|
+
}
|
|
342
|
+
return Buffer.concat(chunks);
|
|
343
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const ENGINE_BROKER_NATIVE_REQUEST_BYTES = 396;
|
|
2
|
+
export declare const ENGINE_BROKER_NATIVE_RESULT_BYTES = 128;
|
|
3
|
+
/** `DBL_MAX_DIAGNOSTIC`: the launcher's bounded tail of a failed worker's own merged stdout/stderr. */
|
|
4
|
+
export declare const ENGINE_BROKER_NATIVE_DIAGNOSTIC_BYTES = 512;
|
|
5
|
+
declare const statuses: readonly ["ok", "prelaunch_failed", "worker_failed", "output_failed", "cancelled"];
|
|
6
|
+
declare const stages: readonly ["none", "peer", "request", "registration", "executable", "exec", "wait", "output", "attestation"];
|
|
7
|
+
declare const failures: readonly ["none", "peer", "protocol", "registration", "executable", "exec", "wait", "output_limit", "cancelled", "profile_missing", "profile_invalid"];
|
|
8
|
+
export interface NativeBrokerDiagnostic {
|
|
9
|
+
exitCode: number;
|
|
10
|
+
failureClass: typeof failures[number];
|
|
11
|
+
profileApplied: boolean;
|
|
12
|
+
reason?: string;
|
|
13
|
+
stage: typeof stages[number];
|
|
14
|
+
startTicks: string;
|
|
15
|
+
status: typeof statuses[number];
|
|
16
|
+
termSignal: number;
|
|
17
|
+
workerPid: number;
|
|
18
|
+
workerUid: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class NativeBrokerTurnFailure extends Error {
|
|
21
|
+
readonly diagnostic: NativeBrokerDiagnostic;
|
|
22
|
+
constructor(diagnostic: NativeBrokerDiagnostic);
|
|
23
|
+
}
|
|
24
|
+
export type NativeBrokerTurn = Readonly<{
|
|
25
|
+
slot: number;
|
|
26
|
+
requestId: string;
|
|
27
|
+
turnId: string;
|
|
28
|
+
agentId: string;
|
|
29
|
+
wakeId: string;
|
|
30
|
+
prompt: string;
|
|
31
|
+
providerCapability: string;
|
|
32
|
+
mcpCapability: string;
|
|
33
|
+
}>;
|
|
34
|
+
export interface NativeBrokerTurnResult {
|
|
35
|
+
text: string;
|
|
36
|
+
workerPid: number;
|
|
37
|
+
workerUid: number;
|
|
38
|
+
startTicks: bigint;
|
|
39
|
+
diagnostic: NativeBrokerDiagnostic;
|
|
40
|
+
}
|
|
41
|
+
export declare function runNativeBrokerTurn(executable: string, input: NativeBrokerTurn, signal?: AbortSignal): Promise<Readonly<NativeBrokerTurnResult>>;
|
|
42
|
+
export declare function encodeNativeBrokerTurn(input: NativeBrokerTurn): Buffer;
|
|
43
|
+
/**
|
|
44
|
+
* `output` is accepted as any byte view, and normalized to a `Buffer` once
|
|
45
|
+
* here: `Uint8Array.prototype.toString("utf8")` ignores its argument and
|
|
46
|
+
* renders the bytes as comma-separated decimals, which is how a live worker's
|
|
47
|
+
* last words reached an operator as `reason=108,111,110,101,...` instead of a
|
|
48
|
+
* sentence. Decoding is explicit from here on, never a stringification.
|
|
49
|
+
*/
|
|
50
|
+
export declare function decodeNativeBrokerResult(input: Uint8Array, turnId: string, secrets?: readonly string[]): NativeBrokerTurnResult;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=engineBrokerNativeClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineBrokerNativeClient.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerNativeClient.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kCAAkC,MAAM,CAAC;AACtD,eAAO,MAAM,iCAAiC,MAAM,CAAC;AACrD,uGAAuG;AACvG,eAAO,MAAM,qCAAqC,MAAM,CAAC;AAGzD,QAAA,MAAM,QAAQ,oFAAqF,CAAC;AACpG,QAAA,MAAM,MAAM,6GAA8G,CAAC;AAC3H,QAAA,MAAM,QAAQ,wJAAyJ,CAAC;AAExK,MAAM,WAAW,sBAAsB;IAAG,QAAQ,EAAC,MAAM,CAAC;IAAA,YAAY,EAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;IAAA,cAAc,EAAC,OAAO,CAAC;IAAA,MAAM,CAAC,EAAC,MAAM,CAAC;IAAA,KAAK,EAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,CAAA;CAAE;AACvQ,qBAAa,uBAAwB,SAAQ,KAAK;IAAe,QAAQ,CAAC,UAAU,EAAC,sBAAsB;gBAAjC,UAAU,EAAC,sBAAsB;CAAwC;AACnJ,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IAAC,IAAI,EAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,OAAO,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,kBAAkB,EAAC,MAAM,CAAC;IAAA,aAAa,EAAC,MAAM,CAAA;CAAC,CAAC,CAAC;AAChL,MAAM,WAAW,sBAAsB;IAAE,IAAI,EAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,CAAC;IAAA,UAAU,EAAC,MAAM,CAAC;IAAA,UAAU,EAAC,sBAAsB,CAAA;CAAC;AAE3I,wBAAsB,mBAAmB,CAAC,UAAU,EAAC,MAAM,EAAC,KAAK,EAAC,gBAAgB,EAAC,MAAM,CAAC,EAAC,WAAW,GAAE,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAIhJ;AACD,wBAAgB,sBAAsB,CAAC,KAAK,EAAC,gBAAgB,GAAE,MAAM,CAAqkC;AAE1oC;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAC,UAAU,EAAC,MAAM,EAAC,MAAM,EAAC,OAAO,GAAC,SAAS,MAAM,EAAK,GAAE,sBAAsB,CAkB3H"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { redactCredentialText } from "../core/credentialRedaction.js";
|
|
3
|
+
import { boundedDiagnosticWindow, CLI_ENGINE_MAX_DIAGNOSTIC_BYTES } from "../pi/cliChildOutput.js";
|
|
4
|
+
import { terminateChild, trackCliChild } from "../pi/cliProcess.js";
|
|
5
|
+
export const ENGINE_BROKER_NATIVE_REQUEST_BYTES = 396;
|
|
6
|
+
export const ENGINE_BROKER_NATIVE_RESULT_BYTES = 128;
|
|
7
|
+
/** `DBL_MAX_DIAGNOSTIC`: the launcher's bounded tail of a failed worker's own merged stdout/stderr. */
|
|
8
|
+
export const ENGINE_BROKER_NATIVE_DIAGNOSTIC_BYTES = 512;
|
|
9
|
+
/** `DBL_MAX_OUTPUT`: the launcher's bound on a whole turn's stdout, and the control protocol's own `text` bound, which is the next boundary this output crosses. */
|
|
10
|
+
const MAX_PROMPT = 65_536, MAX_CAPABILITY = 4_096, MAX_OUTPUT = 262_144;
|
|
11
|
+
const statuses = ["ok", "prelaunch_failed", "worker_failed", "output_failed", "cancelled"];
|
|
12
|
+
const stages = ["none", "peer", "request", "registration", "executable", "exec", "wait", "output", "attestation"];
|
|
13
|
+
const failures = ["none", "peer", "protocol", "registration", "executable", "exec", "wait", "output_limit", "cancelled", "profile_missing", "profile_invalid"];
|
|
14
|
+
export class NativeBrokerTurnFailure extends Error {
|
|
15
|
+
diagnostic;
|
|
16
|
+
constructor(diagnostic) {
|
|
17
|
+
super("engine broker turn failed");
|
|
18
|
+
this.diagnostic = diagnostic;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function runNativeBrokerTurn(executable, input, signal) {
|
|
22
|
+
const frame = encodeNativeBrokerTurn(input), child = trackCliChild(spawn(executable, ["--client"], { detached: process.platform !== "win32", env: { LANG: "C", LC_ALL: "C", TZ: "UTC" }, stdio: ["pipe", "pipe", "ignore"], ...(signal === undefined ? {} : { signal }) }));
|
|
23
|
+
const chunks = [];
|
|
24
|
+
let bytes = 0;
|
|
25
|
+
child.stdout.on("data", (chunk) => { bytes += chunk.length; if (bytes <= ENGINE_BROKER_NATIVE_RESULT_BYTES + MAX_OUTPUT)
|
|
26
|
+
chunks.push(chunk); });
|
|
27
|
+
child.stdin.end(frame);
|
|
28
|
+
frame.fill(0);
|
|
29
|
+
try {
|
|
30
|
+
const code = await new Promise((resolve, reject) => { child.once("error", reject); child.once("exit", resolve); });
|
|
31
|
+
if (code !== 0 || bytes > ENGINE_BROKER_NATIVE_RESULT_BYTES + MAX_OUTPUT)
|
|
32
|
+
throw new Error();
|
|
33
|
+
return decodeNativeBrokerResult(Buffer.concat(chunks), input.turnId, [input.providerCapability, input.mcpCapability]);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error instanceof NativeBrokerTurnFailure)
|
|
37
|
+
throw error;
|
|
38
|
+
throw new Error("engine broker turn failed");
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await terminateChild(child).catch(() => undefined);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function encodeNativeBrokerTurn(input) { if (!Number.isInteger(input.slot) || input.slot < 0)
|
|
45
|
+
throw new TypeError("invalid engine broker turn"); const p = Buffer.from(input.prompt), provider = Buffer.from(input.providerCapability), mcp = Buffer.from(input.mcpCapability); if (p.length < 1 || p.length > MAX_PROMPT || provider.length < 1 || provider.length > MAX_CAPABILITY || mcp.length < 1 || mcp.length > MAX_CAPABILITY || provider.equals(mcp))
|
|
46
|
+
throw new TypeError("invalid engine broker turn"); const c = Buffer.alloc(4 + provider.length + mcp.length); c.writeUInt16LE(provider.length, 0); provider.copy(c, 2); c.writeUInt16LE(mcp.length, 2 + provider.length); mcp.copy(c, 4 + provider.length); const frame = Buffer.alloc(ENGINE_BROKER_NATIVE_REQUEST_BYTES + 8 + p.length + c.length); frame.writeUInt32LE(2, 0); frame.writeUInt32LE(input.slot, 4); field(frame, 8, 65, input.requestId); field(frame, 73, 65, input.turnId); field(frame, 138, 129, input.agentId); field(frame, 267, 129, input.wakeId); let o = ENGINE_BROKER_NATIVE_REQUEST_BYTES; frame.writeUInt32LE(p.length, o); o += 4; p.copy(frame, o); o += p.length; frame.writeUInt32LE(c.length, o); o += 4; c.copy(frame, o); p.fill(0); provider.fill(0); mcp.fill(0); c.fill(0); return frame; }
|
|
47
|
+
/**
|
|
48
|
+
* `output` is accepted as any byte view, and normalized to a `Buffer` once
|
|
49
|
+
* here: `Uint8Array.prototype.toString("utf8")` ignores its argument and
|
|
50
|
+
* renders the bytes as comma-separated decimals, which is how a live worker's
|
|
51
|
+
* last words reached an operator as `reason=108,111,110,101,...` instead of a
|
|
52
|
+
* sentence. Decoding is explicit from here on, never a stringification.
|
|
53
|
+
*/
|
|
54
|
+
export function decodeNativeBrokerResult(input, turnId, secrets = []) {
|
|
55
|
+
const output = Buffer.isBuffer(input) ? input : Buffer.from(input.buffer, input.byteOffset, input.byteLength);
|
|
56
|
+
if (output.length < ENGINE_BROKER_NATIVE_RESULT_BYTES)
|
|
57
|
+
throw new Error("engine broker turn failed");
|
|
58
|
+
const status = output.readUInt32LE(4), uid = output.readUInt32LE(8), length = output.readUInt32LE(12), pid = output.readInt32LE(16), exitCode = output.readInt32LE(20), termSignal = output.readInt32LE(24), ticks = output.readBigUInt64LE(32), stage = output.readUInt32LE(108), failure = output.readUInt32LE(112), profile = output.readUInt32LE(116), diagnosticLength = output.readUInt32LE(120), observed = output.subarray(40, 105).toString("utf8").replace(/\0.*$/u, "");
|
|
59
|
+
const paddingZero = [output.subarray(28, 32), output.subarray(105, 108), output.subarray(124, 128)].every((bytes) => bytes.every((byte) => byte === 0));
|
|
60
|
+
if (output.length !== ENGINE_BROKER_NATIVE_RESULT_BYTES + length + diagnosticLength || output.readUInt32LE(0) !== 2 || status >= statuses.length || stage >= stages.length || failure >= failures.length || profile > 1 || !paddingZero || observed !== turnId || length > MAX_OUTPUT || diagnosticLength > ENGINE_BROKER_NATIVE_DIAGNOSTIC_BYTES)
|
|
61
|
+
throw new Error("engine broker turn failed");
|
|
62
|
+
// Decoded from the caller's own view, not from the normalized frame: the
|
|
63
|
+
// decode is what must be correct for any byte view, and it is the step the
|
|
64
|
+
// live `reason=108,111,110,...` failure came from.
|
|
65
|
+
const reason = workerReason(input.subarray(ENGINE_BROKER_NATIVE_RESULT_BYTES + length), secrets);
|
|
66
|
+
const diagnostic = { status: statuses[status], stage: stages[stage], failureClass: failures[failure], profileApplied: profile === 1, ...(reason === undefined ? {} : { reason }), exitCode, termSignal, workerPid: pid, workerUid: uid, startTicks: ticks.toString() };
|
|
67
|
+
const success = status === 0 && stage === 7 && failure === 0 && profile === 0 && pid > 0 && uid >= 2200 && ticks > 0n && exitCode === 0 && termSignal === 0 && diagnosticLength === 0;
|
|
68
|
+
const prelaunch = status === 1 && stage >= 1 && stage <= 5 && failure >= 1 && failure <= 5 && profile === 0 && pid === 0 && uid === 0 && ticks === 0n && diagnosticLength === 0;
|
|
69
|
+
const worker = status === 2 && stage === 6 && (failure === 5 || failure === 6) && profile === 0 && pid > 0 && uid >= 2200 && ticks > 0n;
|
|
70
|
+
const outputFailure = status === 3 && stage === 7 && failure === 7 && profile === 0 && pid > 0 && uid >= 2200 && ticks > 0n;
|
|
71
|
+
const cancelled = status === 4 && stage === 6 && failure === 8 && profile === 0 && pid > 0 && uid >= 2200 && ticks > 0n;
|
|
72
|
+
if (!success) {
|
|
73
|
+
if (length !== 0 || (!prelaunch && !worker && !outputFailure && !cancelled))
|
|
74
|
+
throw new Error("engine broker turn failed");
|
|
75
|
+
throw new NativeBrokerTurnFailure(diagnostic);
|
|
76
|
+
}
|
|
77
|
+
return { text: output.subarray(ENGINE_BROKER_NATIVE_RESULT_BYTES).toString("utf8"), workerUid: uid, workerPid: pid, startTicks: ticks, diagnostic };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The worker's own last words, fit to cross a boundary.
|
|
81
|
+
*
|
|
82
|
+
* A failed brokered turn otherwise reports nothing but `exit=1`: the launcher
|
|
83
|
+
* merges the worker's stdout and stderr into one pipe and publishes no output
|
|
84
|
+
* for a failure, so this bounded window is the only account of why it failed.
|
|
85
|
+
* It keeps both ends of what it is given (`boundedDiagnosticWindow`), because
|
|
86
|
+
* a worker that dies early prints its error before it echoes anything.
|
|
87
|
+
* It is worker-controlled text, so it is redacted exactly as the CLI child
|
|
88
|
+
* path redacts a failed engine child (`redactCredentialText` with the turn's
|
|
89
|
+
* own capabilities as exact secrets, the same diagnostic bound) and flattened
|
|
90
|
+
* to one line, because it travels inside a failure message.
|
|
91
|
+
*/
|
|
92
|
+
function workerReason(tail, secrets) {
|
|
93
|
+
if (tail.byteLength === 0)
|
|
94
|
+
return undefined;
|
|
95
|
+
// Decoded explicitly, and with replacement rather than a throw: the window
|
|
96
|
+
// is a byte count, so it can cut a multi-byte sequence in half at either
|
|
97
|
+
// end, and a worker's last words must not be lost to its own encoding.
|
|
98
|
+
const flattened = UTF8.decode(tail).replace(/[\u0000-\u001f\u007f]+/gu, " ").replace(/\s+/gu, " ").trim();
|
|
99
|
+
// Redact first, unbounded, then window: redaction can lengthen the text
|
|
100
|
+
// ([REDACTED] is longer than a short secret), so bounding before it could
|
|
101
|
+
// hand back more bytes than the boundary admits.
|
|
102
|
+
const redacted = redactCredentialText(scrubCutFragments(flattened, secrets), secrets, Number.MAX_SAFE_INTEGER).trim();
|
|
103
|
+
const reason = boundedDiagnosticWindow(redacted, CLI_ENGINE_MAX_DIAGNOSTIC_BYTES).trim();
|
|
104
|
+
return reason.length === 0 ? undefined : reason;
|
|
105
|
+
}
|
|
106
|
+
/** Non-fatal by construction: a cut multi-byte sequence becomes U+FFFD, never an exception. */
|
|
107
|
+
const UTF8 = new TextDecoder("utf-8");
|
|
108
|
+
/**
|
|
109
|
+
* A credential the launcher's window cut in half, at either side of a cut.
|
|
110
|
+
*
|
|
111
|
+
* Exact redaction matches a secret whole, so a secret a cut split survives as
|
|
112
|
+
* a fragment it can never match: the piece before a cut can end with a
|
|
113
|
+
* secret's prefix, and the piece after it can begin with a secret's suffix.
|
|
114
|
+
* The trick that answers this where Daimon owns both ends — retain one whole
|
|
115
|
+
* secret more than is reported (`cliChildOutput.ts`) — cannot work at this
|
|
116
|
+
* boundary, because the launcher's window *is* what it sends: a margin
|
|
117
|
+
* reserved there would be reported along with everything else. So the fragment
|
|
118
|
+
* is matched here, where the turn's own capabilities are known, and every cut
|
|
119
|
+
* the window can make is covered: the two sides of each elision marker, and
|
|
120
|
+
* the outer ends, where the launcher's capture itself stopped reading.
|
|
121
|
+
*
|
|
122
|
+
* Only a fragment long enough to be a credential is scrubbed. Below
|
|
123
|
+
* {@link MIN_CREDENTIAL_FRAGMENT} characters a piece of a random token is
|
|
124
|
+
* indistinguishable from ordinary words and carries nothing usable, and
|
|
125
|
+
* scrubbing it would eat real text.
|
|
126
|
+
*/
|
|
127
|
+
const MIN_CREDENTIAL_FRAGMENT = 12;
|
|
128
|
+
const ELISION_MARKER = /(\[… \d+ bytes elided …\])/u;
|
|
129
|
+
const scrubCutFragments = (value, secrets) => value.split(ELISION_MARKER).map((part) => ELISION_MARKER.test(part) ? part : scrubEnds(part, secrets)).join("");
|
|
130
|
+
function scrubEnds(part, secrets) {
|
|
131
|
+
let result = part;
|
|
132
|
+
for (const secret of secrets) {
|
|
133
|
+
if (secret.length <= MIN_CREDENTIAL_FRAGMENT)
|
|
134
|
+
continue;
|
|
135
|
+
for (let length = Math.min(secret.length - 1, result.length); length >= MIN_CREDENTIAL_FRAGMENT; length -= 1) {
|
|
136
|
+
if (result.endsWith(secret.slice(0, length))) {
|
|
137
|
+
result = `${result.slice(0, result.length - length)}[REDACTED]`;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (let length = Math.min(secret.length - 1, result.length); length >= MIN_CREDENTIAL_FRAGMENT; length -= 1) {
|
|
142
|
+
if (result.startsWith(secret.slice(secret.length - length))) {
|
|
143
|
+
result = `[REDACTED]${result.slice(length)}`;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
function field(target, offset, length, value) { if (!/^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(value) || Buffer.byteLength(value) >= length)
|
|
151
|
+
throw new TypeError("invalid engine broker turn"); target.write(value, offset, "utf8"); }
|