* Build the `chat()` stream that runs the harness on THIS container via the * `local-process` sandbox. The agent's `chat()` tools are stubs that delegate * back to the DO; everything else (the harness loop, the MCP bridge, stdin) * stays on localhost.
( request: ContainerRunRequest, resolveAdapter: (input: ResolveAdapterInput) => AnyTextAdapter, )
| 128 | * stays on localhost. |
| 129 | */ |
| 130 | function runAgent( |
| 131 | request: ContainerRunRequest, |
| 132 | resolveAdapter: (input: ResolveAdapterInput) => AnyTextAdapter, |
| 133 | ): AsyncIterable<StreamChunk> { |
| 134 | const sandbox = defineSandbox({ |
| 135 | // The container IS the host: no isolation, just run on its own filesystem. |
| 136 | id: 'colocated-in-container', |
| 137 | provider: localProcessSandbox(), |
| 138 | // Honor the app's workspace (source / setup / skills / …), with the secrets |
| 139 | // re-resolved from the container env. |
| 140 | workspace: reconstituteWorkspace(request.workspace), |
| 141 | }) |
| 142 | |
| 143 | // `stream: true` (no outputSchema) makes chat() return AsyncIterable<StreamChunk>. |
| 144 | return chat({ |
| 145 | threadId: request.threadId, |
| 146 | adapter: resolveAdapter({ |
| 147 | harness: request.harness, |
| 148 | model: request.model, |
| 149 | }), |
| 150 | messages: request.messages, |
| 151 | stream: true, |
| 152 | // Rebuild the DO's host tools as stubs whose execute() POSTs back to the DO. |
| 153 | // The adapter bridges them over the in-container localhost MCP transport. |
| 154 | tools: remoteToolStubs( |
| 155 | request.toolDescriptors, |
| 156 | httpRemoteToolExecutor(request.toolExecUrl, request.toolExecToken), |
| 157 | ), |
| 158 | // Provide the in-container local-process sandbox handle the adapter needs. |
| 159 | middleware: [withSandbox(sandbox)], |
| 160 | }) |
| 161 | } |
| 162 | |
| 163 | /** Stream the agent's chunks to the response as NDJSON, one object per line. */ |
| 164 | async function handleRun( |
no test coverage detected