diff --git a/docker/runtime/Dockerfile b/docker/runtime/Dockerfile index 34bcc9e..0393865 100644 --- a/docker/runtime/Dockerfile +++ b/docker/runtime/Dockerfile @@ -40,7 +40,7 @@ ENV LIBCLANG_PATH=/usr/lib/llvm-14/lib \ CARGO_INCREMENTAL=0 \ CARGO_NET_GIT_FETCH_WITH_CLI=true -# Build OpenSSL for musl target +# Build OpenSSL for musl target (amd64 only - arm64 uses rustls) ENV SSL_VER=1.1.1w RUN if [ "$TARGETARCH" = "amd64" ]; then \ export PATH="/opt/x86_64-unknown-linux-musl/bin:$PATH" && \ @@ -52,18 +52,9 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \ make install_sw && \ cd .. && \ rm -rf openssl-$SSL_VER*; \ - elif [ "$TARGETARCH" = "arm64" ]; then \ - wget https://www.openssl.org/source/openssl-$SSL_VER.tar.gz && \ - tar -xzf openssl-$SSL_VER.tar.gz && \ - cd openssl-$SSL_VER && \ - CC="musl-gcc -static" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-generic64 && \ - make -j$(nproc) CC="musl-gcc -static" && \ - make install_sw && \ - cd .. && \ - rm -rf openssl-$SSL_VER*; \ fi -# Set OpenSSL environment variables +# Set OpenSSL environment variables (only used on amd64) ENV OPENSSL_DIR=/musl \ OPENSSL_INCLUDE_DIR=/musl/include \ OPENSSL_LIB_DIR=/musl/lib \ diff --git a/examples/shared/src/sandbox-agent-client.ts b/examples/shared/src/sandbox-agent-client.ts index d23a45d..55c168d 100644 --- a/examples/shared/src/sandbox-agent-client.ts +++ b/examples/shared/src/sandbox-agent-client.ts @@ -238,11 +238,14 @@ export async function sendMessageStream({ try { const event = JSON.parse(data); - // Handle text deltas - if (event.type === "item.delta" && event.data?.delta?.type === "text") { - const text = event.data.delta.text || ""; - fullText += text; - onText?.(text); + // Handle text deltas (delta can be a string or an object with type: "text") + if (event.type === "item.delta" && event.data?.delta) { + const delta = event.data.delta; + const text = typeof delta === "string" ? delta : delta.type === "text" ? delta.text || "" : ""; + if (text) { + fullText += text; + onText?.(text); + } } // Handle completed assistant message @@ -276,25 +279,71 @@ export async function runPrompt({ extraHeaders?: Record; agentId?: string; }): Promise { + const normalized = normalizeBaseUrl(baseUrl); const sessionId = await createSession({ baseUrl, token, extraHeaders, agentId }); console.log(`Session ${sessionId} ready. Press Ctrl+C to quit.`); - const rl = createInterface({ input: process.stdin, output: process.stdout }); + // Connect to SSE event stream + const headers = buildHeaders({ token, extraHeaders }); + const sseResponse = await fetch(`${normalized}/v1/sessions/${sessionId}/events/sse`, { headers }); + if (!sseResponse.ok || !sseResponse.body) { + throw new Error(`Failed to connect to SSE: ${sseResponse.status}`); + } + const reader = sseResponse.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ""; + let lastSeq = 0; + + // Process SSE events in background + const processEvents = async () => { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split("\n"); + buffer = lines.pop() || ""; + + for (const line of lines) { + if (!line.startsWith("data: ")) continue; + const data = line.slice(6); + if (data === "[DONE]") continue; + + try { + const event = JSON.parse(data); + if (event.sequence <= lastSeq) continue; + lastSeq = event.sequence; + + // Print text deltas + if (event.type === "item.delta" && event.data?.delta) { + const delta = event.data.delta; + const text = typeof delta === "string" ? delta : delta.type === "text" ? delta.text || "" : ""; + if (text) process.stdout.write(text); + } + + // Print newline after completed assistant message + if (event.type === "item.completed" && event.data?.item?.role === "assistant") { + process.stdout.write("\n> "); + } + } catch {} + } + } + }; + processEvents().catch(() => {}); + + // Read user input and post messages + const rl = createInterface({ input: process.stdin, output: process.stdout }); while (true) { const line = await rl.question("> "); if (!line.trim()) continue; try { - await sendMessageStream({ - baseUrl, - token, - extraHeaders, - sessionId, - message: line.trim(), - onText: (text) => process.stdout.write(text), + await fetch(`${normalized}/v1/sessions/${sessionId}/messages`, { + method: "POST", + headers: buildHeaders({ token, extraHeaders, contentType: true }), + body: JSON.stringify({ message: line.trim() }), }); - process.stdout.write("\n"); } catch (error) { console.error(error instanceof Error ? error.message : error); }