mirror of
https://github.com/TencentCloud/Octop.git
synced 2026-10-21 06:29:24 +08:00
* refactor(agents): group thin modules into domain subpackages Move plugin helpers, memory, settings stores, persona/MBTI, and avatar bootstrap code under plugins/, memory/, settings/, persona/, and experts/ while keeping top-level import shims so existing call sites stay stable. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(agents): drop compatibility shims after subpackage move Call sites already import the new package paths; remove the top-level re-export stubs so the agents tree only shows real modules. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(agents): move thread helpers into threads/ Group artifact shaping, fork, and context breakdown under agents/threads so top-level only keeps lifecycle/config adapters. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(agents): fold profile/runtime/tool catalog into settings/ Move the remaining config-surface helpers under settings/ and drop the skill_package id-list aliases in favor of dump/parse_id_list. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(agents): group workspace_dir and execute_env under workspace/ Keep path resolution and harness execute-env injection together as one workspace package; leave only manager and conversation_mode at top level. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(infra): fix history/SkillHub ownership and drop thin providers/ Move history_projection under history/, share SkillHub host/limits and route expert skill downloads through skills.skillhub_market, and fold Codex OAuth helpers into agents.providers to remove the tiny providers/ package. Co-authored-by: Cursor <cursoragent@cursor.com> * docs: sync AGENTS.md and guides with infra/agents layout Reflect subpackages (settings/workspace/threads/persona, history/, skills/) and drop stale runtime.py / mbti_profiles paths after the agents reorg. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: jubaoliang <jubaoliang@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
"""Unit tests for Langfuse settings store."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import urllib.request
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
from octop.infra.agents.settings.langfuse import LangfuseSettingsStore, verify_langfuse_credentials
|
|
from octop.infra.db.migrate import run_migrations
|
|
from octop.infra.db.pool import SqlitePool
|
|
from octop.infra.db.repos.secrets import SecretRepo
|
|
from octop.infra.db.repos.settings import SettingsRepo
|
|
from octop.infra.errors import OctopError
|
|
|
|
|
|
@pytest.fixture
|
|
def store(tmp_path: Path) -> LangfuseSettingsStore:
|
|
db = SqlitePool(tmp_path / "octop.db")
|
|
run_migrations(db)
|
|
return LangfuseSettingsStore(settings_repo=SettingsRepo(db), secret_repo=SecretRepo(db))
|
|
|
|
|
|
def test_langfuse_settings_roundtrip(store: LangfuseSettingsStore) -> None:
|
|
cfg = store.save(
|
|
enabled=True,
|
|
public_key="pk-test",
|
|
host="http://langfuse.example",
|
|
secret_key="sk-test",
|
|
)
|
|
assert cfg.enabled is True
|
|
assert cfg.public_key == "pk-test"
|
|
assert cfg.host == "http://langfuse.example"
|
|
assert cfg.secret_key_set is True
|
|
|
|
loaded = store.load()
|
|
assert loaded.enabled is True
|
|
assert loaded.public_key == "pk-test"
|
|
assert loaded.configured is True
|
|
|
|
|
|
def test_langfuse_requires_secret_when_enabling(store: LangfuseSettingsStore) -> None:
|
|
with pytest.raises(OctopError):
|
|
store.save(enabled=True, public_key="pk", host="http://x")
|
|
|
|
|
|
def test_langfuse_harness_config(store: LangfuseSettingsStore) -> None:
|
|
from octop_harness.observability.langfuse import LangfuseConfig
|
|
|
|
assert store.harness_config() == LangfuseConfig(enabled=False)
|
|
store.save(
|
|
enabled=True,
|
|
public_key="pk-test",
|
|
host="http://langfuse.example",
|
|
secret_key="sk-test",
|
|
)
|
|
hc = store.harness_config()
|
|
assert isinstance(hc, LangfuseConfig)
|
|
assert hc.enabled is True
|
|
assert hc.public_key == "pk-test"
|
|
assert hc.host == "http://langfuse.example"
|
|
assert hc.secret_key == "sk-test"
|
|
|
|
|
|
def test_verify_langfuse_credentials_accepts_legacy_project_shape() -> None:
|
|
payload = json.dumps({"data": [{"id": "proj-1", "name": "octop", "metadata": {}}]}).encode()
|
|
|
|
class _Resp:
|
|
status = 200
|
|
|
|
def read(self) -> bytes:
|
|
return payload
|
|
|
|
def __enter__(self) -> _Resp:
|
|
return self
|
|
|
|
def __exit__(self, *args: object) -> None:
|
|
return None
|
|
|
|
def fake_urlopen(req: urllib.request.Request, timeout: float = 15) -> _Resp:
|
|
assert req.get_method() == "GET"
|
|
assert req.full_url.endswith("/api/public/projects")
|
|
auth = req.headers["Authorization"]
|
|
assert auth.startswith("Basic ")
|
|
return _Resp()
|
|
|
|
with mock.patch("urllib.request.urlopen", fake_urlopen):
|
|
result = verify_langfuse_credentials("http://langfuse.example", "pk", "sk")
|
|
|
|
assert result == {"ok": True}
|