6.2 KiB
Profile Isolation / Download-Link Hardening — Closing Notes
Summary
This batch closes the remaining follow-up items after principal-scoped session, memory, and managed-download isolation landed.
The final scope completed here is:
- prevent live SSE streaming from briefly exposing host-local artifact paths such as
/Users/...orC:\... - carry
download_link_modeone layer higher so OpenWebUI-facing runs can request private vs public managed-download behavior - document a safe restart / recovery procedure for gateway + API server + OpenWebUI runs proxy
Landed repo changes
gateway/platforms/api_server.py
- added a streaming artifact rewrite guard for SSE output
- buffers split local-path prefixes until they can be rewritten safely
- rewrites completed local artifact references to managed-download links during streaming
- falls back to filename-only text if a buffered local path reaches stream end without a safe rewrite
- fixed the carry-buffer logic so normal assistant text is not delayed
- tightened path-prefix detection so
https://...is not misclassified as a Windows-style drive path
tests/gateway/test_api_server.py
- updated the managed-download helper expectation to match the tuple return shape
- verified ordinary streamed text still appears immediately
- verified
Nonetool-call sentinels do not break streaming - verified
/v1/responsesstreaming completed events carry rewritten managed-download URLs and hook metadata
tests/gateway/test_openwebui_runs_proxy_handoff.py
- added regression coverage for extracting
download_link_mode - added regression coverage ensuring owner metadata + link mode are passed into managed-download URL rewriting
docs/profile-isolation/*
- updated
README.mdread order - updated
implementation-status.mdto reflect the streaming rewrite fix and OpenWebUI proxy hook landing - added
restart-recovery-runbook.md - added this closing-notes file
Non-repo local changes
These changes are operational/local and are not part of the git repo:
/Users/hermes/.hermes/scripts/openwebui_runs_proxy.py
- now accepts
download_link_modefrom top-level request payload ormetadata.hermes.download_link_mode - forwards
download_link_modeupstream to the Hermes API server - rewrites local file paths using owner-aware managed-download mode instead of always minting public links
- appends a small note when private mode is used and the caller may want a future public link
~/Library/LaunchAgents/ai.hermes.gateway.plist
- removed
--replacefrom the steady-state LaunchAgent command line - this change only affects future reloads/restarts; it does not rewrite the currently running process until launchd reloads the job
Live rollout lesson captured for future debugging
launchctl kickstart -krestarted the already-loaded gateway job but did not apply the edited plist definition- the live gateway arguments stayed on
gateway run --replaceuntil the job definition was reloaded withlaunchctl bootout ...plist+launchctl bootstrap ...plist - after the controlled plist reload, gateway recovered health on try
13of a 1-second poll loop andlaunchctl printshowed live arguments updated to plaingateway run - the OpenWebUI runs proxy recovered on try
2of the same 1-second poll loop after its ownbootout + bootstrapreload
Verification performed
Verified successfully:
python3 -m py_compile \
gateway/platforms/api_server.py \
tests/gateway/test_api_server.py \
tests/gateway/test_session_api.py \
tests/gateway/test_openwebui_runs_proxy_handoff.py \
/Users/hermes/.hermes/scripts/openwebui_runs_proxy.py
pytest -q \
tests/gateway/test_api_server.py \
tests/gateway/test_session_api.py \
tests/gateway/test_openwebui_runs_proxy_handoff.py
Observed result:
221 passed, 5 warnings in 16.53s
Warnings were third-party deprecation warnings from pkg_resources under lark_oapi, not failures in the isolation changes.
Live runtime facts verified before restart
Observed from the live system during this session:
8642/healthwas healthy8653/healthwas healthy8646/line/webhook/healthwas healthy- the active gateway LaunchAgent runtime still showed
gateway run --replacebefore reload launchctl print gui/$(id -u)/ai.hermes.gatewayshowed repeated restarts (runs = 41,forks = 2400,last terminating signal = Killed: 9)
Interpretation:
- current service was up
- but the old long-lived launchd configuration had real flap risk and should not remain on
--replace
Restart recommendation
Use the runbook in restart-recovery-runbook.md.
Short version:
- ensure tests are green
- ensure
ai.hermes.gateway.plistno longer contains--replace - if the plist changed, reload gateway with
bootout + bootstrap(not onlykickstart -k) and wait for8642/health - if the proxy plist or launch context changed, reload OpenWebUI runs proxy with
bootout + bootstrapand wait for8653/health - re-check
8646/line/webhook/health - inspect
launchctl printto confirm gateway live arguments no longer include--replace - smoke-test streaming + managed-download rewrite immediately after restart
Known limitation in this chat session
Direct restart commands from this active agent session were blocked by safety guards because restarting the supervised gateway from inside the gateway tool context can create SIGTERM/self-respawn loops.
That blocker is expected behavior, not a code failure.
The correct way to perform the live restart is from an external shell / independent operator context. A background delegated verifier was dispatched to try the isolated-path verification separately.
Suggested PR / merge summary
Title:
fix: harden streaming artifact rewrite and propagate download_link_mode to runs proxy
Body bullets:
- prevent live SSE deltas from leaking host-local artifact paths before managed-download rewrite
- preserve ordinary streamed text and tool-call progress semantics
- propagate
download_link_modethrough the OpenWebUI runs proxy - add regression coverage for streaming rewrite behavior and proxy link-mode extraction
- document safe restart/recovery procedure and remove
--replacefrom the steady-state gateway LaunchAgent config