From de2b482ab8f02aa009e05c83b1dd014a17cccde6 Mon Sep 17 00:00:00 2001 From: Brian Krabach Date: Fri, 25 Sep 2026 03:43:45 -0700 Subject: [PATCH 1/2] Support per-file relative mention resolution --- .../lib/mention_loading/app_resolver.py | 7 +++++++ tests/lib/mention_loading/test_resolver.py | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/amplifier_app_cli/lib/mention_loading/app_resolver.py b/amplifier_app_cli/lib/mention_loading/app_resolver.py index 232c3fe3..89562c3e 100644 --- a/amplifier_app_cli/lib/mention_loading/app_resolver.py +++ b/amplifier_app_cli/lib/mention_loading/app_resolver.py @@ -10,6 +10,7 @@ from __future__ import annotations import logging +from copy import copy from pathlib import Path from typing import TYPE_CHECKING from typing import Protocol @@ -126,6 +127,12 @@ def resolve(self, mention: str) -> Path | None: # === RELATIVE PATHS === return self._resolve_relative(mention) + def resolve_relative(self, mention: str, relative_to: Path) -> Path | None: + """Scope local paths for one load without changing shortcut roots/state.""" + scoped = copy(self) + scoped.relative_to = relative_to + return scoped.resolve(mention) + def _resolve_user(self, mention: str) -> Path | None: """Resolve @user:path → ~/.amplifier/{path}.""" path = mention[6:] # Remove "@user:" diff --git a/tests/lib/mention_loading/test_resolver.py b/tests/lib/mention_loading/test_resolver.py index c25a34b6..fc61fbd2 100644 --- a/tests/lib/mention_loading/test_resolver.py +++ b/tests/lib/mention_loading/test_resolver.py @@ -62,6 +62,23 @@ def test_resolver_relative_to(temp_context_dirs): assert path.read_text() == "relative content" +def test_per_call_relative_scope_preserves_shortcuts_and_policy(tmp_path, monkeypatch): + workspace, nested, user, bundle = (tmp_path / name for name in ("workspace", "nested", "user", "bundle")) + for path in (workspace / ".amplifier", nested, user, bundle): + path.mkdir(parents=True) + (path / "rules.md").write_text(str(path)) + monkeypatch.chdir(workspace) + monkeypatch.setenv("AMPLIFIER_HOME", str(user)) + resolver = AppMentionResolver(bundle_mappings={"bundle": bundle}) + assert resolver.resolve_relative("@./rules.md", nested) == nested / "rules.md" + assert resolver.resolve_relative("@project:rules.md", nested) == workspace / ".amplifier/rules.md" + assert resolver.resolve_relative("@user:rules.md", nested) == user / "rules.md" + assert resolver.resolve_relative("@bundle:rules.md", nested) == bundle / "rules.md" + assert resolver.resolve_relative("@../rules.md", nested) is None + assert resolver.relative_to is None + assert resolver.resolve("@./rules.md") is None + + def test_resolver_relative_path_syntax(temp_context_dirs, monkeypatch): """Test ./relative.md syntax with relative_to.""" base_dir = temp_context_dirs["bundled"] From 0f7b5a89248296ff43f3abd4b4c06e44c754348b Mon Sep 17 00:00:00 2001 From: Brian Krabach Date: Fri, 25 Sep 2026 06:03:12 -0700 Subject: [PATCH 2/2] Adopt merged Foundation nested-reference resolution --- tests/lib/mention_loading/test_resolver.py | 19 +++++++++++++++++++ uv.lock | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/lib/mention_loading/test_resolver.py b/tests/lib/mention_loading/test_resolver.py index fc61fbd2..18127dce 100644 --- a/tests/lib/mention_loading/test_resolver.py +++ b/tests/lib/mention_loading/test_resolver.py @@ -62,6 +62,25 @@ def test_resolver_relative_to(temp_context_dirs): assert path.read_text() == "relative content" +@pytest.mark.asyncio +async def test_installed_foundation_expands_nested_references_with_app_policy(tmp_path, monkeypatch): + """Exercise the installed dependency, not only the resolver adapter method.""" + from amplifier_foundation.mentions import ContentDeduplicator, load_mentions + + monkeypatch.chdir(tmp_path) + (tmp_path / "rules").mkdir() + (tmp_path / "rules/AGENTS.md").write_text("Follow @./tasks.md and @workspace.md") + (tmp_path / "rules/tasks.md").write_text("NESTED TASKS") + (tmp_path / "tasks.md").write_text("WRONG WORKSPACE TASKS") + (tmp_path / "workspace.md").write_text("WORKSPACE RULE") + dedup = ContentDeduplicator() + await load_mentions("@rules/AGENTS.md", AppMentionResolver(), dedup) + contents = {entry.content for entry in dedup.get_unique_files()} + assert "NESTED TASKS" in contents + assert "WORKSPACE RULE" in contents + assert "WRONG WORKSPACE TASKS" not in contents + + def test_per_call_relative_scope_preserves_shortcuts_and_policy(tmp_path, monkeypatch): workspace, nested, user, bundle = (tmp_path / name for name in ("workspace", "nested", "user", "bundle")) for path in (workspace / ".amplifier", nested, user, bundle): diff --git a/uv.lock b/uv.lock index 6c6717a5..679bc8aa 100644 --- a/uv.lock +++ b/uv.lock @@ -72,7 +72,7 @@ wheels = [ [[package]] name = "amplifier-foundation" version = "1.0.0" -source = { git = "https://github.com/microsoft/amplifier-foundation?rev=main#52dec7e276db62f720448c8e2ec176b9cbffde2d" } +source = { git = "https://github.com/microsoft/amplifier-foundation?rev=main#89575c3482e3e8afe5a03df72e723cf815fa1f6c" } dependencies = [ { name = "amplifier-core" }, { name = "filelock" },