fix(runtime+mcp): PLATFORM_URL defaults alignment + HTTP/SSE review fixes #12
@ -24,7 +24,7 @@ import httpx
|
||||
from builtin_tools.validation import WorkspaceIdValidationError, get_validated_workspace_id
|
||||
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "") # used for discover() headers only; URL uses validated version
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
|
||||
|
||||
async def discover(target_id: str) -> dict | None:
|
||||
|
||||
@ -16,7 +16,7 @@ from .platform_auth import auth_headers
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
|
||||
# Cache workspace ID → name mappings (populated by list_peers calls)
|
||||
_peer_names: dict[str, str] = {}
|
||||
|
||||
@ -14,7 +14,7 @@ the claude --print invocation.
|
||||
|
||||
Environment variables (set by the workspace container):
|
||||
WORKSPACE_ID — this workspace's ID
|
||||
PLATFORM_URL — platform API base URL (e.g. http://platform:8080)
|
||||
PLATFORM_URL — platform API base URL (default: http://host.docker.internal:8080)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@ -314,7 +314,7 @@ async def _handle_stdio():
|
||||
"result": {
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {"tools": {"listChanged": False}},
|
||||
"serverInfo": {"name": "a2a-delegation", "version": "1.0.0"},
|
||||
"serverInfo": {"name": "molecule", "version": "1.0.0"},
|
||||
},
|
||||
})
|
||||
|
||||
@ -361,15 +361,7 @@ _connection_queues: dict[str, asyncio.Queue] = {}
|
||||
_connection_lock = asyncio.Lock()
|
||||
|
||||
|
||||
async def _sse_broadcaster(request_id: str, response: dict, conn_id: str):
|
||||
"""Send a JSON-RPC response to a specific SSE connection."""
|
||||
async with _connection_lock:
|
||||
queue = _connection_queues.get(conn_id)
|
||||
if queue is not None:
|
||||
await queue.put(response)
|
||||
|
||||
|
||||
async def _handle_http_mcp(request) -> dict:
|
||||
async def _handle_http_mcp(request) -> dict | None:
|
||||
"""Handle an incoming JSON-RPC request over HTTP. Returns the JSON-RPC response."""
|
||||
try:
|
||||
body = await request.json()
|
||||
@ -386,7 +378,7 @@ async def _handle_http_mcp(request) -> dict:
|
||||
"result": {
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {"tools": {"listChanged": False}},
|
||||
"serverInfo": {"name": "a2a-delegation", "version": "1.0.0"},
|
||||
"serverInfo": {"name": "molecule", "version": "1.0.0"},
|
||||
},
|
||||
}
|
||||
|
||||
@ -440,7 +432,7 @@ async def _run_http_server(port: int):
|
||||
|
||||
async def sse_handler(request):
|
||||
"""GET endpoint — SSE stream for push-based responses."""
|
||||
conn_id = str(uuid.uuid4())[:8]
|
||||
conn_id = str(uuid.uuid4()) # full UUID to avoid collision across connections
|
||||
queue: asyncio.Queue = asyncio.Queue(maxsize=100)
|
||||
|
||||
async with _connection_lock:
|
||||
@ -452,8 +444,9 @@ async def _run_http_server(port: int):
|
||||
while True:
|
||||
response = await asyncio.wait_for(queue.get(), timeout=300)
|
||||
yield f"event: message\ndata: {json.dumps(response)}\n\n"
|
||||
# Emit a heartbeat when the queue is drained (connection alive but idle)
|
||||
if queue.empty():
|
||||
yield "event: heartbeat\ndata: {}\n\n"
|
||||
yield "event: heartbeat\ndata: null\n\n"
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
finally:
|
||||
|
||||
@ -229,7 +229,7 @@ class BaseAdapter(ABC):
|
||||
from builtin_tools.memory import commit_memory, search_memory
|
||||
from builtin_tools.sandbox import run_code
|
||||
|
||||
platform_url = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
platform_url = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
|
||||
# Load plugins from per-workspace dir first, then shared fallback
|
||||
workspace_plugins_dir = os.path.join(config.config_path, "plugins")
|
||||
|
||||
@ -11,7 +11,7 @@ import httpx
|
||||
|
||||
from builtin_tools.validation import WorkspaceIdValidationError, get_validated_workspace_id
|
||||
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "") # used only for tracing headers; URLs use validated version
|
||||
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ RBAC denials emit an ``rbac / rbac.deny / denied`` event instead.
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
PLATFORM_URL Platform base URL (default: http://platform:8080)
|
||||
PLATFORM_URL Platform base URL (default: http://host.docker.internal:8080)
|
||||
WORKSPACE_ID This workspace's ID (validated at startup by platform_auth)
|
||||
APPROVAL_TIMEOUT Max wait in seconds (default: 300)
|
||||
APPROVAL_POLL_INTERVAL Polling interval in seconds (default: 5, polling path only)
|
||||
@ -55,7 +55,7 @@ from builtin_tools.validation import WorkspaceIdValidationError, get_validated_w
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
from molecule_runtime.platform_auth import WORKSPACE_ID
|
||||
APPROVAL_POLL_INTERVAL = float(os.environ.get("APPROVAL_POLL_INTERVAL", "5"))
|
||||
APPROVAL_TIMEOUT = float(os.environ.get("APPROVAL_TIMEOUT", "300"))
|
||||
|
||||
@ -30,7 +30,7 @@ from builtin_tools.telemetry import (
|
||||
inject_trace_headers,
|
||||
)
|
||||
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
from molecule_runtime.platform_auth import WORKSPACE_ID
|
||||
DELEGATION_RETRY_ATTEMPTS = int(os.environ.get("DELEGATION_RETRY_ATTEMPTS", "3"))
|
||||
DELEGATION_RETRY_DELAY = float(os.environ.get("DELEGATION_RETRY_DELAY", "5.0"))
|
||||
|
||||
@ -177,7 +177,7 @@ async def _notify_channels(
|
||||
Errors in individual channels are logged but never re-raised so that a
|
||||
misconfigured Slack webhook cannot block the approval flow.
|
||||
"""
|
||||
platform_url = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
platform_url = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
workspace_id = os.environ.get("WORKSPACE_ID", "")
|
||||
|
||||
for channel in cfg.channels:
|
||||
|
||||
@ -42,7 +42,7 @@ try: # pragma: no cover - optional runtime dependency in lightweight test envs
|
||||
except ImportError: # pragma: no cover
|
||||
httpx = SimpleNamespace(AsyncClient=None)
|
||||
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "")
|
||||
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ from .platform_auth import auth_headers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "")
|
||||
CONSOLIDATION_INTERVAL = float(os.environ.get("CONSOLIDATION_INTERVAL", "300")) # 5 min
|
||||
CONSOLIDATION_THRESHOLD = int(os.environ.get("CONSOLIDATION_THRESHOLD", "10")) # min memories before consolidating
|
||||
|
||||
@ -23,7 +23,7 @@ from policies.routing import build_team_routing_payload
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "")
|
||||
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ from transcript_auth import transcript_authorized as _transcript_authorized
|
||||
async def main(): # pragma: no cover
|
||||
workspace_id = os.environ.get("WORKSPACE_ID", "workspace-default")
|
||||
config_path = os.environ.get("WORKSPACE_CONFIG_PATH", "/configs")
|
||||
platform_url = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
platform_url = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
awareness_config = get_awareness_config()
|
||||
|
||||
# 0. Normalise LLM auth env vars based on token type.
|
||||
|
||||
@ -25,7 +25,7 @@ import httpx
|
||||
from builtin_tools.validation import WorkspaceIdValidationError, get_validated_workspace_id
|
||||
|
||||
WORKSPACE_ID = os.environ.get("WORKSPACE_ID", "")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://platform:8080")
|
||||
PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080")
|
||||
|
||||
|
||||
def set_status(task: str):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user