mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
refactor: 移除独立 hub/proxy/executor/gateway crate,统一为 gateway tunnel 架构
- 删除 aether-hub、aether-proxy 独立项目及其 Dockerfile/配置 - 删除 crates/aether-executor 和 crates/aether-gateway 全部模块 - 新增 apps/ 目录作为应用入口 - 将 hub 概念重构为 gateway tunnel transport - 将 executor 重构为 execution runtime - 新增 tunnel.rs 合约定义和 testkit tunnel/execution_runtime 模块 - 更新 Python 服务层和测试适配新架构命名
This commit is contained in:
@@ -9,14 +9,14 @@ import src.api.handlers.base.chat_sync_executor as chat_sync_mod
|
||||
from src.api.handlers.base.chat_sync_executor import ChatSyncExecutor
|
||||
from src.core.exceptions import EmbeddedErrorException
|
||||
from src.core.exceptions import ProviderNotAvailableException
|
||||
from src.services.request.executor_plan import (
|
||||
from src.services.request.execution_runtime_plan import (
|
||||
ExecutionPlan,
|
||||
ExecutionPlanBody,
|
||||
PreparedExecutionPlan,
|
||||
)
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -138,16 +138,16 @@ async def test_execute_sync_plan_uses_rust_executor_when_available(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.request_id == "req-test"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "chatcmpl-1"},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -172,17 +172,17 @@ async def test_execute_sync_plan_allows_supported_proxy_urls_for_rust(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.proxy is not None
|
||||
assert plan.proxy.url == "http://proxy.internal:8080"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "chatcmpl-proxy"},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -205,18 +205,18 @@ async def test_execute_sync_plan_allows_tunnel_delegate_for_rust(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.proxy is not None
|
||||
assert plan.proxy.mode == "tunnel"
|
||||
assert plan.proxy.node_id == "node-1"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "chatcmpl-tunnel"},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -239,16 +239,16 @@ async def test_execute_sync_plan_allows_tls_profile_for_rust(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.tls_profile == "claude_code_nodejs"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "chatcmpl-tls"},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -272,15 +272,15 @@ async def test_execute_sync_plan_applies_envelope_postprocessing_after_rust(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
return RustExecutorSyncResult(
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"payload": {"id": "wrapped-1", "message": "ok"}},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -330,16 +330,16 @@ async def test_execute_sync_plan_applies_format_conversion_after_rust(
|
||||
"source_id": response_json["provider_id"],
|
||||
}
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.provider_api_format == "gemini:chat"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"provider_id": "gemini-1"},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -389,16 +389,16 @@ async def test_execute_sync_plan_aggregates_upstream_stream_after_rust(
|
||||
assert request_id == "req-test"
|
||||
return SimpleNamespace(id="agg-1")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.stream is True
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_body_bytes=b"data: {\"id\":\"chunk-1\"}\n\ndata: [DONE]\n\n",
|
||||
headers={"content-type": "text/event-stream"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -432,16 +432,16 @@ async def test_execute_sync_plan_turns_rust_http_error_into_httpx_status_error(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.url.endswith("/chat/completions")
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=429,
|
||||
response_json={"error": {"message": "slow down"}},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -466,9 +466,9 @@ async def test_execute_sync_plan_preserves_embedded_error_semantics_from_rust(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.provider_api_format == "openai:chat"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={
|
||||
"error": {
|
||||
@@ -481,7 +481,7 @@ async def test_execute_sync_plan_preserves_embedded_error_semantics_from_rust(
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -506,12 +506,12 @@ async def test_execute_sync_plan_raises_when_rust_unavailable(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
assert plan.request_id == "req-test"
|
||||
raise RustExecutorClientError("executor down")
|
||||
raise ExecutionRuntimeClientError("executor down")
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -541,12 +541,12 @@ async def test_execute_sync_plan_raises_when_remote_contract_is_ineligible(
|
||||
|
||||
monkeypatch.setattr(chat_sync_mod.config, "executor_backend", "rust")
|
||||
|
||||
async def _should_not_call_rust(self: object, plan: ExecutionPlan) -> RustExecutorSyncResult:
|
||||
async def _should_not_call_rust(self: object, plan: ExecutionPlan) -> ExecutionRuntimeSyncResult:
|
||||
del self, plan
|
||||
raise AssertionError("rust executor should not be called")
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat_sync_mod.RustExecutorClient,
|
||||
chat_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_should_not_call_rust,
|
||||
)
|
||||
|
||||
@@ -12,9 +12,9 @@ import src.services.proxy_node.resolver as proxymod
|
||||
from src.api.handlers.base.chat_handler_base import ChatHandlerBase
|
||||
from src.api.handlers.base.stream_context import StreamContext
|
||||
from src.core.exceptions import ProviderNotAvailableException
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorStreamResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeStreamResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -265,9 +265,9 @@ async def test_execute_stream_request_uses_rust_executor_when_available(
|
||||
|
||||
dummy_ctx = _DummyStreamResponseCtx()
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "stream") is True
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "text/event-stream", "x-upstream-test": "true"},
|
||||
byte_iterator=_iter_chunks(
|
||||
@@ -279,7 +279,7 @@ async def test_execute_stream_request_uses_rust_executor_when_available(
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
stream = await handler._execute_stream_request(
|
||||
ctx,
|
||||
@@ -359,7 +359,7 @@ async def test_execute_stream_request_uses_rust_sync_executor_for_non_stream_ups
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
async def _should_not_call_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _should_not_call_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
del self, plan
|
||||
raise AssertionError("stream executor should not be used")
|
||||
|
||||
@@ -378,8 +378,8 @@ async def test_execute_stream_request_uses_rust_sync_executor_for_non_stream_ups
|
||||
lambda internal_resp: [{"kind": "chunk"}],
|
||||
)
|
||||
monkeypatch.setattr(chatmod, "get_parser_for_format", lambda _format: _FakeParser())
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _should_not_call_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _should_not_call_stream)
|
||||
monkeypatch.setattr(
|
||||
"src.clients.http_client.HTTPClientPool.get_upstream_client",
|
||||
_should_not_get_http_client,
|
||||
@@ -432,9 +432,9 @@ async def test_execute_stream_request_accepts_async_generator_stream_processor(
|
||||
|
||||
dummy_ctx = _DummyStreamResponseCtx()
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "stream") is True
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "text/event-stream"},
|
||||
byte_iterator=_iter_chunks(
|
||||
@@ -446,7 +446,7 @@ async def test_execute_stream_request_accepts_async_generator_stream_processor(
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
stream = await handler._execute_stream_request(
|
||||
ctx,
|
||||
@@ -501,18 +501,18 @@ async def test_execute_stream_request_allows_tunnel_delegate_for_rust(
|
||||
|
||||
dummy_ctx = _DummyStreamResponseCtx()
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "proxy") is not None
|
||||
assert getattr(plan.proxy, "mode") == "tunnel"
|
||||
assert getattr(plan.proxy, "node_id") == "node-1"
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "text/event-stream"},
|
||||
byte_iterator=_iter_chunks([b"data: [DONE]\n\n"]),
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
stream = await handler._execute_stream_request(
|
||||
ctx,
|
||||
@@ -577,16 +577,16 @@ async def test_execute_stream_request_allows_tls_profile_for_rust(
|
||||
_fake_prepare_provider_request,
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "tls_profile") == "claude_code_nodejs"
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "text/event-stream"},
|
||||
byte_iterator=_iter_chunks([b"data: [DONE]\n\n"]),
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
stream = await handler._execute_stream_request(
|
||||
ctx,
|
||||
@@ -629,16 +629,16 @@ async def test_execute_stream_request_turns_rust_upstream_error_into_http_status
|
||||
|
||||
dummy_ctx = _DummyStreamResponseCtx()
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "stream") is True
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=429,
|
||||
headers={"content-type": "application/json"},
|
||||
byte_iterator=_iter_chunks([b'{"error":{"message":"slow down"}}']),
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
with pytest.raises(httpx.HTTPStatusError) as exc_info:
|
||||
await handler._execute_stream_request(
|
||||
@@ -678,14 +678,14 @@ async def test_execute_stream_request_raises_when_rust_unavailable(
|
||||
output_limit=None,
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
del plan
|
||||
raise RustExecutorClientError("executor down")
|
||||
raise ExecutionRuntimeClientError("executor down")
|
||||
|
||||
async def _fake_get_upstream_client(*args: Any, **kwargs: Any) -> object:
|
||||
raise AssertionError("python fallback should not be used")
|
||||
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(
|
||||
"src.clients.http_client.HTTPClientPool.get_upstream_client",
|
||||
_fake_get_upstream_client,
|
||||
@@ -728,15 +728,15 @@ async def test_execute_stream_request_raises_when_remote_contract_is_ineligible(
|
||||
output_limit=None,
|
||||
)
|
||||
|
||||
async def _should_not_call_rust(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _should_not_call_rust(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
del self, plan
|
||||
raise AssertionError("rust executor should not be called")
|
||||
|
||||
async def _fake_get_upstream_client(*args: Any, **kwargs: Any) -> object:
|
||||
raise AssertionError("python fallback should not be used")
|
||||
|
||||
monkeypatch.setattr(chatmod, "is_remote_contract_eligible", lambda plan: False)
|
||||
monkeypatch.setattr(chatmod.RustExecutorClient, "execute_stream", _should_not_call_rust)
|
||||
monkeypatch.setattr(chatmod, "is_remote_execution_runtime_contract_eligible", lambda plan: False)
|
||||
monkeypatch.setattr(chatmod.ExecutionRuntimeClient, "execute_stream", _should_not_call_rust)
|
||||
monkeypatch.setattr(
|
||||
"src.clients.http_client.HTTPClientPool.get_upstream_client",
|
||||
_fake_get_upstream_client,
|
||||
|
||||
@@ -15,10 +15,10 @@ from src.api.handlers.base.cli_stream_mixin import CliStreamMixin
|
||||
from src.api.handlers.base.cli_sync_mixin import CliSyncMixin
|
||||
from src.api.handlers.base.stream_context import StreamContext
|
||||
from src.core.exceptions import ProviderNotAvailableException
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorStreamResult,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeStreamResult,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -278,9 +278,9 @@ async def test_cli_process_sync_uses_rust_executor_when_available(
|
||||
pool_summary=None,
|
||||
)
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
assert getattr(plan, "provider_api_format") == "openai:cli"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "resp-rust-cli"},
|
||||
headers={"content-type": "application/json"},
|
||||
@@ -288,7 +288,7 @@ async def test_cli_process_sync_uses_rust_executor_when_available(
|
||||
|
||||
monkeypatch.setattr(taskmod, "TaskService", _FakeTaskService)
|
||||
monkeypatch.setattr(
|
||||
cli_sync_mod.RustExecutorClient,
|
||||
cli_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -376,10 +376,10 @@ async def test_cli_process_sync_aggregates_upstream_stream_after_rust(
|
||||
assert request_id == "req-cli-sync"
|
||||
return SimpleNamespace(id="agg-cli-1")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
assert getattr(plan, "provider_api_format") == "openai:cli"
|
||||
assert getattr(plan, "stream") is True
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_body_bytes=b"data: {\"id\":\"chunk-1\"}\n\ndata: [DONE]\n\n",
|
||||
headers={"content-type": "text/event-stream"},
|
||||
@@ -390,7 +390,7 @@ async def test_cli_process_sync_aggregates_upstream_stream_after_rust(
|
||||
|
||||
monkeypatch.setattr(taskmod, "TaskService", _FakeTaskService)
|
||||
monkeypatch.setattr(
|
||||
cli_sync_mod.RustExecutorClient,
|
||||
cli_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -451,16 +451,16 @@ async def test_cli_process_sync_raises_when_rust_unavailable(
|
||||
await kwargs["request_func"](provider, endpoint, key, candidate)
|
||||
raise AssertionError("task service should not reach Python local execution")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
del self, plan
|
||||
raise RustExecutorClientError("executor down")
|
||||
raise ExecutionRuntimeClientError("executor down")
|
||||
|
||||
async def _fake_get_upstream_client(*args: Any, **kwargs: Any) -> object:
|
||||
raise AssertionError("python fallback should not be used")
|
||||
|
||||
monkeypatch.setattr(taskmod, "TaskService", _FakeTaskService)
|
||||
monkeypatch.setattr(
|
||||
cli_sync_mod.RustExecutorClient,
|
||||
cli_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -485,7 +485,7 @@ async def test_cli_process_sync_raises_when_remote_contract_is_ineligible(
|
||||
) -> None:
|
||||
handler = _DummySyncHandler()
|
||||
monkeypatch.setattr(cli_sync_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(cli_sync_mod, "is_remote_contract_eligible", lambda plan: False)
|
||||
monkeypatch.setattr(cli_sync_mod, "is_remote_execution_runtime_contract_eligible", lambda plan: False)
|
||||
_patch_proxy_resolver(monkeypatch)
|
||||
|
||||
class _FakeTaskService:
|
||||
@@ -512,7 +512,7 @@ async def test_cli_process_sync_raises_when_remote_contract_is_ineligible(
|
||||
await kwargs["request_func"](provider, endpoint, key, candidate)
|
||||
raise AssertionError("task service should not complete after local upstream attempt")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
raise AssertionError("rust executor should not be used when contract is ineligible")
|
||||
|
||||
async def _fake_get_upstream_client(*args: Any, **kwargs: Any) -> object:
|
||||
@@ -520,7 +520,7 @@ async def test_cli_process_sync_raises_when_remote_contract_is_ineligible(
|
||||
|
||||
monkeypatch.setattr(taskmod, "TaskService", _FakeTaskService)
|
||||
monkeypatch.setattr(
|
||||
cli_sync_mod.RustExecutorClient,
|
||||
cli_sync_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -550,9 +550,9 @@ async def test_cli_execute_stream_request_uses_rust_sync_bridge(
|
||||
monkeypatch.setattr(cli_stream_mod.config, "executor_backend", "rust")
|
||||
_patch_proxy_resolver(monkeypatch)
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
assert getattr(plan, "stream") is False
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "sync-bridge-rust"},
|
||||
headers={"content-type": "application/json"},
|
||||
@@ -563,7 +563,7 @@ async def test_cli_execute_stream_request_uses_rust_sync_bridge(
|
||||
yield b"data: cli-bridge\n\n"
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli_stream_mod.RustExecutorClient,
|
||||
cli_stream_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -641,22 +641,22 @@ async def test_cli_execute_stream_request_raises_when_rust_unavailable(
|
||||
)
|
||||
|
||||
if upstream_is_stream:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
del self, plan
|
||||
raise RustExecutorClientError("executor down")
|
||||
raise ExecutionRuntimeClientError("executor down")
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli_stream_mod.RustExecutorClient,
|
||||
cli_stream_mod.ExecutionRuntimeClient,
|
||||
"execute_stream",
|
||||
_fake_execute_stream,
|
||||
)
|
||||
else:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
del self, plan
|
||||
raise RustExecutorClientError("executor down")
|
||||
raise ExecutionRuntimeClientError("executor down")
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli_stream_mod.RustExecutorClient,
|
||||
cli_stream_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -690,16 +690,16 @@ async def test_cli_execute_stream_request_raises_when_remote_contract_is_ineligi
|
||||
ctx.client_api_format = "openai:cli"
|
||||
|
||||
monkeypatch.setattr(cli_stream_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(cli_stream_mod, "is_remote_contract_eligible", lambda plan: False)
|
||||
monkeypatch.setattr(cli_stream_mod, "is_remote_execution_runtime_contract_eligible", lambda plan: False)
|
||||
_patch_proxy_resolver(monkeypatch)
|
||||
|
||||
async def _fake_get_upstream_client(*args: Any, **kwargs: Any) -> object:
|
||||
raise AssertionError("python fallback should not be used")
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
raise AssertionError("rust sync executor should not be used when contract is ineligible")
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
raise AssertionError("rust stream executor should not be used when contract is ineligible")
|
||||
|
||||
monkeypatch.setattr(
|
||||
@@ -707,12 +707,12 @@ async def test_cli_execute_stream_request_raises_when_remote_contract_is_ineligi
|
||||
_fake_get_upstream_client,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
cli_stream_mod.RustExecutorClient,
|
||||
cli_stream_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
cli_stream_mod.RustExecutorClient,
|
||||
cli_stream_mod.ExecutionRuntimeClient,
|
||||
"execute_stream",
|
||||
_fake_execute_stream,
|
||||
)
|
||||
@@ -763,9 +763,9 @@ async def test_cli_execute_stream_request_uses_rust_native_stream(
|
||||
monkeypatch.setattr(cli_stream_mod.config, "executor_backend", "rust")
|
||||
_patch_proxy_resolver(monkeypatch)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "stream") is True
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "text/event-stream", "x-upstream-test": "true"},
|
||||
byte_iterator=_iter_chunks(
|
||||
@@ -778,7 +778,7 @@ async def test_cli_execute_stream_request_uses_rust_native_stream(
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
cli_stream_mod.RustExecutorClient,
|
||||
cli_stream_mod.ExecutionRuntimeClient,
|
||||
"execute_stream",
|
||||
_fake_execute_stream,
|
||||
)
|
||||
|
||||
@@ -6,9 +6,9 @@ from unittest.mock import AsyncMock
|
||||
import pytest
|
||||
|
||||
from src.api.handlers.base.endpoint_checker import EndpointCheckRequest, HttpRequestExecutor
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorStreamResult,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeStreamResult,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ async def test_endpoint_checker_sync_prefers_rust_executor(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.api.handlers.base import endpoint_checker as mod
|
||||
from src.services.request import rust_executor_client as rust_mod
|
||||
from src.services.request import execution_runtime_client as rust_mod
|
||||
|
||||
monkeypatch.setattr(mod.config, "executor_backend", "rust")
|
||||
|
||||
@@ -42,15 +42,15 @@ async def test_endpoint_checker_sync_prefers_rust_executor(
|
||||
async def _fake_execute_sync_json(
|
||||
self: object,
|
||||
plan: Any,
|
||||
) -> RustExecutorSyncResult:
|
||||
) -> ExecutionRuntimeSyncResult:
|
||||
captured["plan"] = plan
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "resp_1", "usage": {"prompt_tokens": 1, "completion_tokens": 2}},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_mod.RustExecutorClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
monkeypatch.setattr(rust_mod.ExecutionRuntimeClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
|
||||
result = await executor.execute(
|
||||
EndpointCheckRequest(
|
||||
@@ -80,7 +80,7 @@ async def test_endpoint_checker_stream_prefers_rust_executor(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.api.handlers.base import endpoint_checker as mod
|
||||
from src.services.request import rust_executor_client as rust_mod
|
||||
from src.services.request import execution_runtime_client as rust_mod
|
||||
|
||||
monkeypatch.setattr(mod.config, "executor_backend", "rust")
|
||||
|
||||
@@ -98,15 +98,15 @@ async def test_endpoint_checker_stream_prefers_rust_executor(
|
||||
|
||||
stream_ctx = _DummyStreamContext()
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: Any) -> RustExecutorStreamResult:
|
||||
return RustExecutorStreamResult(
|
||||
async def _fake_execute_stream(self: object, plan: Any) -> ExecutionRuntimeStreamResult:
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "text/event-stream"},
|
||||
byte_iterator=_byte_iter(),
|
||||
response_ctx=stream_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_mod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(rust_mod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
result = await executor.execute(
|
||||
EndpointCheckRequest(
|
||||
|
||||
@@ -11,11 +11,11 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
||||
|
||||
import src.api.handlers.gemini.video_handler as video_mod
|
||||
import src.services.proxy_node.resolver as resolver_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as rust_client_mod
|
||||
from src.api.handlers.gemini.video_handler import GeminiVeoHandler
|
||||
from src.core.api_format.conversion.internal_video import VideoStatus
|
||||
from src.core.exceptions import ProviderNotAvailableException
|
||||
from src.services.request.rust_executor_client import RustExecutorStreamResult
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeStreamResult
|
||||
|
||||
|
||||
class _DummyStreamResponseCtx:
|
||||
@@ -189,19 +189,19 @@ async def test_handle_download_content_uses_rust_executor_with_proxy_snapshot(
|
||||
_fake_resolve_proxy_info_async,
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "method") == "GET"
|
||||
assert getattr(plan, "url") == "https://storage.example.com/video.mp4"
|
||||
assert getattr(plan, "headers") == {"x-goog-api-key": "upstream-key"}
|
||||
assert getattr(plan, "proxy").url == "http://proxy.local:8080"
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "video/mp4", "x-rust-download": "true"},
|
||||
byte_iterator=_iter_chunks([b"gemini-", b"video"]),
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_client_mod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(rust_client_mod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
response = await handler.handle_download_content(
|
||||
task_id="operations/ext-1",
|
||||
http_request=SimpleNamespace(),
|
||||
|
||||
@@ -11,9 +11,9 @@ import src.api.handlers.openai.video_handler as video_mod
|
||||
from src.api.handlers.openai.video_handler import OpenAIVideoHandler
|
||||
from src.core.api_format.conversion.internal_video import VideoStatus
|
||||
from src.core.exceptions import ProviderNotAvailableException
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorStreamResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeStreamResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -61,19 +61,19 @@ async def test_handle_download_content_uses_rust_executor_for_direct_video_url(
|
||||
),
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "method") == "GET"
|
||||
assert getattr(plan, "url") == "https://cdn.example.com/video.mp4"
|
||||
assert getattr(plan, "body").json_body is None
|
||||
assert getattr(plan, "body").body_bytes_b64 is None
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "video/mp4", "x-rust-download": "true"},
|
||||
byte_iterator=_iter_chunks([b"video-", b"bytes"]),
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(video_mod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(video_mod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
response = await handler.handle_download_content(
|
||||
task_id="task-1",
|
||||
@@ -128,21 +128,21 @@ async def test_handle_download_content_uses_rust_executor_for_upstream_content_e
|
||||
lambda original_headers, upstream_key, endpoint: {"authorization": f"Bearer {upstream_key}"},
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "method") == "GET"
|
||||
assert getattr(plan, "url") == "https://api.openai.com/v1/videos/ext-1/content"
|
||||
assert getattr(plan, "headers") == {"authorization": "Bearer upstream-key"}
|
||||
assert getattr(plan, "provider_id") == "prov-1"
|
||||
assert getattr(plan, "endpoint_id") == "ep-1"
|
||||
assert getattr(plan, "key_id") == "key-1"
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "video/mp4", "x-rust-download": "true"},
|
||||
byte_iterator=_iter_chunks([b"upstream-", b"video"]),
|
||||
response_ctx=dummy_ctx,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(video_mod.RustExecutorClient, "execute_stream", _fake_execute_stream)
|
||||
monkeypatch.setattr(video_mod.ExecutionRuntimeClient, "execute_stream", _fake_execute_stream)
|
||||
|
||||
response = await handler.handle_download_content(
|
||||
task_id="task-1",
|
||||
@@ -175,11 +175,11 @@ async def test_handle_download_content_raises_when_rust_executor_unavailable(
|
||||
),
|
||||
)
|
||||
|
||||
async def _failing_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _failing_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
del self, plan
|
||||
raise RustExecutorClientError("executor down")
|
||||
raise ExecutionRuntimeClientError("executor down")
|
||||
|
||||
monkeypatch.setattr(video_mod.RustExecutorClient, "execute_stream", _failing_execute_stream)
|
||||
monkeypatch.setattr(video_mod.ExecutionRuntimeClient, "execute_stream", _failing_execute_stream)
|
||||
with pytest.raises(ProviderNotAvailableException):
|
||||
await handler.handle_download_content(
|
||||
task_id="task-1",
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
|
||||
@@ -63,7 +63,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import ExecutionPlan, ExecutionPlanBody, PreparedExecutionPlan
|
||||
|
||||
|
||||
def _wait_until(predicate: Any, *, timeout: float = 1.0, interval: float = 0.01) -> None:
|
||||
@@ -919,7 +919,7 @@ def test_execute_sync_route_handles_openai_video_remix_with_original_request(
|
||||
assert response.json() == {"video": True}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_gemini_files_download(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_gemini_files_download(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -983,7 +983,7 @@ def test_plan_stream_route_returns_executor_plan_for_gemini_files_download(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_openai_video_content(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_openai_video_content(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -1047,7 +1047,7 @@ def test_plan_stream_route_returns_executor_plan_for_openai_video_content(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_files_get(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_files_get(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -1113,7 +1113,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_files_get(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_chat(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -1179,7 +1179,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_chat(
|
||||
}
|
||||
|
||||
|
||||
def test_decision_sync_route_returns_executor_decision_for_openai_chat(
|
||||
def test_decision_sync_route_returns_execution_runtime_decision_for_openai_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -1262,7 +1262,7 @@ def test_decision_sync_route_returns_executor_decision_for_openai_chat(
|
||||
}
|
||||
|
||||
|
||||
def test_decision_stream_route_returns_executor_decision_for_openai_chat(
|
||||
def test_decision_stream_route_returns_execution_runtime_decision_for_openai_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -1411,7 +1411,7 @@ def test_decision_stream_route_requires_legacy_header(monkeypatch: pytest.Monkey
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_decision_stream_route_returns_executor_decision_for_claude_and_gemini_chat(
|
||||
def test_decision_stream_route_returns_execution_runtime_decision_for_claude_and_gemini_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
path: str,
|
||||
headers: dict[str, str],
|
||||
@@ -1572,7 +1572,7 @@ def test_decision_stream_route_returns_executor_decision_for_claude_and_gemini_c
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_decision_stream_route_returns_executor_decision_for_cli_variants(
|
||||
def test_decision_stream_route_returns_execution_runtime_decision_for_cli_variants(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
path: str,
|
||||
headers: dict[str, str],
|
||||
@@ -1681,7 +1681,7 @@ def test_decision_stream_route_returns_executor_decision_for_cli_variants(
|
||||
("/v1/responses/compact", "openai_compact_sync", "openai:compact"),
|
||||
],
|
||||
)
|
||||
def test_decision_sync_route_returns_executor_decision_for_openai_cli_variants(
|
||||
def test_decision_sync_route_returns_execution_runtime_decision_for_openai_cli_variants(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
path: str,
|
||||
decision_kind: str,
|
||||
@@ -1788,7 +1788,7 @@ def test_decision_sync_route_returns_executor_decision_for_openai_cli_variants(
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_decision_sync_route_returns_executor_decision_for_claude_variants(
|
||||
def test_decision_sync_route_returns_execution_runtime_decision_for_claude_variants(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
headers: dict[str, str],
|
||||
decision_kind: str,
|
||||
@@ -1914,7 +1914,7 @@ def test_decision_sync_route_returns_executor_decision_for_claude_variants(
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_decision_sync_route_returns_executor_decision_for_gemini_variants(
|
||||
def test_decision_sync_route_returns_execution_runtime_decision_for_gemini_variants(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
path: str,
|
||||
headers: dict[str, str],
|
||||
@@ -2020,7 +2020,7 @@ def test_decision_sync_route_returns_executor_decision_for_gemini_variants(
|
||||
}
|
||||
|
||||
|
||||
def test_decision_sync_route_returns_executor_decision_for_gemini_files_get(
|
||||
def test_decision_sync_route_returns_execution_runtime_decision_for_gemini_files_get(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2181,7 +2181,7 @@ def test_decision_sync_route_returns_executor_decision_for_gemini_files_get(
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_decision_sync_route_returns_executor_decision_for_video_variants(
|
||||
def test_decision_sync_route_returns_execution_runtime_decision_for_video_variants(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
method: str,
|
||||
path: str,
|
||||
@@ -2274,7 +2274,7 @@ def test_decision_sync_route_returns_executor_decision_for_video_variants(
|
||||
assert response.json() == expected
|
||||
|
||||
|
||||
def test_decision_stream_route_returns_executor_decision_for_gemini_files_download(
|
||||
def test_decision_stream_route_returns_execution_runtime_decision_for_gemini_files_download(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2345,7 +2345,7 @@ def test_decision_stream_route_returns_executor_decision_for_gemini_files_downlo
|
||||
assert response.json()["decision_kind"] == "gemini_files_download"
|
||||
|
||||
|
||||
def test_decision_stream_route_returns_executor_decision_for_openai_video_content(
|
||||
def test_decision_stream_route_returns_execution_runtime_decision_for_openai_video_content(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2478,7 +2478,7 @@ def test_plan_sync_route_resolves_auth_context_when_missing(
|
||||
assert build_plan.await_args.kwargs["auth_context"].api_key_id == "key-123"
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_video_create(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_video_create(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2544,7 +2544,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_video_create(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_video_remix(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_video_remix(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2610,7 +2610,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_video_remix(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_video_create(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_video_create(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2676,7 +2676,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_video_create(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_video_cancel(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_video_cancel(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2740,7 +2740,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_video_cancel(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_video_delete(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_video_delete(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2804,7 +2804,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_video_delete(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_video_cancel(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_video_cancel(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -2869,7 +2869,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_video_cancel(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_openai_chat(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_openai_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3011,7 +3011,7 @@ def test_plan_stream_route_resolves_auth_context_when_missing(
|
||||
assert build_plan.await_args.kwargs["auth_context"].api_key_id == "key-123"
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_claude_chat(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_claude_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3087,7 +3087,7 @@ def test_plan_stream_route_returns_executor_plan_for_claude_chat(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_gemini_chat(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_gemini_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3157,7 +3157,7 @@ def test_plan_stream_route_returns_executor_plan_for_gemini_chat(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_openai_cli(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_openai_cli(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3227,7 +3227,7 @@ def test_plan_stream_route_returns_executor_plan_for_openai_cli(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_claude_cli(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_claude_cli(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3308,7 +3308,7 @@ def test_plan_stream_route_returns_executor_plan_for_claude_cli(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_stream_route_returns_executor_plan_for_gemini_cli(
|
||||
def test_plan_stream_route_returns_execution_runtime_plan_for_gemini_cli(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3379,7 +3379,7 @@ def test_plan_stream_route_returns_executor_plan_for_gemini_cli(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_cli(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_cli(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3445,7 +3445,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_cli(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_openai_compact(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_openai_compact(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3511,7 +3511,7 @@ def test_plan_sync_route_returns_executor_plan_for_openai_compact(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_claude_chat(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_claude_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3577,7 +3577,7 @@ def test_plan_sync_route_returns_executor_plan_for_claude_chat(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_chat(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_chat(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3643,7 +3643,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_chat(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_claude_cli(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_claude_cli(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3709,7 +3709,7 @@ def test_plan_sync_route_returns_executor_plan_for_claude_cli(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_cli(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_cli(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3776,7 +3776,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_cli(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_files_list(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_files_list(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3842,7 +3842,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_files_list(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_files_upload(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_files_upload(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
@@ -3912,7 +3912,7 @@ def test_plan_sync_route_returns_executor_plan_for_gemini_files_upload(
|
||||
}
|
||||
|
||||
|
||||
def test_plan_sync_route_returns_executor_plan_for_gemini_files_delete(
|
||||
def test_plan_sync_route_returns_execution_runtime_plan_for_gemini_files_delete(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
app = FastAPI()
|
||||
|
||||
@@ -11,13 +11,13 @@ from fastapi.responses import StreamingResponse
|
||||
|
||||
import src.api.public.gemini_files as gemini_files_mod
|
||||
import src.services.proxy_node.resolver as resolver_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as rust_client_mod
|
||||
from src.api.public.gemini_files import UpstreamContext
|
||||
from src.config.settings import config
|
||||
from src.services.request.executor_plan import ExecutionProxySnapshot
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorStreamResult,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_plan import ExecutionProxySnapshot
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeStreamResult,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -111,19 +111,19 @@ async def test_proxy_request_passes_proxy_snapshot_to_rust_executor(
|
||||
url="http://proxy.local:8080",
|
||||
)
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
assert getattr(plan, "method") == "GET"
|
||||
assert getattr(plan, "provider_id") == "prov-1"
|
||||
assert getattr(plan, "endpoint_id") == "ep-1"
|
||||
assert getattr(plan, "proxy").url == "http://proxy.local:8080"
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json", "x-rust-files": "true"},
|
||||
response_json={"files": [{"name": "files/abc"}]},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
rust_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
@@ -223,14 +223,14 @@ async def test_download_file_uses_enriched_proxy_snapshot_for_regular_files(
|
||||
AsyncMock(return_value=enriched_ctx),
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
assert getattr(plan, "method") == "GET"
|
||||
assert getattr(plan, "url") == (
|
||||
"https://generativelanguage.googleapis.com/v1beta/files/file-1:download?alt=media"
|
||||
)
|
||||
assert getattr(plan, "headers") == {"x-goog-api-key": "upstream-key"}
|
||||
assert getattr(plan, "proxy").url == "http://proxy.local:8080"
|
||||
return RustExecutorStreamResult(
|
||||
return ExecutionRuntimeStreamResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/octet-stream", "x-rust-files": "true"},
|
||||
byte_iterator=_iter_chunks([b"file-", b"bytes"]),
|
||||
@@ -238,7 +238,7 @@ async def test_download_file_uses_enriched_proxy_snapshot_for_regular_files(
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
rust_client_mod.ExecutionRuntimeClient,
|
||||
"execute_stream",
|
||||
_fake_execute_stream,
|
||||
)
|
||||
@@ -302,12 +302,12 @@ async def test_download_file_returns_503_when_rust_stream_unavailable(
|
||||
AsyncMock(return_value=enriched_ctx),
|
||||
)
|
||||
|
||||
async def _fake_execute_stream(self: object, plan: object) -> RustExecutorStreamResult:
|
||||
async def _fake_execute_stream(self: object, plan: object) -> ExecutionRuntimeStreamResult:
|
||||
del self, plan
|
||||
raise rust_client_mod.RustExecutorClientError("executor unavailable")
|
||||
raise rust_client_mod.ExecutionRuntimeClientError("executor unavailable")
|
||||
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
rust_client_mod.ExecutionRuntimeClient,
|
||||
"execute_stream",
|
||||
_fake_execute_stream,
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ from src.database import get_db
|
||||
from src.models.database import Base, RequestCandidate
|
||||
from src.services.orchestration.candidate_resolver import CandidateResolver
|
||||
from src.services.scheduling.schemas import PoolCandidate, ProviderCandidate
|
||||
from src.services.request.executor_plan import (
|
||||
from src.services.request.execution_runtime_plan import (
|
||||
ExecutionPlan,
|
||||
ExecutionPlanBody,
|
||||
PreparedExecutionPlan,
|
||||
|
||||
@@ -897,8 +897,8 @@ def test_python_host_app_surface_keeps_shell_routes_and_rejects_removed_edges()
|
||||
assert _app_matches_http_route("/api/internal/gateway/auth-context", "POST") is False
|
||||
assert _app_matches_http_route("/api/internal/gateway/resolve", "POST") is False
|
||||
assert _app_matches_http_route("/api/internal/gateway/decision-sync", "POST") is False
|
||||
assert _app_matches_http_route("/api/internal/hub/heartbeat", "POST") is False
|
||||
assert _app_matches_http_route("/api/internal/hub/node-status", "POST") is False
|
||||
assert _app_matches_http_route("/api/internal/tunnel/heartbeat", "POST") is False
|
||||
assert _app_matches_http_route("/api/internal/tunnel/node-status", "POST") is False
|
||||
assert _app_matches_http_route("/readyz", "GET") is False
|
||||
|
||||
tags = {tag.get("name") for tag in main_module.app.openapi().get("tags", [])}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"""
|
||||
aether-hub local relay 端到端测试
|
||||
aether-gateway tunnel runtime harness 端到端测试
|
||||
|
||||
测试流程:
|
||||
1. 启动 aether-hub(绑定随机端口)
|
||||
2. 用 websockets 库模拟一个 aether-proxy client 连接到 Hub
|
||||
1. 启动 aether-gateway 的 tunnel runtime harness(绑定随机端口)
|
||||
2. 用 websockets 库模拟一个 aether-proxy client 连接到 tunnel runtime
|
||||
3. Mock proxy 在收到请求帧后返回固定响应帧
|
||||
4. 通过 Hub 的 /local/relay/{node_id} HTTP API 发送请求
|
||||
5. 验证完整链路: HTTP request -> Hub -> WS frame -> mock proxy -> WS frame -> Hub -> HTTP response
|
||||
4. 通过 /api/internal/tunnel/relay/{node_id} HTTP API 发送请求
|
||||
5. 验证完整链路: HTTP request -> tunnel runtime -> WS frame -> mock proxy -> WS frame -> tunnel runtime -> HTTP response
|
||||
|
||||
运行: uv run python tests/e2e_hub_relay.py
|
||||
"""
|
||||
@@ -26,7 +26,7 @@ import time
|
||||
import httpx
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Protocol constants (mirror aether-hub/src/protocol.rs)
|
||||
# Protocol constants (mirror apps/aether-gateway/src/tunnel/embedded/protocol.rs)
|
||||
# ---------------------------------------------------------------------------
|
||||
HEADER_SIZE = 10
|
||||
|
||||
@@ -158,20 +158,30 @@ async def run_test() -> bool:
|
||||
hub_binary = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..",
|
||||
"aether-hub",
|
||||
"target",
|
||||
"release",
|
||||
"aether-hub",
|
||||
"examples",
|
||||
"tunnel_runtime_harness",
|
||||
)
|
||||
hub_binary = os.path.normpath(hub_binary)
|
||||
|
||||
if not os.path.isfile(hub_binary):
|
||||
print(f"FAIL: hub binary not found at {hub_binary}")
|
||||
print(" run: cd aether-hub && cargo build --release")
|
||||
return False
|
||||
hub_binary = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..",
|
||||
"target",
|
||||
"debug",
|
||||
"examples",
|
||||
"tunnel_runtime_harness",
|
||||
)
|
||||
hub_binary = os.path.normpath(hub_binary)
|
||||
if not os.path.isfile(hub_binary):
|
||||
print(f"FAIL: tunnel runtime harness binary not found at {hub_binary}")
|
||||
print(" run: cargo build -p aether-gateway --example tunnel_runtime_harness")
|
||||
return False
|
||||
|
||||
# Start aether-hub (with control plane disabled since we don't have the app running)
|
||||
print(f"[1/5] Starting aether-hub on {hub_bind} ...")
|
||||
# Start tunnel runtime harness (with control plane disabled since we don't have the app running)
|
||||
print(f"[1/5] Starting tunnel runtime harness on {hub_bind} ...")
|
||||
hub_proc = subprocess.Popen(
|
||||
[
|
||||
hub_binary,
|
||||
@@ -187,19 +197,19 @@ async def run_test() -> bool:
|
||||
)
|
||||
|
||||
try:
|
||||
# Wait for hub to be ready
|
||||
# Wait for runtime to be ready
|
||||
for _ in range(30):
|
||||
await asyncio.sleep(0.2)
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(f"http://{hub_bind}/health", timeout=1.0)
|
||||
if resp.status_code == 200:
|
||||
print(" hub is healthy")
|
||||
print(" tunnel runtime harness is healthy")
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
else:
|
||||
print("FAIL: hub did not start in time")
|
||||
print("FAIL: tunnel runtime harness did not start in time")
|
||||
return False
|
||||
|
||||
# Check initial stats
|
||||
@@ -214,7 +224,9 @@ async def run_test() -> bool:
|
||||
proxy_ready = asyncio.Event()
|
||||
print(f"\n[2/5] Connecting mock proxy (node_id={node_id}) ...")
|
||||
proxy_task = asyncio.create_task(
|
||||
mock_proxy(f"ws://{hub_bind}/proxy", node_id, proxy_ready)
|
||||
mock_proxy(
|
||||
f"ws://{hub_bind}/api/internal/proxy-tunnel", node_id, proxy_ready
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -223,7 +235,7 @@ async def run_test() -> bool:
|
||||
print("FAIL: mock proxy did not connect in time")
|
||||
return False
|
||||
|
||||
# Give hub a moment to register
|
||||
# Give runtime a moment to register
|
||||
await asyncio.sleep(0.3)
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
@@ -249,7 +261,7 @@ async def run_test() -> bool:
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
relay_url = f"http://{hub_bind}/local/relay/{node_id}"
|
||||
relay_url = f"http://{hub_bind}/api/internal/tunnel/relay/{node_id}"
|
||||
resp = await client.post(
|
||||
relay_url,
|
||||
content=envelope,
|
||||
@@ -281,7 +293,7 @@ async def run_test() -> bool:
|
||||
print(f"\n[5/5] Testing error cases ...")
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(
|
||||
f"http://{hub_bind}/local/relay/non-existent-node",
|
||||
f"http://{hub_bind}/api/internal/tunnel/relay/non-existent-node",
|
||||
content=encode_relay_envelope(
|
||||
{"method": "GET", "url": "https://example.com", "headers": {}, "timeout": 5},
|
||||
b"",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"""
|
||||
aether-executor 本地端到端测试
|
||||
aether-gateway execution runtime harness 本地端到端测试
|
||||
|
||||
测试流程:
|
||||
1. 启动本地假上游 HTTP 服务
|
||||
2. 启动 aether-executor(Unix Socket)
|
||||
3. 用 Python RustExecutorClient 发送 ExecutionPlan
|
||||
2. 启动 aether-gateway example harness(Unix Socket)
|
||||
3. 用 Python ExecutionRuntimeClient 发送 ExecutionPlan
|
||||
4. 验证执行结果与上游响应一致
|
||||
|
||||
运行:
|
||||
cargo build -p aether-executor
|
||||
cargo build -p aether-gateway --example execution-runtime-harness
|
||||
uv run python tests/e2e_rust_executor.py
|
||||
"""
|
||||
|
||||
@@ -26,13 +26,13 @@ from pathlib import Path
|
||||
|
||||
import httpx
|
||||
|
||||
from src.services.request.executor_plan import (
|
||||
from src.services.request.execution_runtime_plan import (
|
||||
ExecutionPlan,
|
||||
ExecutionPlanBody,
|
||||
ExecutionProxySnapshot,
|
||||
ExecutionPlanTimeouts,
|
||||
)
|
||||
from src.services.request.rust_executor_client import RustExecutorClient
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeClient
|
||||
|
||||
|
||||
async def _upstream_app(scope, receive, send) -> None: # type: ignore[no-untyped-def]
|
||||
@@ -361,12 +361,6 @@ async def _start_proxy_server() -> tuple[asyncio.AbstractServer, int, asyncio.Fu
|
||||
|
||||
async def run_test() -> bool:
|
||||
repo_root = Path(__file__).resolve().parents[1]
|
||||
executor_binary = repo_root / "target" / "debug" / "aether-executor"
|
||||
if not executor_binary.is_file():
|
||||
print(f"FAIL: executor binary not found at {executor_binary}")
|
||||
print(" run: cargo build -p aether-executor")
|
||||
return False
|
||||
|
||||
upstream_listener = await asyncio.start_server(lambda r, w: None, "127.0.0.1", 0)
|
||||
upstream_port = upstream_listener.sockets[0].getsockname()[1]
|
||||
upstream_listener.close()
|
||||
@@ -401,12 +395,19 @@ async def run_test() -> bool:
|
||||
executor_socket.unlink(missing_ok=True)
|
||||
executor_proc = subprocess.Popen(
|
||||
[
|
||||
str(executor_binary),
|
||||
"cargo",
|
||||
"run",
|
||||
"-p",
|
||||
"aether-gateway",
|
||||
"--example",
|
||||
"execution-runtime-harness",
|
||||
"--",
|
||||
"--transport",
|
||||
"unix_socket",
|
||||
"--unix-socket",
|
||||
str(executor_socket),
|
||||
],
|
||||
cwd=repo_root,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
@@ -433,7 +434,7 @@ async def run_test() -> bool:
|
||||
for _ in range(50):
|
||||
try:
|
||||
resp = await client.post(
|
||||
f"http://127.0.0.1:{relay_port}/local/relay/probe",
|
||||
f"http://127.0.0.1:{relay_port}/api/internal/tunnel/relay/probe",
|
||||
content=(0).to_bytes(4, "big"),
|
||||
timeout=0.2,
|
||||
)
|
||||
@@ -445,8 +446,8 @@ async def run_test() -> bool:
|
||||
print("FAIL: relay server did not start in time")
|
||||
return False
|
||||
|
||||
print("[2/4] Waiting for aether-executor ...")
|
||||
for _ in range(100):
|
||||
print("[2/4] Waiting for execution-runtime harness ...")
|
||||
for _ in range(600):
|
||||
if executor_socket.exists():
|
||||
try:
|
||||
async with httpx.AsyncClient(
|
||||
@@ -460,13 +461,13 @@ async def run_test() -> bool:
|
||||
pass
|
||||
await asyncio.sleep(0.1)
|
||||
else:
|
||||
print("FAIL: executor did not start in time")
|
||||
print("FAIL: execution-runtime harness did not start in time")
|
||||
if executor_proc.stdout is not None:
|
||||
print(executor_proc.stdout.read())
|
||||
return False
|
||||
|
||||
print("[3/4] Sending ExecutionPlan via RustExecutorClient ...")
|
||||
client = RustExecutorClient(
|
||||
print("[3/4] Sending ExecutionPlan via ExecutionRuntimeClient ...")
|
||||
client = ExecutionRuntimeClient(
|
||||
transport="unix_socket",
|
||||
socket_path=str(executor_socket),
|
||||
base_url="http://127.0.0.1:5219",
|
||||
@@ -539,7 +540,7 @@ async def run_test() -> bool:
|
||||
mode="tunnel",
|
||||
node_id="node-1",
|
||||
label="relay-node",
|
||||
extra={"hub_base_url": f"http://127.0.0.1:{relay_port}"},
|
||||
extra={"tunnel_base_url": f"http://127.0.0.1:{relay_port}"},
|
||||
),
|
||||
timeouts=ExecutionPlanTimeouts(
|
||||
connect_ms=5_000,
|
||||
@@ -844,7 +845,7 @@ async def run_test() -> bool:
|
||||
mode="tunnel",
|
||||
node_id="node-1",
|
||||
label="relay-node",
|
||||
extra={"hub_base_url": f"http://127.0.0.1:{relay_port}"},
|
||||
extra={"tunnel_base_url": f"http://127.0.0.1:{relay_port}"},
|
||||
),
|
||||
timeouts=ExecutionPlanTimeouts(
|
||||
connect_ms=5_000,
|
||||
|
||||
@@ -7,7 +7,7 @@ import httpx
|
||||
import pytest
|
||||
|
||||
import src.services.provider.adapters.antigravity.rust_http as antigravity_rust_http_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as runtime_client_mod
|
||||
from src.services.provider.adapters.antigravity.client import (
|
||||
fetch_available_models,
|
||||
load_code_assist,
|
||||
@@ -19,7 +19,7 @@ from src.services.provider.adapters.antigravity.constants import (
|
||||
PROD_BASE_URL,
|
||||
SANDBOX_BASE_URL,
|
||||
)
|
||||
from src.services.request.rust_executor_client import RustExecutorSyncResult
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeSyncResult
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# load_code_assist
|
||||
@@ -88,10 +88,10 @@ async def test_load_code_assist_uses_rust_executor(
|
||||
) -> None:
|
||||
monkeypatch.setattr(antigravity_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={"cloudaicompanionProject": "project-rust"},
|
||||
@@ -110,7 +110,7 @@ async def test_load_code_assist_uses_rust_executor(
|
||||
data = await load_code_assist("tok", proxy_config=None, timeout_seconds=1.0)
|
||||
|
||||
assert data["cloudaicompanionProject"] == "project-rust"
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.url == f"{SANDBOX_BASE_URL}/v1internal:loadCodeAssist"
|
||||
assert plan.provider_api_format == "antigravity:load_code_assist"
|
||||
|
||||
@@ -176,10 +176,10 @@ async def test_fetch_available_models_uses_rust_executor(
|
||||
) -> None:
|
||||
monkeypatch.setattr(antigravity_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={"models": {"claude-sonnet-4": {"displayName": "Claude Sonnet 4"}}},
|
||||
@@ -203,7 +203,7 @@ async def test_fetch_available_models_uses_rust_executor(
|
||||
)
|
||||
|
||||
assert "models" in data
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.url == f"{DAILY_BASE_URL}/v1internal:fetchAvailableModels"
|
||||
assert plan.provider_api_format == "antigravity:fetch_available_models"
|
||||
assert plan.body.json_body == {"project": "project-1"}
|
||||
@@ -215,10 +215,10 @@ async def test_onboard_user_uses_rust_executor(
|
||||
) -> None:
|
||||
monkeypatch.setattr(antigravity_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={
|
||||
@@ -246,7 +246,7 @@ async def test_onboard_user_uses_rust_executor(
|
||||
)
|
||||
|
||||
assert project_id == "project-onboard"
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.url == f"{PROD_BASE_URL}/v1internal:onboardUser"
|
||||
assert plan.provider_api_format == "antigravity:onboard_user"
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ import httpx
|
||||
import pytest
|
||||
|
||||
import src.services.provider.adapters.gemini_cli.rust_http as gemini_cli_rust_http_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as runtime_client_mod
|
||||
from src.services.provider.adapters.gemini_cli.client import (
|
||||
load_code_assist,
|
||||
onboard_user,
|
||||
)
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ async def test_load_code_assist_uses_rust_executor(
|
||||
) -> None:
|
||||
monkeypatch.setattr(gemini_cli_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={"cloudaicompanionProject": "project-1"},
|
||||
@@ -42,7 +42,7 @@ async def test_load_code_assist_uses_rust_executor(
|
||||
result = await load_code_assist("access-token", proxy_config=None, timeout_seconds=12.0)
|
||||
|
||||
assert result["cloudaicompanionProject"] == "project-1"
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.method == "POST"
|
||||
assert plan.url.endswith("/v1internal:loadCodeAssist")
|
||||
assert plan.provider_api_format == "gemini_cli:load_code_assist"
|
||||
@@ -61,9 +61,9 @@ async def test_load_code_assist_falls_back_to_python_when_rust_unavailable(
|
||||
) -> None:
|
||||
monkeypatch.setattr(gemini_cli_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(side_effect=RustExecutorClientError("executor down")),
|
||||
AsyncMock(side_effect=ExecutionRuntimeClientError("executor down")),
|
||||
)
|
||||
fake_client = SimpleNamespace(
|
||||
post=AsyncMock(
|
||||
@@ -91,10 +91,10 @@ async def test_onboard_user_uses_rust_executor(
|
||||
) -> None:
|
||||
monkeypatch.setattr(gemini_cli_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={
|
||||
@@ -118,7 +118,7 @@ async def test_onboard_user_uses_rust_executor(
|
||||
)
|
||||
|
||||
assert project_id == "project-onboarded"
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.method == "POST"
|
||||
assert plan.url.endswith("/v1internal:onboardUser")
|
||||
assert plan.provider_api_format == "gemini_cli:onboard_user"
|
||||
|
||||
@@ -10,15 +10,15 @@ import pytest
|
||||
import src.services.provider.adapters.kiro.token_manager as token_manager_mod
|
||||
import src.services.provider.adapters.kiro.usage as usage_mod
|
||||
import src.services.provider.adapters.kiro.rust_http as kiro_rust_http_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as runtime_client_mod
|
||||
from src.services.provider.adapters.kiro.token_manager import (
|
||||
refresh_idc_token,
|
||||
refresh_social_token,
|
||||
)
|
||||
from src.services.provider.adapters.kiro.usage import fetch_kiro_usage_limits
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ async def test_fetch_kiro_usage_limits_uses_rust_executor(
|
||||
) -> None:
|
||||
monkeypatch.setattr(kiro_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={
|
||||
@@ -64,7 +64,7 @@ async def test_fetch_kiro_usage_limits_uses_rust_executor(
|
||||
|
||||
assert result["usage_data"]["desktopUserInfo"]["email"] == "kiro@example.com"
|
||||
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.method == "GET"
|
||||
assert "getUsageLimits" in plan.url
|
||||
assert plan.provider_api_format == "kiro:usage"
|
||||
@@ -77,9 +77,9 @@ async def test_fetch_kiro_usage_limits_falls_back_to_python_when_rust_unavailabl
|
||||
) -> None:
|
||||
monkeypatch.setattr(kiro_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(side_effect=RustExecutorClientError("executor down")),
|
||||
AsyncMock(side_effect=ExecutionRuntimeClientError("executor down")),
|
||||
)
|
||||
fake_client = SimpleNamespace(
|
||||
get=AsyncMock(
|
||||
@@ -120,10 +120,10 @@ async def test_refresh_social_token_uses_rust_executor(
|
||||
monkeypatch.setattr(kiro_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(time, "time", lambda: 1_000)
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={
|
||||
@@ -157,7 +157,7 @@ async def test_refresh_social_token_uses_rust_executor(
|
||||
assert new_cfg.access_token == "new-social-access-token"
|
||||
assert new_cfg.expires_at == 2800
|
||||
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.method == "POST"
|
||||
assert plan.url == "https://prod.us-east-1.auth.desktop.kiro.dev/refreshToken"
|
||||
assert plan.provider_api_format == "kiro:social_refresh"
|
||||
@@ -171,10 +171,10 @@ async def test_refresh_idc_token_uses_rust_executor(
|
||||
monkeypatch.setattr(kiro_rust_http_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(time, "time", lambda: 2_000)
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={
|
||||
@@ -209,7 +209,7 @@ async def test_refresh_idc_token_uses_rust_executor(
|
||||
assert new_cfg.access_token == "new-idc-access-token"
|
||||
assert new_cfg.expires_at == 5600
|
||||
|
||||
plan = rust_client_mod.RustExecutorClient.execute_sync_json.await_args.args[0]
|
||||
plan = runtime_client_mod.ExecutionRuntimeClient.execute_sync_json.await_args.args[0]
|
||||
assert plan.method == "POST"
|
||||
assert plan.url == "https://oidc.eu-west-1.amazonaws.com/token"
|
||||
assert plan.provider_api_format == "kiro:idc_refresh"
|
||||
|
||||
@@ -19,7 +19,7 @@ from src.services.provider_keys.quota_refresh.antigravity_refresher import (
|
||||
)
|
||||
from src.services.provider_keys.quota_refresh.codex_refresher import refresh_codex_key_quota
|
||||
from src.services.provider_keys.quota_refresh.kiro_refresher import refresh_kiro_key_quota
|
||||
from src.services.request.rust_executor_client import RustExecutorSyncResult
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeSyncResult
|
||||
|
||||
|
||||
class _FakeDB:
|
||||
@@ -166,7 +166,7 @@ async def test_codex_refresher_prefers_rust_executor(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.services.provider_keys.quota_refresh import codex_refresher as module
|
||||
from src.services.request import rust_executor_client as rust_module
|
||||
from src.services.request import execution_runtime_client as runtime_module
|
||||
|
||||
monkeypatch.setattr(app_config, "executor_backend", "rust")
|
||||
|
||||
@@ -200,15 +200,19 @@ async def test_codex_refresher_prefers_rust_executor(
|
||||
module, "parse_codex_wham_usage_response", lambda _data: {"used_percent": 12.5}
|
||||
)
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: Any) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: Any) -> ExecutionRuntimeSyncResult:
|
||||
captured["plan"] = plan
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"ok": True},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_module.RustExecutorClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
monkeypatch.setattr(
|
||||
runtime_module.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
|
||||
result = await refresh_codex_key_quota(
|
||||
db=cast(Any, _FakeDB()),
|
||||
|
||||
@@ -14,7 +14,7 @@ from src.services.provider_ops.types import (
|
||||
ProviderActionType,
|
||||
ProviderOpsConfig,
|
||||
)
|
||||
from src.services.request.rust_executor_client import RustExecutorSyncResult
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeSyncResult
|
||||
|
||||
|
||||
class _FakeDB:
|
||||
@@ -133,7 +133,7 @@ async def test_verify_auth_prefers_rust_executor(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.services.provider_ops import service as module
|
||||
from src.services.request import rust_executor_client as rust_module
|
||||
from src.services.request import execution_runtime_client as runtime_module
|
||||
|
||||
service = ProviderOpsService(_FakeDB())
|
||||
architecture = _SuccessArchitecture()
|
||||
@@ -154,15 +154,19 @@ async def test_verify_auth_prefers_rust_executor(
|
||||
|
||||
captured: dict[str, Any] = {}
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: Any) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: Any) -> ExecutionRuntimeSyncResult:
|
||||
captured["plan"] = plan
|
||||
return RustExecutorSyncResult(
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"ok": True},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_module.RustExecutorClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
monkeypatch.setattr(
|
||||
runtime_module.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
|
||||
result = await service.verify_auth(
|
||||
base_url="https://example.com",
|
||||
|
||||
@@ -6,11 +6,11 @@ import pytest
|
||||
|
||||
import src.core.api_format.capabilities as capabilities_mod
|
||||
import src.services.model.upstream_fetcher as fetcher_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as runtime_client_mod
|
||||
from src.services.model.upstream_fetcher import fetch_models_from_endpoints
|
||||
from src.services.request.rust_executor_client import (
|
||||
RustExecutorClientError,
|
||||
RustExecutorSyncResult,
|
||||
from src.services.request.execution_runtime_client import (
|
||||
ExecutionRuntimeClientError,
|
||||
ExecutionRuntimeSyncResult,
|
||||
)
|
||||
|
||||
|
||||
@@ -34,13 +34,17 @@ async def test_fetch_models_from_endpoints_uses_rust_for_openai(
|
||||
AsyncMock(side_effect=AssertionError("python fallback should not run")),
|
||||
)
|
||||
execute_sync = AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"data": [{"id": "gpt-5", "owned_by": "openai"}]},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr(rust_client_mod.RustExecutorClient, "execute_sync_json", execute_sync)
|
||||
monkeypatch.setattr(
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
execute_sync,
|
||||
)
|
||||
|
||||
models, errors, ok = await fetch_models_from_endpoints(
|
||||
[
|
||||
@@ -84,7 +88,7 @@ async def test_fetch_models_from_endpoints_uses_rust_for_claude_paginated(
|
||||
)
|
||||
execute_sync = AsyncMock(
|
||||
side_effect=[
|
||||
RustExecutorSyncResult(
|
||||
ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={
|
||||
"data": [{"id": "claude-sonnet-4"}],
|
||||
@@ -93,7 +97,7 @@ async def test_fetch_models_from_endpoints_uses_rust_for_claude_paginated(
|
||||
},
|
||||
headers={"content-type": "application/json"},
|
||||
),
|
||||
RustExecutorSyncResult(
|
||||
ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={
|
||||
"data": [{"id": "claude-opus-4"}],
|
||||
@@ -103,7 +107,11 @@ async def test_fetch_models_from_endpoints_uses_rust_for_claude_paginated(
|
||||
),
|
||||
]
|
||||
)
|
||||
monkeypatch.setattr(rust_client_mod.RustExecutorClient, "execute_sync_json", execute_sync)
|
||||
monkeypatch.setattr(
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
execute_sync,
|
||||
)
|
||||
|
||||
models, errors, ok = await fetch_models_from_endpoints(
|
||||
[
|
||||
@@ -149,7 +157,7 @@ async def test_fetch_models_from_endpoints_uses_rust_for_gemini(
|
||||
AsyncMock(side_effect=AssertionError("python fallback should not run")),
|
||||
)
|
||||
execute_sync = AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={
|
||||
"models": [
|
||||
@@ -162,7 +170,11 @@ async def test_fetch_models_from_endpoints_uses_rust_for_gemini(
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr(rust_client_mod.RustExecutorClient, "execute_sync_json", execute_sync)
|
||||
monkeypatch.setattr(
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
execute_sync,
|
||||
)
|
||||
|
||||
models, errors, ok = await fetch_models_from_endpoints(
|
||||
[
|
||||
@@ -205,9 +217,9 @@ async def test_fetch_models_from_endpoints_returns_rust_only_error_when_rust_una
|
||||
lambda proxy_config, timeout=30.0: {"timeout": timeout},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(side_effect=RustExecutorClientError("executor down")),
|
||||
AsyncMock(side_effect=ExecutionRuntimeClientError("executor down")),
|
||||
)
|
||||
python_fetch = AsyncMock(return_value=([{"id": "fallback-model"}], None))
|
||||
monkeypatch.setattr(capabilities_mod, "fetch_models_for_api_format", python_fetch)
|
||||
|
||||
@@ -7,9 +7,9 @@ import httpx
|
||||
import pytest
|
||||
|
||||
import src.services.task.video.cancel as cancel_mod
|
||||
import src.services.request.rust_executor_client as rust_client_mod
|
||||
import src.services.request.execution_runtime_client as runtime_client_mod
|
||||
from src.core.api_format.conversion.internal_video import VideoStatus
|
||||
from src.services.request.rust_executor_client import RustExecutorSyncResult
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeSyncResult
|
||||
from src.services.task.video.cancel import VideoTaskCancelService
|
||||
|
||||
|
||||
@@ -66,10 +66,10 @@ async def test_video_cancel_service_uses_rust_for_openai_delete(
|
||||
|
||||
monkeypatch.setattr(cancel_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=204,
|
||||
headers={},
|
||||
response_json=None,
|
||||
@@ -134,14 +134,18 @@ async def test_video_cancel_service_uses_rust_for_gemini_cancel(
|
||||
|
||||
monkeypatch.setattr(cancel_mod.config, "executor_backend", "rust")
|
||||
execute_sync = AsyncMock(
|
||||
return_value=RustExecutorSyncResult(
|
||||
return_value=ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
headers={"content-type": "application/json"},
|
||||
response_json={"ok": True},
|
||||
response_body_bytes=None,
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr(rust_client_mod.RustExecutorClient, "execute_sync_json", execute_sync)
|
||||
monkeypatch.setattr(
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
execute_sync,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"src.core.crypto.crypto_service.decrypt",
|
||||
lambda value: "upstream-key",
|
||||
@@ -259,9 +263,9 @@ async def test_video_cancel_service_returns_503_when_rust_executor_unavailable(
|
||||
|
||||
monkeypatch.setattr(cancel_mod.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
rust_client_mod.RustExecutorClient,
|
||||
runtime_client_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
AsyncMock(side_effect=rust_client_mod.RustExecutorClientError("executor down")),
|
||||
AsyncMock(side_effect=runtime_client_mod.ExecutionRuntimeClientError("executor down")),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"src.core.crypto.crypto_service.decrypt",
|
||||
|
||||
@@ -6,7 +6,7 @@ import pytest
|
||||
|
||||
from src.core.api_format.conversion.internal_video import InternalVideoPollResult, VideoStatus
|
||||
from src.models.database import VideoTask
|
||||
from src.services.request.rust_executor_client import RustExecutorSyncResult
|
||||
from src.services.request.execution_runtime_client import ExecutionRuntimeSyncResult
|
||||
from src.services.task.video.poller_adapter import VideoPollContext, VideoTaskPollerAdapter
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ async def test_update_task_after_poll_skips_terminal_cancelled_task(
|
||||
async def test_video_poller_try_rust_payload_passes_proxy_snapshot(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.services.request import rust_executor_client as rust_mod
|
||||
from src.services.request import execution_runtime_client as runtime_mod
|
||||
from src.services.task.video import poller_adapter as mod
|
||||
|
||||
adapter = VideoTaskPollerAdapter()
|
||||
@@ -90,11 +90,18 @@ async def test_video_poller_try_rust_payload_passes_proxy_snapshot(
|
||||
proxy_snapshot = object()
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> RustExecutorSyncResult:
|
||||
async def _fake_execute_sync_json(self: object, plan: object) -> ExecutionRuntimeSyncResult:
|
||||
captured["plan"] = plan
|
||||
return RustExecutorSyncResult(status_code=200, response_json={"id": "op_1", "done": False})
|
||||
return ExecutionRuntimeSyncResult(
|
||||
status_code=200,
|
||||
response_json={"id": "op_1", "done": False},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_mod.RustExecutorClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
monkeypatch.setattr(
|
||||
runtime_mod.ExecutionRuntimeClient,
|
||||
"execute_sync_json",
|
||||
_fake_execute_sync_json,
|
||||
)
|
||||
|
||||
ctx = VideoPollContext(
|
||||
task_id="task-1",
|
||||
|
||||
@@ -9,6 +9,11 @@ def test_executor_config_defaults_to_rust_and_unix_socket(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
for key in (
|
||||
"EXECUTION_RUNTIME_BACKEND",
|
||||
"EXECUTION_RUNTIME_TRANSPORT",
|
||||
"EXECUTION_RUNTIME_SOCKET_PATH",
|
||||
"EXECUTION_RUNTIME_BASE_URL",
|
||||
"EXECUTION_RUNTIME_REQUEST_TIMEOUT",
|
||||
"EXECUTOR_BACKEND",
|
||||
"EXECUTOR_TRANSPORT",
|
||||
"EXECUTOR_SOCKET_PATH",
|
||||
@@ -20,6 +25,11 @@ def test_executor_config_defaults_to_rust_and_unix_socket(
|
||||
|
||||
cfg = Config()
|
||||
|
||||
assert cfg.execution_runtime_backend == "rust"
|
||||
assert cfg.execution_runtime_transport == "unix_socket"
|
||||
assert cfg.execution_runtime_socket_path == "/tmp/aether-executor.sock"
|
||||
assert cfg.execution_runtime_base_url == "http://127.0.0.1:5219"
|
||||
assert cfg.execution_runtime_request_timeout == cfg.http_request_timeout
|
||||
assert cfg.executor_backend == "rust"
|
||||
assert cfg.executor_transport == "unix_socket"
|
||||
assert cfg.executor_socket_path == "/tmp/aether-executor.sock"
|
||||
@@ -28,16 +38,42 @@ def test_executor_config_defaults_to_rust_and_unix_socket(
|
||||
|
||||
|
||||
def test_executor_config_accepts_env_override(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("EXECUTOR_BACKEND", "RUST")
|
||||
monkeypatch.setenv("EXECUTOR_TRANSPORT", "TCP")
|
||||
monkeypatch.setenv("EXECUTOR_SOCKET_PATH", "/var/run/aether.sock")
|
||||
monkeypatch.setenv("EXECUTOR_BASE_URL", "http://127.0.0.1:9311")
|
||||
monkeypatch.setenv("EXECUTOR_REQUEST_TIMEOUT", "12.5")
|
||||
monkeypatch.setenv("EXECUTION_RUNTIME_BACKEND", "RUST")
|
||||
monkeypatch.setenv("EXECUTION_RUNTIME_TRANSPORT", "TCP")
|
||||
monkeypatch.setenv("EXECUTION_RUNTIME_SOCKET_PATH", "/var/run/aether.sock")
|
||||
monkeypatch.setenv("EXECUTION_RUNTIME_BASE_URL", "http://127.0.0.1:9311")
|
||||
monkeypatch.setenv("EXECUTION_RUNTIME_REQUEST_TIMEOUT", "12.5")
|
||||
|
||||
cfg = Config()
|
||||
|
||||
assert cfg.execution_runtime_backend == "rust"
|
||||
assert cfg.execution_runtime_transport == "tcp"
|
||||
assert cfg.execution_runtime_socket_path == "/var/run/aether.sock"
|
||||
assert cfg.execution_runtime_base_url == "http://127.0.0.1:9311"
|
||||
assert cfg.execution_runtime_request_timeout == 12.5
|
||||
assert cfg.executor_backend == "rust"
|
||||
assert cfg.executor_transport == "tcp"
|
||||
assert cfg.executor_socket_path == "/var/run/aether.sock"
|
||||
assert cfg.executor_base_url == "http://127.0.0.1:9311"
|
||||
assert cfg.executor_request_timeout == 12.5
|
||||
|
||||
|
||||
def test_executor_config_legacy_envs_still_work(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("EXECUTOR_BACKEND", "RUST")
|
||||
monkeypatch.setenv("EXECUTOR_TRANSPORT", "TCP")
|
||||
monkeypatch.setenv("EXECUTOR_SOCKET_PATH", "/tmp/legacy-aether.sock")
|
||||
monkeypatch.setenv("EXECUTOR_BASE_URL", "http://127.0.0.1:9322")
|
||||
monkeypatch.setenv("EXECUTOR_REQUEST_TIMEOUT", "14.5")
|
||||
|
||||
cfg = Config()
|
||||
|
||||
assert cfg.execution_runtime_backend == "rust"
|
||||
assert cfg.execution_runtime_transport == "tcp"
|
||||
assert cfg.execution_runtime_socket_path == "/tmp/legacy-aether.sock"
|
||||
assert cfg.execution_runtime_base_url == "http://127.0.0.1:9322"
|
||||
assert cfg.execution_runtime_request_timeout == 14.5
|
||||
assert cfg.executor_backend == "rust"
|
||||
assert cfg.executor_transport == "tcp"
|
||||
assert cfg.executor_socket_path == "/tmp/legacy-aether.sock"
|
||||
assert cfg.executor_base_url == "http://127.0.0.1:9322"
|
||||
assert cfg.executor_request_timeout == 14.5
|
||||
|
||||
@@ -2,14 +2,14 @@ from __future__ import annotations
|
||||
|
||||
import base64
|
||||
|
||||
from src.services.request.executor_plan import PreparedExecutionPlan
|
||||
from src.services.request.executor_plan import (
|
||||
from src.services.request.execution_runtime_plan import PreparedExecutionPlan
|
||||
from src.services.request.execution_runtime_plan import (
|
||||
ExecutionPlan,
|
||||
ExecutionPlanBody,
|
||||
ExecutionPlanTimeouts,
|
||||
ExecutionProxySnapshot,
|
||||
build_execution_plan_body,
|
||||
should_bypass_remote_executor_url,
|
||||
should_bypass_remote_execution_runtime_url,
|
||||
)
|
||||
|
||||
|
||||
@@ -374,9 +374,9 @@ def test_prepared_execution_plan_remote_eligible_rejects_codex_cli_transport() -
|
||||
assert prepared.remote_eligible is False
|
||||
|
||||
|
||||
def test_should_bypass_remote_executor_url_accepts_backendapi_codex_variant() -> None:
|
||||
def test_should_bypass_remote_execution_runtime_url_accepts_backendapi_codex_variant() -> None:
|
||||
assert (
|
||||
should_bypass_remote_executor_url(
|
||||
should_bypass_remote_execution_runtime_url(
|
||||
"https://chatgpt.com/backendapi/codex/responses",
|
||||
provider_api_format="openai:cli",
|
||||
client_api_format="openai:cli",
|
||||
|
||||
@@ -7,8 +7,8 @@ from typing import Any
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from src.services.proxy_node.hub_config import HubConfig
|
||||
from src.services.proxy_node.hub_transport import HubTunnelTransport
|
||||
from src.services.proxy_node.gateway_tunnel_transport import GatewayTunnelTransport
|
||||
from src.services.proxy_node.tunnel_config import TunnelRelayConfig
|
||||
|
||||
|
||||
class _FakeRelayClient:
|
||||
@@ -31,19 +31,22 @@ class _FakeRelayClient:
|
||||
return None
|
||||
|
||||
|
||||
def _relay_config() -> HubConfig:
|
||||
return HubConfig(
|
||||
def _relay_config() -> TunnelRelayConfig:
|
||||
return TunnelRelayConfig(
|
||||
enabled=True,
|
||||
url="http://127.0.0.1:8085",
|
||||
url="http://127.0.0.1:8084",
|
||||
connect_timeout_seconds=1.0,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_transport_encodes_local_relay_envelope(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
transport = HubTunnelTransport("node-1", timeout=12.0)
|
||||
transport = GatewayTunnelTransport("node-1", timeout=12.0)
|
||||
fake_client = _FakeRelayClient(httpx.Response(200, content=b"ok"))
|
||||
monkeypatch.setattr("src.services.proxy_node.hub_transport.get_hub_config", _relay_config)
|
||||
monkeypatch.setattr(
|
||||
"src.services.proxy_node.gateway_tunnel_transport.get_tunnel_relay_config",
|
||||
_relay_config,
|
||||
)
|
||||
monkeypatch.setattr(transport, "_relay_client", fake_client)
|
||||
|
||||
request = httpx.Request(
|
||||
@@ -75,7 +78,7 @@ async def test_transport_encodes_local_relay_envelope(monkeypatch: pytest.Monkey
|
||||
async def test_transport_maps_relay_timeout_to_read_timeout(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
transport = HubTunnelTransport("node-1", timeout=12.0)
|
||||
transport = GatewayTunnelTransport("node-1", timeout=12.0)
|
||||
fake_client = _FakeRelayClient(
|
||||
httpx.Response(
|
||||
504,
|
||||
@@ -83,7 +86,10 @@ async def test_transport_maps_relay_timeout_to_read_timeout(
|
||||
content=b"relay timed out",
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr("src.services.proxy_node.hub_transport.get_hub_config", _relay_config)
|
||||
monkeypatch.setattr(
|
||||
"src.services.proxy_node.gateway_tunnel_transport.get_tunnel_relay_config",
|
||||
_relay_config,
|
||||
)
|
||||
monkeypatch.setattr(transport, "_relay_client", fake_client)
|
||||
|
||||
request = httpx.Request("GET", "https://example.com")
|
||||
@@ -96,9 +102,12 @@ async def test_transport_maps_relay_timeout_to_read_timeout(
|
||||
async def test_transport_streams_request_body_from_async_generator(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
transport = HubTunnelTransport("node-1", timeout=12.0)
|
||||
transport = GatewayTunnelTransport("node-1", timeout=12.0)
|
||||
fake_client = _FakeRelayClient(httpx.Response(200, content=b"ok"))
|
||||
monkeypatch.setattr("src.services.proxy_node.hub_transport.get_hub_config", _relay_config)
|
||||
monkeypatch.setattr(
|
||||
"src.services.proxy_node.gateway_tunnel_transport.get_tunnel_relay_config",
|
||||
_relay_config,
|
||||
)
|
||||
monkeypatch.setattr(transport, "_relay_client", fake_client)
|
||||
|
||||
async def body() -> Any:
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services.proxy_node.hub_transport import HubRelayResponseStream
|
||||
from src.services.proxy_node.gateway_tunnel_transport import TunnelRelayResponseStream
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
@@ -19,9 +19,9 @@ class _FakeResponse:
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hub_relay_response_stream_closes_after_iteration() -> None:
|
||||
async def test_tunnel_relay_response_stream_closes_after_iteration() -> None:
|
||||
response = _FakeResponse([b"hello", b"world"])
|
||||
stream = HubRelayResponseStream(response) # type: ignore[arg-type]
|
||||
stream = TunnelRelayResponseStream(response) # type: ignore[arg-type]
|
||||
|
||||
chunks = []
|
||||
async for chunk in stream:
|
||||
@@ -32,9 +32,9 @@ async def test_hub_relay_response_stream_closes_after_iteration() -> None:
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hub_relay_response_stream_aclose_closes_response() -> None:
|
||||
async def test_tunnel_relay_response_stream_aclose_closes_response() -> None:
|
||||
response = _FakeResponse([])
|
||||
stream = HubRelayResponseStream(response) # type: ignore[arg-type]
|
||||
stream = TunnelRelayResponseStream(response) # type: ignore[arg-type]
|
||||
|
||||
await stream.aclose()
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
from src.services.proxy_node.hub_config import HubConfig
|
||||
|
||||
|
||||
def test_local_relay_url_uses_http_path() -> None:
|
||||
config = HubConfig(
|
||||
enabled=True,
|
||||
url="http://127.0.0.1:8085",
|
||||
connect_timeout_seconds=1.0,
|
||||
)
|
||||
|
||||
assert (
|
||||
config.local_relay_url("node a/1")
|
||||
== "http://127.0.0.1:8085/local/relay/node%20a%2F1"
|
||||
)
|
||||
14
tests/unit/test_tunnel_config.py
Normal file
14
tests/unit/test_tunnel_config.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from src.services.proxy_node.tunnel_config import TunnelRelayConfig
|
||||
|
||||
|
||||
def test_local_relay_url_uses_http_path() -> None:
|
||||
config = TunnelRelayConfig(
|
||||
enabled=True,
|
||||
url="http://127.0.0.1:8084",
|
||||
connect_timeout_seconds=1.0,
|
||||
)
|
||||
|
||||
assert (
|
||||
config.local_relay_url("node a/1")
|
||||
== "http://127.0.0.1:8084/api/internal/tunnel/relay/node%20a%2F1"
|
||||
)
|
||||
@@ -1,11 +1,11 @@
|
||||
from src.services.proxy_node.hub_transport import HubTunnelTransport
|
||||
from src.services.proxy_node.gateway_tunnel_transport import GatewayTunnelTransport
|
||||
from src.services.proxy_node.tunnel_protocol import Frame, MsgType
|
||||
from src.services.proxy_node.tunnel_transport import create_tunnel_transport
|
||||
|
||||
|
||||
def test_create_tunnel_transport_always_uses_hub_transport() -> None:
|
||||
def test_create_tunnel_transport_always_uses_gateway_tunnel_transport() -> None:
|
||||
transport = create_tunnel_transport("node-1", timeout=12.0)
|
||||
assert isinstance(transport, HubTunnelTransport)
|
||||
assert isinstance(transport, GatewayTunnelTransport)
|
||||
|
||||
|
||||
def test_tunnel_protocol_supports_node_status_msg_type() -> None:
|
||||
Reference in New Issue
Block a user