Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/tau_coding/extensions/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from tau_coding.extensions.providers import DynamicProvider
from tau_coding.extensions.runtime import ExtensionRuntime
from tau_coding.local_backends import LocalBackend
from tau_coding.paths import TauPaths
from tau_coding.tui.config import TuiTheme

AGENT_EVENT_TYPES: frozenset[str] = frozenset(
Expand Down Expand Up @@ -890,6 +891,12 @@ def cwd(self) -> Path:
self._generation.assert_active()
return self._runtime.session_view.cwd

@property
def paths(self) -> TauPaths:
"""Return the resolved Tau filesystem paths for this session."""
self._generation.assert_active()
return self._runtime.paths

@property
def model(self) -> str:
"""Return the active model name."""
Expand Down
7 changes: 7 additions & 0 deletions src/tau_coding/extensions/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def __init__(
self._renderer_failures_reported: set[str] = set()
self._load_diagnostics: list[ResourceDiagnostic] = []
self._runtime_diagnostics: list[ResourceDiagnostic] = []
self._paths: TauPaths = TauPaths()
self._session: BoundSession | None = None
self._ui: UiBridge = ui or NullUiBridge()
self._turn_requested: TurnRequestedCallback | None = None
Expand All @@ -266,6 +267,7 @@ def load(
include_user_dir: bool = True,
) -> None:
"""Load built-ins, then discover extensions and run isolated setup."""
self._paths = paths.paths or TauPaths(home=paths.root)
self._load_built_ins()
result = load_extensions(
paths,
Expand Down Expand Up @@ -851,6 +853,11 @@ def local_backend_registry(self) -> LocalBackendRegistry:
"""Return this staged runtime generation's local-backend registry."""
return self._local_backend_registry

@property
def paths(self) -> TauPaths:
"""Return the resolved Tau filesystem paths for this runtime."""
return self._paths

@property
def extension_names(self) -> tuple[str, ...]:
"""Return visible extension names in load order."""
Expand Down
31 changes: 31 additions & 0 deletions tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,25 @@ async def executor(
return AgentTool(name=name, label=name, description="d", parameters={}, execute_fn=executor)


def test_context_paths_exposes_resolved_paths_from_load(tmp_path: Path) -> None:
runtime = ExtensionRuntime()
resolved = TauPaths(home=tmp_path / "custom-home")
runtime.load(TauResourcePaths(root=tmp_path / "unused-root", paths=resolved))
api = cast(ExtensionAPI, _register_inline_extension(runtime, "reader"))
runtime.bind(RecordingSession(tmp_path))

assert api.context.paths is resolved


def test_context_paths_falls_back_to_resource_root_home(tmp_path: Path) -> None:
runtime = ExtensionRuntime()
runtime.load(TauResourcePaths(root=tmp_path / "home-tau"))
api = cast(ExtensionAPI, _register_inline_extension(runtime, "reader"))
runtime.bind(RecordingSession(tmp_path))

assert api.context.paths.home == tmp_path / "home-tau"


# -- coding-session integration ---------------------------------------------------


Expand Down Expand Up @@ -2060,6 +2079,16 @@ async def test_session_lifecycle_recreates_built_in_in_a_fresh_generation(
await session.aclose()


async def test_session_exposes_extension_paths_at_moved_home(tmp_path: Path) -> None:
await CodingSession.load(
_session_config(tmp_path, FakeProvider([]), extension_body=API_CAPTURING_EXTENSION)
)
module = _loaded_extension_module("integration")
api = cast(ExtensionAPI, module.APIS[-1]) # type: ignore[attr-defined]

assert api.context.paths.home == tmp_path / "home-tau"


async def test_session_exposes_extension_tools_and_commands(tmp_path: Path) -> None:
body = HELLO_TOOL_EXTENSION + (
"\n\ndef _cmd(args, context):\n"
Expand Down Expand Up @@ -2871,6 +2900,8 @@ async def test_reset_for_reload_invalidates_prior_context_and_ui(tmp_path: Path)

with pytest.raises(ExtensionError, match="stale after reload"):
_ = context.cwd
with pytest.raises(ExtensionError, match="stale after reload"):
_ = context.paths
with pytest.raises(ExtensionError, match="stale after reload"):
_ = context.transcript
with pytest.raises(ExtensionError, match="stale after reload"):
Expand Down