edgeone 1.6.21 → 1.6.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
-
import hashlib
|
|
7
6
|
import importlib
|
|
8
7
|
import json
|
|
9
8
|
import os
|
|
@@ -11,7 +10,6 @@ import re
|
|
|
11
10
|
import sys
|
|
12
11
|
from typing import Any, Callable
|
|
13
12
|
from urllib.parse import parse_qs
|
|
14
|
-
import httpx
|
|
15
13
|
|
|
16
14
|
# --- Observability bootstrap (must run before user code imports) ---
|
|
17
15
|
# Reads entry names from AGENT_OBSERVABILITY_ENTRIES env var (set by main.py
|
|
@@ -128,71 +126,6 @@ def _is_interrupt_exception(err: BaseException) -> bool:
|
|
|
128
126
|
return True
|
|
129
127
|
return False
|
|
130
128
|
|
|
131
|
-
# --- Proxy transport for credential requests ---
|
|
132
|
-
|
|
133
|
-
_PROXY_UUID = "{{PAGES_PROXY_UUID}}"
|
|
134
|
-
_PROXY_HOST = "{{PAGES_PROXY_HOST}}"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def _is_proxy_enabled() -> bool:
|
|
138
|
-
"""Check if proxy placeholders have been replaced with real values."""
|
|
139
|
-
return (
|
|
140
|
-
not _PROXY_UUID.startswith("{{")
|
|
141
|
-
and not _PROXY_HOST.startswith("{{")
|
|
142
|
-
and bool(_PROXY_UUID)
|
|
143
|
-
and bool(_PROXY_HOST)
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
class _ProxyTransport(httpx.AsyncBaseTransport):
|
|
148
|
-
"""Rewrites requests to go through the EdgeOne proxy with signing headers.
|
|
149
|
-
|
|
150
|
-
Signature algorithm matches Node fetch-proxy.js:
|
|
151
|
-
sign = md5(timestamp + '-' + pathname + '-' + uuid)
|
|
152
|
-
"""
|
|
153
|
-
|
|
154
|
-
def __init__(self) -> None:
|
|
155
|
-
self._inner = httpx.AsyncHTTPTransport()
|
|
156
|
-
|
|
157
|
-
async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
|
|
158
|
-
original_url = request.url
|
|
159
|
-
pathname = original_url.raw_path.decode("ascii").split("?")[0]
|
|
160
|
-
timestamp = str(int(__import__("time").time() * 1000))
|
|
161
|
-
sign = hashlib.md5(
|
|
162
|
-
f"{timestamp}-{pathname}-{_PROXY_UUID}".encode()
|
|
163
|
-
).hexdigest()
|
|
164
|
-
|
|
165
|
-
# Rewrite URL to proxy host, preserving path and query
|
|
166
|
-
proxy_url = original_url.copy_with(
|
|
167
|
-
host=_PROXY_HOST.replace("https://", "").replace("http://", ""),
|
|
168
|
-
scheme="https",
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
# Add signing headers
|
|
172
|
-
request.headers["oe-host"] = str(original_url.host)
|
|
173
|
-
request.headers["oe-timestamp"] = timestamp
|
|
174
|
-
request.headers["oe-sign"] = sign
|
|
175
|
-
|
|
176
|
-
# Build new request targeting proxy
|
|
177
|
-
proxy_request = httpx.Request(
|
|
178
|
-
method=request.method,
|
|
179
|
-
url=proxy_url,
|
|
180
|
-
headers=request.headers,
|
|
181
|
-
content=request.content,
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
return await self._inner.handle_async_request(proxy_request)
|
|
185
|
-
|
|
186
|
-
async def aclose(self) -> None:
|
|
187
|
-
await self._inner.aclose()
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def _build_proxy_client() -> httpx.AsyncClient | None:
|
|
191
|
-
"""Build an httpx.AsyncClient with proxy transport, or None if proxy is not configured."""
|
|
192
|
-
if not _is_proxy_enabled():
|
|
193
|
-
return None
|
|
194
|
-
return httpx.AsyncClient(transport=_ProxyTransport(), timeout=30.0)
|
|
195
|
-
|
|
196
129
|
# --- Cold start ---
|
|
197
130
|
try:
|
|
198
131
|
_route_table_raw = json.loads(os.environ.get("AGENT_ROUTE_TABLE", "{}"))
|
|
@@ -262,13 +195,6 @@ def _create_store_resolver() -> Callable[[str], Any]:
|
|
|
262
195
|
print(f"[agent-python] pages-blob not available: {type(_blob_import_err).__name__}: {_blob_import_err}", file=sys.stderr, flush=True)
|
|
263
196
|
print("[agent-python] using InMemoryStore", file=sys.stderr, flush=True)
|
|
264
197
|
|
|
265
|
-
# Build proxy client for credential requests (only in prod when placeholders are replaced)
|
|
266
|
-
_proxy_client = _build_proxy_client()
|
|
267
|
-
if _proxy_client is not None:
|
|
268
|
-
print("[agent-python] Proxy enabled for credential requests", file=sys.stderr, flush=True)
|
|
269
|
-
else:
|
|
270
|
-
print("[agent-python] Proxy not configured, using direct connections", file=sys.stderr, flush=True)
|
|
271
|
-
|
|
272
198
|
def resolver(route_path: str) -> Any:
|
|
273
199
|
cache_key = str(route_path or "/")
|
|
274
200
|
if cache_key in cache:
|
|
@@ -287,7 +213,7 @@ def _create_store_resolver() -> Callable[[str], Any]:
|
|
|
287
213
|
if _get_store is not None:
|
|
288
214
|
try:
|
|
289
215
|
_project_id = os.environ.get("PAGES_PROJECT_ID", "") or None
|
|
290
|
-
blob_store = _get_store(store_name, project_id=_project_id, token=_dev_credential or None, consistency="strong"
|
|
216
|
+
blob_store = _get_store(store_name, project_id=_project_id, token=_dev_credential or None, consistency="strong") if (_dev_credential and _project_id) else _get_store(store_name, consistency="strong")
|
|
291
217
|
store = BlobBackedStore(blob_store)
|
|
292
218
|
except Exception as e:
|
|
293
219
|
print(f"[agent-python] WARNING: Failed to create blob store for {cache_key}: {e}, falling back to InMemoryStore", file=sys.stderr, flush=True)
|
|
@@ -418,13 +344,12 @@ def _create_store_blob() -> Any:
|
|
|
418
344
|
|
|
419
345
|
try:
|
|
420
346
|
from pages_blob import get_store as _get_store_fn
|
|
421
|
-
proxy_client = _build_proxy_client()
|
|
422
347
|
_mem_project_id = os.environ.get("PAGES_PROJECT_ID", "") or None
|
|
423
348
|
_mem_token = os.environ.get("PAGES_BLOB_DEPLOY_CREDENTIAL", "") or None
|
|
424
349
|
if _mem_token and _mem_project_id:
|
|
425
|
-
blob_store = _get_store_fn(store_name, project_id=_mem_project_id, token=_mem_token, consistency="strong"
|
|
350
|
+
blob_store = _get_store_fn(store_name, project_id=_mem_project_id, token=_mem_token, consistency="strong")
|
|
426
351
|
else:
|
|
427
|
-
blob_store = _get_store_fn(store_name, consistency="strong"
|
|
352
|
+
blob_store = _get_store_fn(store_name, consistency="strong")
|
|
428
353
|
print(
|
|
429
354
|
f"[agent-python] Conversation store: blob-backed → {store_name}",
|
|
430
355
|
file=sys.stderr, flush=True,
|