-
Notifications
You must be signed in to change notification settings - Fork 3.1k
feat: multi-agent architecture with Hermes support #1618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
a08e0a5
feat(agents): add Hermes Agent support scaffolding and agent-definiti…
ericksoa 621ea4a
fix(hermes): fix config generation, gateway startup, and HERMES_HOME …
ericksoa c1e70e0
fix(hermes): socat forwarder for 0.0.0.0 bind and capsh compatibility
ericksoa 3f1e473
feat(onboard): wire agent selection into onboarding flow
ericksoa 432c85b
fix(onboard): auto-build agent base image during sandbox creation
ericksoa 09a9e14
fix(onboard): replace hardcoded OpenClaw references with agent-aware …
ericksoa ac39bda
fix(hermes): make policy a complete valid policy file, not a fragment
ericksoa cd1401d
fix(cli): make connect, status, and recovery agent-aware
ericksoa 09d89a8
fix(dashboard): pass agent-aware port to buildControlUiUrls
ericksoa 52e0d54
fix(hermes): disable API server auth key for sandbox environment
ericksoa 53a440b
refactor(hermes): strip invented features, use Hermes defaults
ericksoa de70467
fix(types): add agent field to Session interface and fix JSDoc types
ericksoa 7e8b9e4
fix(onboard): remove API_SERVER_KEY reference from Hermes dashboard o…
ericksoa 76d0d49
fix(session): persist agent field through normalizeSession
ericksoa d60c35b
fix(hermes): add python-telegram-bot for Telegram messaging support
ericksoa 5fad12f
fix(hermes): add URL-decode proxy for OpenShell placeholder rewriting
ericksoa 4b09f4d
fix(hermes): disable TelegramFallbackTransport in sandbox
ericksoa be90d16
fix(hermes): fix telegram fallback transport patch to match actual so…
ericksoa 82a1efb
fix(hermes): move telegram patch before USER sandbox (permission fix)
ericksoa ab187c1
fix(hermes): make decode-proxy.py world-readable for sandbox user
ericksoa b41e673
fix(hermes): replace --chmod COPY flag with RUN chmod (no BuildKit)
ericksoa dd928e4
fix(hermes): move decode-proxy to /usr/local/bin (Landlock allows /usr)
ericksoa 5684681
fix(hermes): use python3.11 in binary policy (matches /proc/self/exe)
ericksoa c122800
Merge remote-tracking branch 'origin/main' into feat/hermes-agent-sup…
ericksoa 01454c1
test(e2e): add Hermes Agent nightly E2E test
ericksoa 41d1f2c
fix(deps): add js-yaml to root dependencies
ericksoa 47d0a88
fix(blueprint): lower min_openshell_version to 0.0.24
ericksoa 264b17d
fix(e2e): fix session path and process check in Hermes E2E test
ericksoa 563d95d
fix(e2e): remove process check from Hermes E2E test
ericksoa 1f4b2f4
refactor(hermes): convert generate-config from Python to TypeScript
ericksoa dde4fc4
Merge branch 'main' into feat/hermes-agent-support
ericksoa 11f65ff
Merge branch 'main' into feat/hermes-agent-support
ericksoa 689dc3a
refactor(agents): extract agent logic into agent-onboard.js and agent…
ericksoa 0451d56
fix(agents): persist agent name to session when resolved via --agent …
ericksoa 6bda33b
fix(agents): address CodeRabbit review findings on PR #1618
ericksoa ad6ef06
Merge branch 'main' into feat/hermes-agent-support
ericksoa 30a5c17
fix(agents): resolve agent from per-sandbox registry, not global session
ericksoa b19437d
Merge branch 'feat/hermes-agent-support' of https://github.com/NVIDIA…
ericksoa 6fcf315
fix(onboard): remove interactive agent selection prompt
ericksoa 6a73f9c
merge: resolve conflicts with main after TS migration
ericksoa c5b21d3
Merge branch 'main' into feat/hermes-agent-support
cv f842c7b
Merge branch 'main' into feat/hermes-agent-support
ericksoa e06b7c7
feat(policy): add --dangerously-skip-permissions flag for permissive …
ericksoa 9946816
Merge remote-tracking branch 'origin/main' into feat/hermes-agent-sup…
ericksoa a4cd8ce
Merge branch 'feat/hermes-agent-support' of https://github.com/NVIDIA…
ericksoa e24b3cf
Revert "feat(policy): add --dangerously-skip-permissions flag for per…
ericksoa 849a97a
merge: resolve conflicts with main for agent + dangerouslySkipPermiss…
ericksoa 5c82a2a
refactor(agents): migrate agent modules to TypeScript with shims
ericksoa 88b665a
fix(hermes): harden Dockerfile and tighten E2E session check
ericksoa 659a618
fix(security): quote shell-interpolated URLs and validate binary paths
ericksoa 924fe1b
fix(agents): fail onboarding when agent health probe times out
ericksoa 405c661
fix(policy): add missing preset hosts and persist dangerouslySkipPerm…
ericksoa e5e4930
fix(agents): use agent-specific port for dashboard forwarding
ericksoa a3e284f
feat(policy): per-agent permissive policies for dangerously-skip-perm…
ericksoa 886342a
fix(agents): use manifest timeout_seconds for health probe and bump H…
ericksoa 6b1683b
fix(agents): revert hard failure on health probe timeout
ericksoa acb1cdf
Merge branch 'main' into feat/hermes-agent-support
ericksoa d1f6f6b
fix(policy): remove Hermes-specific entries from global permissive po…
ericksoa 3d7b2f2
Merge remote-tracking branch 'origin/feat/hermes-agent-support' into …
ericksoa 4e9715b
fix(cli): hide undocumented flags from help and error output
ericksoa 2db110e
Merge branch 'main' into feat/hermes-agent-support
ericksoa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Hermes sandbox image — Hermes Agent + NemoClaw plugin inside OpenShell | ||
| # | ||
| # Layers PR-specific code (plugin, config, startup script) on top of the | ||
| # pre-built Hermes base image. Mirrors the OpenClaw Dockerfile structure. | ||
|
|
||
| ARG BASE_IMAGE=ghcr.io/nvidia/nemoclaw/hermes-sandbox-base:latest | ||
|
|
||
| FROM ${BASE_IMAGE} | ||
|
|
||
| # Harden: remove unnecessary build tools and network probes | ||
| RUN (apt-get remove --purge -y gcc gcc-12 g++ g++-12 cpp cpp-12 make \ | ||
| netcat-openbsd netcat-traditional ncat 2>/dev/null || true) \ | ||
| && apt-get autoremove --purge -y \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Patch: disable Hermes's TelegramFallbackTransport inside the sandbox. | ||
| # The fallback transport rewrites api.telegram.org to raw IPs, which | ||
| # OpenShell's L7 proxy rejects (hostname-based policy). Without it, | ||
| # python-telegram-bot uses default httpx transport which respects | ||
| # HTTPS_PROXY and routes through the proxy correctly. | ||
| # Must run as root before USER sandbox. | ||
| # Replace _fallback_ips method to always return empty list, which | ||
| # skips the entire fallback transport code path. | ||
| RUN python3 -c "\ | ||
| import pathlib, re; \ | ||
| p = pathlib.Path('/usr/local/lib/python3.11/dist-packages/gateway/platforms/telegram.py'); \ | ||
| src = p.read_text(); \ | ||
| patched = src.replace( \ | ||
| 'fallback_ips = self._fallback_ips()', \ | ||
| 'fallback_ips = [] # NemoClaw: disabled for sandbox proxy compatibility'); \ | ||
| patched = patched.replace( \ | ||
| 'if not fallback_ips:', \ | ||
| 'if False: # NemoClaw: skip fallback discovery'); \ | ||
| assert 'NemoClaw: disabled' in patched, 'Patch failed: _fallback_ips line not found'; \ | ||
| p.write_text(patched); \ | ||
| print('[patch] Disabled TelegramFallbackTransport for sandbox proxy compatibility')" | ||
|
|
||
| # Copy NemoClaw plugin for Hermes (Python-based) | ||
| COPY agents/hermes/plugin/ /opt/nemoclaw-hermes-plugin/ | ||
|
|
||
| # Copy config generation script and URL-decode proxy | ||
| COPY agents/hermes/generate-config.ts /opt/nemoclaw-generate-config.ts | ||
| COPY agents/hermes/decode-proxy.py /usr/local/bin/nemoclaw-decode-proxy | ||
| RUN chmod 755 /usr/local/bin/nemoclaw-decode-proxy | ||
|
|
||
| # Copy blueprint (shared infrastructure) | ||
| COPY nemoclaw-blueprint/ /opt/nemoclaw-blueprint/ | ||
|
|
||
| # Copy startup script | ||
| COPY agents/hermes/start.sh /usr/local/bin/nemoclaw-start | ||
| RUN chmod 755 /usr/local/bin/nemoclaw-start | ||
|
|
||
| # Build args for config that varies per deployment. | ||
| ARG NEMOCLAW_MODEL=nvidia/nemotron-3-super-120b-a12b | ||
| ARG NEMOCLAW_PROVIDER_KEY=custom | ||
| ARG NEMOCLAW_INFERENCE_BASE_URL=https://inference.local/v1 | ||
| ARG CHAT_UI_URL=http://127.0.0.1:8642 | ||
| ARG NEMOCLAW_MESSAGING_CHANNELS_B64=W10= | ||
| ARG NEMOCLAW_MESSAGING_ALLOWED_IDS_B64=e30= | ||
| ARG NEMOCLAW_BUILD_ID=default | ||
|
|
||
| # Promote build-args to env vars for the config generation script. | ||
| ENV NEMOCLAW_MODEL=${NEMOCLAW_MODEL} \ | ||
| NEMOCLAW_PROVIDER_KEY=${NEMOCLAW_PROVIDER_KEY} \ | ||
| NEMOCLAW_INFERENCE_BASE_URL=${NEMOCLAW_INFERENCE_BASE_URL} \ | ||
| CHAT_UI_URL=${CHAT_UI_URL} \ | ||
| NEMOCLAW_MESSAGING_CHANNELS_B64=${NEMOCLAW_MESSAGING_CHANNELS_B64} \ | ||
| NEMOCLAW_MESSAGING_ALLOWED_IDS_B64=${NEMOCLAW_MESSAGING_ALLOWED_IDS_B64} | ||
|
|
||
| WORKDIR /sandbox | ||
| USER sandbox | ||
|
|
||
| # Set up blueprint for local resolution | ||
| RUN mkdir -p /sandbox/.nemoclaw/blueprints/0.1.0 \ | ||
| && cp -r /opt/nemoclaw-blueprint/* /sandbox/.nemoclaw/blueprints/0.1.0/ | ||
|
|
||
| # Generate Hermes config.yaml and .env from build args. | ||
| # config.yaml is immutable at runtime (Landlock read-only on /sandbox/.hermes). | ||
| # .env holds API key placeholders for OpenShell provider pipeline. | ||
| # SECURITY: Uses a separate script file instead of inline code to avoid | ||
| # code injection via build-arg interpolation (same concern as OpenClaw C-2). | ||
| RUN node --experimental-strip-types /opt/nemoclaw-generate-config.ts | ||
|
|
||
| # Install NemoClaw plugin into Hermes | ||
| RUN mkdir -p /sandbox/.hermes-data/plugins/nemoclaw \ | ||
| && cp -r /opt/nemoclaw-hermes-plugin/* /sandbox/.hermes-data/plugins/nemoclaw/ | ||
|
|
||
| # Lock .hermes via DAC: chown to root so sandbox user cannot modify config. | ||
| # Same pattern as OpenClaw — Landlock provides defense-in-depth. | ||
| # hadolint ignore=DL3002 | ||
| USER root | ||
| RUN chown root:root /sandbox/.hermes \ | ||
| && rm -rf /root/.cache/pip /sandbox/.cache \ | ||
| && find /sandbox/.hermes -mindepth 1 -maxdepth 1 -exec chown -h root:root {} + \ | ||
| && chmod 755 /sandbox/.hermes \ | ||
| && chmod 444 /sandbox/.hermes/config.yaml \ | ||
| && chmod 444 /sandbox/.hermes/.env | ||
|
|
||
| # Pin config hash at build time for integrity verification at startup. | ||
| RUN sha256sum /sandbox/.hermes/config.yaml /sandbox/.hermes/.env \ | ||
| > /sandbox/.hermes/.config-hash \ | ||
| && chmod 444 /sandbox/.hermes/.config-hash \ | ||
| && chown root:root /sandbox/.hermes/.config-hash | ||
|
|
||
| # start.sh handles privilege separation: runs as root initially to perform | ||
| # symlink validation and hardening, then drops to 'gateway' user via gosu | ||
| # for the agent process. See the root-path branch in start.sh. | ||
| ENTRYPOINT ["/usr/local/bin/nemoclaw-start"] | ||
| CMD ["/bin/bash"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Hermes sandbox base image — expensive, rarely-changing layers. | ||
| # | ||
| # Contains: node:22-slim (OpenShell needs Node), apt packages, gosu, | ||
| # user/group setup, .hermes directory structure, Hermes CLI, and PyYAML. | ||
| # | ||
| # Mirrors the OpenClaw Dockerfile.base structure but installs Hermes | ||
| # (Python-based) instead of OpenClaw (Node-based). | ||
| # | ||
| # ── When to rebuild ───────────────────────────────────────────── | ||
| # 1. Hermes version bump — change the HERMES_VERSION below | ||
| # 2. New apt package needed — add it to the apt-get install list | ||
| # 3. gosu upgrade — update URL, checksum, and version | ||
| # 4. node:22-slim digest rot — update-docker-pin.sh updates both | ||
| # 5. New .hermes subdirectory — add mkdir + symlink below | ||
| # ──────────────────────────────────────────────────────────────── | ||
|
|
||
| FROM node:22-slim@sha256:4f77a690f2f8946ab16fe1e791a3ac0667ae1c3575c3e4d0d4589e9ed5bfaf3d | ||
|
|
||
| ENV DEBIAN_FRONTEND=noninteractive | ||
|
|
||
| # Hermes version pinned for reproducibility. | ||
| # Calver tag v2026.4.8 = semver 0.8.0. | ||
| ARG HERMES_VERSION=v2026.4.8 | ||
|
|
||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| python3=3.11.2-1+b1 \ | ||
| python3-pip=23.0.1+dfsg-1 \ | ||
| python3-venv=3.11.2-1+b1 \ | ||
| curl=7.88.1-10+deb12u14 \ | ||
| git=1:2.39.5-0+deb12u3 \ | ||
| ca-certificates=20230311+deb12u1 \ | ||
| iproute2=6.1.0-3 \ | ||
| iptables=1.8.9-2 \ | ||
| libcap2-bin=1:2.66-4+deb12u2+b2 \ | ||
| socat=1.7.4.4-2 \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # gosu for privilege separation (gateway vs sandbox user). | ||
| # Identical to OpenClaw base — pinned to 1.19 with checksum. | ||
| # hadolint ignore=DL4006 | ||
| RUN arch="$(dpkg --print-architecture)" \ | ||
| && case "$arch" in \ | ||
| amd64) gosu_asset="gosu-amd64"; gosu_sha256="52c8749d0142edd234e9d6bd5237dff2d81e71f43537e2f4f66f75dd4b243dd0" ;; \ | ||
| arm64) gosu_asset="gosu-arm64"; gosu_sha256="3a8ef022d82c0bc4a98bcb144e77da714c25fcfa64dccc57f6aba7ae47ff1a44" ;; \ | ||
| *) echo "Unsupported architecture for gosu: $arch" >&2; exit 1 ;; \ | ||
| esac \ | ||
| && curl -fsSL -o /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.19/${gosu_asset}" \ | ||
| && echo "${gosu_sha256} /usr/local/bin/gosu" | sha256sum -c - \ | ||
| && chmod +x /usr/local/bin/gosu \ | ||
| && gosu --version | ||
|
|
||
| # Create sandbox user (matches OpenShell convention) and gateway user. | ||
| # Same UID/GID layout as OpenClaw — OpenShell expects these names. | ||
| RUN groupadd -r gateway && useradd -r -g gateway -d /sandbox -s /usr/sbin/nologin gateway \ | ||
| && groupadd -r sandbox && useradd -r -g sandbox -d /sandbox -s /bin/bash sandbox \ | ||
| && mkdir -p /sandbox/.nemoclaw \ | ||
| && chown -R sandbox:sandbox /sandbox | ||
|
|
||
| # Split .hermes into immutable config dir + writable state dir. | ||
| # Same pattern as OpenClaw: Landlock makes /sandbox/.hermes read-only, | ||
| # writable state lives in .hermes-data, reached via symlinks. | ||
| RUN mkdir -p /sandbox/.hermes-data/memories \ | ||
| /sandbox/.hermes-data/sessions \ | ||
| /sandbox/.hermes-data/skills \ | ||
| /sandbox/.hermes-data/plugins \ | ||
| /sandbox/.hermes-data/cron \ | ||
| /sandbox/.hermes-data/logs \ | ||
| /sandbox/.hermes-data/skins \ | ||
| /sandbox/.hermes-data/plans \ | ||
| /sandbox/.hermes-data/workspace \ | ||
| /sandbox/.hermes-data/profiles \ | ||
| /sandbox/.hermes-data/cache \ | ||
| /sandbox/.hermes-data/pairing \ | ||
| && mkdir -p /sandbox/.hermes \ | ||
| && ln -s /sandbox/.hermes-data/memories /sandbox/.hermes/memories \ | ||
| && ln -s /sandbox/.hermes-data/sessions /sandbox/.hermes/sessions \ | ||
| && ln -s /sandbox/.hermes-data/skills /sandbox/.hermes/skills \ | ||
| && ln -s /sandbox/.hermes-data/plugins /sandbox/.hermes/plugins \ | ||
| && ln -s /sandbox/.hermes-data/cron /sandbox/.hermes/cron \ | ||
| && ln -s /sandbox/.hermes-data/logs /sandbox/.hermes/logs \ | ||
| && ln -s /sandbox/.hermes-data/skins /sandbox/.hermes/skins \ | ||
| && ln -s /sandbox/.hermes-data/plans /sandbox/.hermes/plans \ | ||
| && ln -s /sandbox/.hermes-data/workspace /sandbox/.hermes/workspace \ | ||
| && ln -s /sandbox/.hermes-data/profiles /sandbox/.hermes/profiles \ | ||
| && ln -s /sandbox/.hermes-data/cache /sandbox/.hermes/cache \ | ||
| && ln -s /sandbox/.hermes-data/pairing /sandbox/.hermes/pairing \ | ||
| && chown -R sandbox:sandbox /sandbox/.hermes /sandbox/.hermes-data | ||
|
|
||
| # Install Hermes Agent from GitHub release. | ||
| # Hermes is not on PyPI — official install is via their install script or | ||
| # direct pip install from the release tarball. | ||
| # hadolint ignore=DL3013 | ||
| RUN pip3 install --no-cache-dir --break-system-packages \ | ||
| "hermes-agent @ https://github.com/NousResearch/hermes-agent/archive/refs/tags/${HERMES_VERSION}.tar.gz" \ | ||
| "pyyaml==6.0.3" \ | ||
| "python-telegram-bot>=21.0" \ | ||
| && hermes --version |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| #!/usr/bin/env python3 | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| """ | ||
| URL-decoding HTTP proxy for OpenShell placeholder rewriting. | ||
|
|
||
| Python HTTP clients (httpx) URL-encode colons in URL paths, turning | ||
| openshell:resolve:env:TOKEN into openshell%3Aresolve%3Aenv%3ATOKEN. | ||
| OpenShell's L7 proxy doesn't recognize the encoded form. | ||
|
|
||
| This proxy sits between the Python process and the OpenShell proxy, | ||
| URL-decodes the CONNECT target and request paths so the placeholders | ||
| are restored before reaching the L7 proxy. | ||
|
|
||
| Usage: Launched by start.sh, listens on 127.0.0.1:3129. | ||
| HTTPS_PROXY=http://127.0.0.1:3129 hermes gateway run | ||
| """ | ||
|
|
||
| import asyncio | ||
| import sys | ||
| from urllib.parse import unquote | ||
|
|
||
|
|
||
| UPSTREAM_HOST = "10.200.0.1" | ||
| UPSTREAM_PORT = 3128 | ||
| LISTEN_HOST = "127.0.0.1" | ||
| LISTEN_PORT = 3129 | ||
|
|
||
|
|
||
| async def handle_client(reader, writer): | ||
| """Proxy a single connection, URL-decoding the initial request line.""" | ||
| up_writer = None | ||
| try: | ||
| first_line = await asyncio.wait_for(reader.readline(), timeout=10) | ||
| if not first_line: | ||
| writer.close() | ||
| return | ||
|
|
||
| # Decode only the request target (second token) so valid percent-encoding | ||
| # like %2F or %3F in the method/version is preserved. Only the path | ||
| # contains openshell%3Aresolve placeholders that need decoding. | ||
| parts = first_line.decode("utf-8", errors="replace").split(" ", 2) | ||
| if len(parts) == 3: | ||
| parts[1] = unquote(parts[1]) | ||
| decoded_line = " ".join(parts).encode("utf-8") | ||
|
|
||
| # Read remaining headers | ||
| headers = bytearray(decoded_line) | ||
| while True: | ||
| line = await asyncio.wait_for(reader.readline(), timeout=10) | ||
| headers.extend(line) | ||
| if line == b"\r\n" or line == b"\n" or not line: | ||
| break | ||
|
|
||
| # Connect to upstream proxy | ||
| up_reader, up_writer = await asyncio.open_connection( | ||
| UPSTREAM_HOST, UPSTREAM_PORT | ||
| ) | ||
| up_writer.write(bytes(headers)) | ||
| await up_writer.drain() | ||
|
|
||
| # Bidirectional relay | ||
| await asyncio.gather( | ||
| _relay(reader, up_writer), | ||
| _relay(up_reader, writer), | ||
| ) | ||
| except (asyncio.TimeoutError, ConnectionError, OSError): | ||
| pass | ||
| finally: | ||
| for w in (up_writer, writer): | ||
| if w is not None: | ||
| try: | ||
| w.close() | ||
| await w.wait_closed() | ||
| except (ConnectionError, OSError): | ||
| pass | ||
|
|
||
|
|
||
| async def _relay(src, dst): | ||
| """Copy data from src to dst until EOF.""" | ||
| try: | ||
| while True: | ||
| data = await src.read(65536) | ||
| if not data: | ||
| break | ||
| dst.write(data) | ||
| await dst.drain() | ||
| except (ConnectionError, OSError): | ||
| pass | ||
|
|
||
|
|
||
| async def main(): | ||
| server = await asyncio.start_server(handle_client, LISTEN_HOST, LISTEN_PORT) | ||
| print( | ||
| f"[decode-proxy] Listening on {LISTEN_HOST}:{LISTEN_PORT} -> {UPSTREAM_HOST}:{UPSTREAM_PORT}", | ||
| file=sys.stderr, | ||
| ) | ||
| async with server: | ||
| await server.serve_forever() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.run(main()) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.