test_internal_runtime.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. from __future__ import annotations
  2. from pathlib import Path
  3. from typing import Any
  4. import pytest
  5. from pydantic import SecretStr
  6. from script_build_host.agents.model_manifest import resolve_script_role_model_manifest
  7. from script_build_host.agents.prompts import (
  8. phase_three_prompt_manifest,
  9. script_build_prompt_manifest,
  10. )
  11. from script_build_host.domain.records import Principal
  12. from script_build_host.infrastructure.config import ScriptBuildSettings
  13. from script_build_host.internal_runtime import (
  14. InternalBuildAuthorizer,
  15. InternalPrincipalProvider,
  16. create_internal_runtime,
  17. )
  18. def _settings(tmp_path: Path, **overrides: Any) -> ScriptBuildSettings:
  19. values: dict[str, Any] = {
  20. "environment": "test",
  21. "read_database_url": f"sqlite+aiosqlite:///{tmp_path / 'read.db'}",
  22. "write_database_url": f"sqlite+aiosqlite:///{tmp_path / 'write.db'}",
  23. "agent_data_root": tmp_path / "agent-data",
  24. "persona_root": tmp_path / "persona",
  25. "section_pattern_root": tmp_path / "sections",
  26. "decode_index_root": tmp_path / "decode",
  27. "knowledge_root": tmp_path / "knowledge.json",
  28. "prompt_fallback_root": tmp_path / "prompts",
  29. "role_model": "qwen3.7-max",
  30. "embedding_api_key": SecretStr("secret"),
  31. }
  32. values.update(overrides)
  33. return ScriptBuildSettings(**values)
  34. def test_role_model_manifest_covers_frozen_prompt_catalog_and_keeps_overrides() -> None:
  35. result = resolve_script_role_model_manifest(
  36. {
  37. "embedding_model": "text-embedding-v4",
  38. "presets": {"script_root_validator": {"temperature": 0.1}},
  39. },
  40. model="qwen3.7-max",
  41. max_iterations=120,
  42. )
  43. presets = result["presets"]
  44. assert isinstance(presets, dict)
  45. required = {
  46. str(item["preset"])
  47. for item in (*script_build_prompt_manifest(), *phase_three_prompt_manifest())
  48. }
  49. assert set(presets) == required
  50. assert presets["script_context_broker"]["temperature"] == 0.0
  51. assert {value["model"] for value in presets.values()} == {"qwen3.7-max"}
  52. assert presets["script_root_validator"]["temperature"] == 0.0
  53. assert presets["script_planner"]["max_iterations"] == 100
  54. assert presets["script_direction_worker"]["max_iterations"] == 20
  55. assert presets["script_root_validator"]["max_iterations"] == 25
  56. assert presets["script_direction_worker"]["temperature"] == 0.2
  57. assert result["embedding_model"] == "text-embedding-v4"
  58. @pytest.mark.asyncio
  59. async def test_internal_auth_is_fixed_and_rejected_for_invalid_builds() -> None:
  60. provider = InternalPrincipalProvider(" internal-e2e ")
  61. principal = await provider.current(object())
  62. assert principal == Principal("internal-e2e")
  63. authorizer = InternalBuildAuthorizer()
  64. await authorizer.require_source_access(principal, execution_id=1, topic_build_id=2, topic_id=3)
  65. await authorizer.require_access(principal, 1)
  66. with pytest.raises(PermissionError):
  67. await authorizer.require_access(principal, 0)
  68. def test_internal_runtime_uses_qwen_and_fails_closed_outside_test(
  69. tmp_path: Path, monkeypatch: pytest.MonkeyPatch
  70. ) -> None:
  71. received: dict[str, Any] = {}
  72. def fake_qwen(**kwargs: Any) -> Any:
  73. received.update(kwargs)
  74. async def call(**_call: Any) -> dict[str, Any]:
  75. return {"content": "unused", "finish_reason": "stop"}
  76. return call
  77. monkeypatch.setattr("script_build_host.internal_runtime.create_qwen_llm_call", fake_qwen)
  78. settings = _settings(tmp_path)
  79. runtime = create_internal_runtime(settings)
  80. assert runtime.runner.trace_store is not None
  81. assert received == {
  82. "model": "qwen3.7-max",
  83. "base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
  84. "api_key": "secret",
  85. "enable_thinking": False,
  86. "request_timeout_seconds": 300.0,
  87. "max_retries": 2,
  88. }
  89. with pytest.raises(RuntimeError, match="only in test"):
  90. create_internal_runtime(
  91. _settings(
  92. tmp_path,
  93. environment="production",
  94. read_database_url="mysql+asyncmy://reader:r@db.example/app",
  95. read_database_socks_proxy=None,
  96. write_database_url="mysql+asyncmy://runtime:r@db.example/app",
  97. final_database_url="mysql+asyncmy://publisher:r@db.example/app",
  98. )
  99. )