From 3fbe170e9f1d65553e7c7fb961ff7911c4ed453e Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 10 Jun 2026 15:39:00 +0100 Subject: [PATCH 1/4] fix(hook-context-intelligence): install standalone via PEP 508 direct git reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hook's pyproject.toml declared amplifier-bundle-context-intelligence as a bare-name dependency, resolvable only via [tool.uv.sources] path = "../.." (monorepo-only). When agents install modules with `uv pip install --no-sources`, this path override is stripped, causing install failure (Blocker 1: 'No solution found'). Additionally, config_resolver.py imports from context_intelligence, which requires the bundle on sys.path (Blocker 2: ModuleNotFoundError). Fix applies three changes to modules/hook-context-intelligence/pyproject.toml: 1. Changed bare dependency to PEP 508 direct git reference in [project.dependencies]: 'amplifier-bundle-context-intelligence @ git+https://github.com/microsoft/amplifier-bundle-context-intelligence@v0.1.1' Direct-URL references in [project.dependencies] survive `--no-sources` (unlike [tool.uv.sources] entries), so install resolves and the bundle lands on sys.path. 2. Added [tool.hatch.metadata] allow-direct-references = true (required for hatchling to build a wheel carrying a direct-URL dependency). 3. Removed the 'amplifier-bundle-context-intelligence = { path = "../.." }' entry from [tool.uv.sources], so the module installs identically in-monorepo and standalone. Bumped version 0.1.1 -> 0.1.2. Validation in clean Python 3.11 venv: `uv pip install --no-sources` on the hook module resolved 9 packages, built the wheel, fetched the bundle from git@v0.1.1, and installed successfully (exit 0). Confirmed imports from context_intelligence work; hook config_resolver imports OK; context_intelligence loads from venv site-packages (not ../.. path). Both blockers proven fixed. This follows the one-change approach agreed in microsoft-amplifier/amplifier-support#269 and feedback from Brian: prefer git+https direct reference over vendoring (which carries drift/maintenance cost). Intentionally scoped as the small standalone-install bug fix, separate from the larger behavior-split work in PR #27. Note: the same path = "../.." pattern exists in three sibling tool modules (tool-graph-query, tool-blob-read, tool-context-intelligence-upload) and can receive the same one-line fix later if/when they need standalone install. πŸ€– Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- modules/hook-context-intelligence/pyproject.toml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/hook-context-intelligence/pyproject.toml b/modules/hook-context-intelligence/pyproject.toml index 375e53b..d8954ad 100644 --- a/modules/hook-context-intelligence/pyproject.toml +++ b/modules/hook-context-intelligence/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "amplifier-module-hook-context-intelligence" -version = "0.1.1" +version = "0.1.2" description = "Context intelligence hook β€” event-driven property graph builder for Amplifier sessions" requires-python = ">=3.11" license = "MIT" @@ -8,7 +8,7 @@ license = "MIT" dependencies = [ "httpx>=0.28.1", "idna>=3.15", - "amplifier-bundle-context-intelligence", + "amplifier-bundle-context-intelligence @ git+https://github.com/microsoft/amplifier-bundle-context-intelligence@v0.1.1", ] [project.entry-points."amplifier.modules"] @@ -24,6 +24,10 @@ package = true [tool.hatch.build.targets.wheel] packages = ["amplifier_module_hook_context_intelligence"] +[tool.hatch.metadata] +# Required to build a wheel that carries a PEP 508 direct-reference (git+https) dependency. +allow-direct-references = true + [dependency-groups] dev = [ "amplifier-core>=1.4.1", @@ -36,7 +40,10 @@ dev = [ [tool.uv.sources] amplifier-core = { git = "https://github.com/microsoft/amplifier-core", rev = "v1.4.1" } -amplifier-bundle-context-intelligence = { path = "../.." } +# Note: the bundle dependency is declared as a PEP 508 direct git reference in +# [project.dependencies] above (survives `uv pip install --no-sources`). It is +# intentionally NOT given a `path = "../.."` source here, so the module installs +# identically inside the monorepo and standalone. [tool.pytest.ini_options] asyncio_mode = "auto" From b93903dbcc859628b97844ca118d2d461c6365f9 Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 10 Jun 2026 16:46:08 +0100 Subject: [PATCH 2/4] fix(context-intelligence): align upload module + invert hook dep tests for standalone install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two CI failures from PR #36 are now fixed: 1. **Hook dependency tests were stale** (test_hook_dependencies.py) The tests still asserted the OLD broken pattern: bare bundle name in [project.dependencies] plus `path = "../.."" in [tool.uv.sources]. The actual pyproject.toml was updated to use a PEP 508 direct git reference. This commit inverts all 4 test assertions to the NEW contract: - Bundle dep is now the direct reference (git+https://…amplifier-bundle-context-intelligence@v0.1.1) - No path source entry for the bundle exists in [tool.uv.sources] - allow-direct-references is enabled in [tool.hatch.metadata] 2. **Upload module had conflicting URLs** (tool-context-intelligence-upload) The upload module depends on the hook AND was still pinning the bundle via `path = "../.."" in [tool.uv.sources]. With the hook now declaring the bundle via a hard PEP 508 direct URL, uv saw two conflicting URLs: - From hook: git+https://github.com/microsoft/…v0.1.1 - From upload: file:///home/runner/work/… This caused the "conflicting URLs for amplifier-bundle-context-intelligence" error in CI. Applied the same direct-git-reference fix to upload's [project.dependencies], added allow-direct-references, removed the bundle path source (kept hook editable path), and bumped version 0.1.0β†’0.1.1. Validation (clean Python 3.11 venvs, reproduced CI scenario): - `uv pip install ` now resolves and installs 10 pkgs successfully (previously failed with conflicting URLs error) - `uv pip install --no-sources ` still succeeds; context_intelligence + config_resolver imports resolve; verified installed from git@v0.1.1 - `pytest tests/test_hook_dependencies.py` β†’ 4 passed Closes both CI failures that turned PR #36 red. πŸ€– Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- .../tests/test_hook_dependencies.py | 77 ++++++++++++++----- .../pyproject.toml | 11 ++- 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/modules/hook-context-intelligence/tests/test_hook_dependencies.py b/modules/hook-context-intelligence/tests/test_hook_dependencies.py index 3a94569..fd56a77 100644 --- a/modules/hook-context-intelligence/tests/test_hook_dependencies.py +++ b/modules/hook-context-intelligence/tests/test_hook_dependencies.py @@ -1,6 +1,13 @@ -"""Test that the hook module pyproject.toml declares the context_intelligence dependency. +"""Test that the hook module pyproject.toml declares the bundle dependency in a +form that installs standalone (outside the monorepo). -TDD: This test is written FIRST and will FAIL until pyproject.toml is updated. +The hook imports from the `context_intelligence` package shipped by the parent +bundle. For the hook to install standalone under the Amplifier agent's +`uv pip install --no-sources` policy, the bundle MUST be referenced as a PEP 508 +direct git reference inside [project.dependencies] (which survives --no-sources), +NOT via a [tool.uv.sources] `path = "../.."` entry (which --no-sources strips). + +See microsoft-amplifier/amplifier-support#269 for the full root-cause analysis. """ from __future__ import annotations @@ -11,43 +18,73 @@ MODULE_ROOT = Path(__file__).parent.parent PYPROJECT = MODULE_ROOT / "pyproject.toml" +BUNDLE = "amplifier-bundle-context-intelligence" + def _load_pyproject() -> dict: return tomllib.loads(PYPROJECT.read_text()) +def _dep_name(dep: str) -> str: + """Extract the bare package name from a requirement string. + + Handles version specifiers (>=, ==) and PEP 508 direct references + (`name @ git+https://...`). + """ + return dep.split("@")[0].split(">=")[0].split("==")[0].strip() + + class TestHookDependencies: - """Verify hook module's pyproject.toml declares amplifier-bundle-context-intelligence.""" + """Verify the hook declares the bundle as a standalone-installable dependency.""" + + def test_bundle_declared_as_direct_git_reference(self) -> None: + """The bundle must be a PEP 508 direct git reference in [project.dependencies]. - def test_amplifier_bundle_context_intelligence_in_dependencies(self) -> None: - """amplifier-bundle-context-intelligence must appear in the dependencies list.""" + A direct `name @ git+https://...` reference survives `--no-sources`, + unlike a bare name (only resolvable from PyPI) or a [tool.uv.sources] entry. + """ data = _load_pyproject() deps: list[str] = data["project"]["dependencies"] - dep_names = [d.split(">=")[0].split("==")[0].strip() for d in deps] - assert "amplifier-bundle-context-intelligence" in dep_names, ( - f"Expected 'amplifier-bundle-context-intelligence' in dependencies, got: {deps}" + bundle_deps = [d for d in deps if _dep_name(d) == BUNDLE] + assert bundle_deps, f"Expected '{BUNDLE}' in dependencies, got: {deps}" + assert "git+https://" in bundle_deps[0], ( + f"Bundle dependency must be a direct git+https reference so it survives " + f"`uv pip install --no-sources`, got: {bundle_deps[0]!r}" ) - def test_uv_sources_has_path_entry_for_bundle(self) -> None: - """[tool.uv.sources] must have path = '../..' for amplifier-bundle-context-intelligence.""" + def test_bundle_is_not_a_uv_path_source(self) -> None: + """The bundle must NOT be a [tool.uv.sources] path entry. + + The `path = '../..'` assumption is exactly what breaks standalone install: + --no-sources strips [tool.uv.sources], leaving an unresolvable reference. + """ data = _load_pyproject() sources: dict = data.get("tool", {}).get("uv", {}).get("sources", {}) - assert "amplifier-bundle-context-intelligence" in sources, ( - f"Expected 'amplifier-bundle-context-intelligence' in [tool.uv.sources], got: {sources}" + assert BUNDLE not in sources, ( + f"'{BUNDLE}' must not be a [tool.uv.sources] entry (breaks standalone " + f"install under --no-sources); declare it as a direct git reference in " + f"[project.dependencies] instead. Got sources: {sources}" ) - entry = sources["amplifier-bundle-context-intelligence"] - assert entry.get("path") == "../..", f"Expected path = '../..', got: {entry}" def test_dependencies_list_has_httpx_and_bundle(self) -> None: - """The production dependencies must include httpx and amplifier-bundle-context-intelligence. - amplifier-core is NOT a production dep β€” it is runtime-provided by the Amplifier CLI. + """Production deps must include httpx and the bundle. + + amplifier-core is NOT a production dep β€” it is runtime-provided by the + Amplifier CLI. """ data = _load_pyproject() deps: list[str] = data["project"]["dependencies"] assert any("httpx" in d for d in deps), f"httpx not found in {deps}" - assert any("amplifier-bundle-context-intelligence" in d for d in deps), ( - f"amplifier-bundle-context-intelligence not found in {deps}" - ) - assert not any("amplifier-core" in d for d in deps), ( + assert any(_dep_name(d) == BUNDLE for d in deps), f"{BUNDLE} not found in {deps}" + assert not any(_dep_name(d) == "amplifier-core" for d in deps), ( f"amplifier-core must not be a production dep (runtime-provided): {deps}" ) + + def test_allow_direct_references_enabled(self) -> None: + """Building a wheel that carries a direct reference requires this hatch flag.""" + data = _load_pyproject() + allow = data.get("tool", {}).get("hatch", {}).get("metadata", {}).get("allow-direct-references") + assert allow is True, ( + "tool.hatch.metadata.allow-direct-references must be true to build a wheel " + f"carrying the direct git reference, got: {allow!r}" + ) diff --git a/modules/tool-context-intelligence-upload/pyproject.toml b/modules/tool-context-intelligence-upload/pyproject.toml index e33c97b..6e3cf3a 100644 --- a/modules/tool-context-intelligence-upload/pyproject.toml +++ b/modules/tool-context-intelligence-upload/pyproject.toml @@ -1,11 +1,11 @@ [project] name = "amplifier-module-tool-context-intelligence-upload" -version = "0.1.0" +version = "0.1.1" requires-python = ">=3.11" license = "MIT" dependencies = [ - "amplifier-bundle-context-intelligence", + "amplifier-bundle-context-intelligence @ git+https://github.com/microsoft/amplifier-bundle-context-intelligence@v0.1.1", "httpx>=0.28.1", "idna>=3.15", "amplifier-module-hook-context-intelligence", @@ -24,6 +24,10 @@ package = true [tool.hatch.build.targets.wheel] packages = ["amplifier_module_tool_context_intelligence_upload"] +[tool.hatch.metadata] +# Required to build a wheel that carries a PEP 508 direct-reference (git+https) dependency. +allow-direct-references = true + [dependency-groups] dev = [ "pytest>=9.0.3", @@ -33,7 +37,8 @@ dev = [ ] [tool.uv.sources] -amplifier-bundle-context-intelligence = { path = "../.." } +# The bundle is declared as a PEP 508 direct git reference in [project.dependencies] +# (survives `uv pip install --no-sources`); it is intentionally NOT a path source here. amplifier-module-hook-context-intelligence = { path = "../hook-context-intelligence", editable = true } [tool.pytest.ini_options] From da00615679def45a2f4fa6e7c031a800a1c28787 Mon Sep 17 00:00:00 2001 From: Colombo D Date: Wed, 10 Jun 2026 16:57:29 +0100 Subject: [PATCH 3/4] fix(context-intelligence): resolve lint formatting and version test failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reformat test_hook_dependencies.py with ruff to fix 'Check formatting' job - Update test_project_version assertion to expect 0.1.1 (matches bumped version) These changes address the two failing CI jobs on PR#36 without requiring additional commits from the contributor. πŸ€– Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- .../hook-context-intelligence/tests/test_hook_dependencies.py | 4 +++- .../tests/test_pyproject_toml.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/hook-context-intelligence/tests/test_hook_dependencies.py b/modules/hook-context-intelligence/tests/test_hook_dependencies.py index fd56a77..56bb2fb 100644 --- a/modules/hook-context-intelligence/tests/test_hook_dependencies.py +++ b/modules/hook-context-intelligence/tests/test_hook_dependencies.py @@ -83,7 +83,9 @@ def test_dependencies_list_has_httpx_and_bundle(self) -> None: def test_allow_direct_references_enabled(self) -> None: """Building a wheel that carries a direct reference requires this hatch flag.""" data = _load_pyproject() - allow = data.get("tool", {}).get("hatch", {}).get("metadata", {}).get("allow-direct-references") + allow = ( + data.get("tool", {}).get("hatch", {}).get("metadata", {}).get("allow-direct-references") + ) assert allow is True, ( "tool.hatch.metadata.allow-direct-references must be true to build a wheel " f"carrying the direct git reference, got: {allow!r}" diff --git a/modules/tool-context-intelligence-upload/tests/test_pyproject_toml.py b/modules/tool-context-intelligence-upload/tests/test_pyproject_toml.py index 447bc62..b0ca63c 100644 --- a/modules/tool-context-intelligence-upload/tests/test_pyproject_toml.py +++ b/modules/tool-context-intelligence-upload/tests/test_pyproject_toml.py @@ -24,7 +24,7 @@ def test_project_name(self): def test_project_version(self): data = _load() - assert data["project"]["version"] == "0.1.0" + assert data["project"]["version"] == "0.1.1" def test_requires_python(self): data = _load() From 637259e5d56a01c5ba73ebc077d335e830c6cd9d Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 10 Jun 2026 16:57:29 +0100 Subject: [PATCH 4/4] fix(context-intelligence): regenerate uv.lock for git-referenced bundle + ruff format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes stale lockfile conflict in CI when running `uv sync --frozen`. ROOT CAUSE: After changing the bundle dependency from a `path = "../.." source entry in pyproject.toml to a PEP 508 direct git reference (`amplifier-bundle-context-intelligence @ git+https://...`), the committed uv.lock files in both modules still pinned the bundle via the old `file:///` path. When CI runs `uv sync --frozen` (strict install from committed locks), uv sees two conflicting URLs for the same package: the old file:// path in the lock + the new git+https in pyproject β€” resolution fails with "Requirements contain conflicting URLs." FIX: 1. Regenerated modules/hook-context-intelligence/uv.lock via `uv lock` β€” now records bundle as git source (rev=v0.1.1), hook bumped to 0.1.2 2. Regenerated modules/tool-context-intelligence-upload/uv.lock via `uv lock` β€” now records bundle as git source, hook pinned to 0.1.2, upload remains 0.1.0 3. Applied ruff format to modules/hook-context-intelligence/tests/test_hook_dependencies.py (whitespace/formatting; assertions unchanged) VALIDATION (evidence): - `uv sync --frozen` in modules/hook-context-intelligence: βœ… PASS (previously failed with conflicting URL) - `uv sync --frozen` in modules/tool-context-intelligence-upload: βœ… PASS (previously failed with conflicting URL) - `ruff check` + `ruff format --check` on test file: βœ… PASS - `pytest modules/hook-context-intelligence/tests/test_hook_dependencies.py`: βœ… 4 passed πŸ€– Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- modules/hook-context-intelligence/uv.lock | 19 +++------------ .../tool-context-intelligence-upload/uv.lock | 23 ++++--------------- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/modules/hook-context-intelligence/uv.lock b/modules/hook-context-intelligence/uv.lock index b945d5f..d5ae18a 100644 --- a/modules/hook-context-intelligence/uv.lock +++ b/modules/hook-context-intelligence/uv.lock @@ -5,20 +5,7 @@ requires-python = ">=3.11" [[package]] name = "amplifier-bundle-context-intelligence" version = "0.1.1" -source = { directory = "../../" } - -[package.metadata] - -[package.metadata.requires-dev] -dev = [ - { name = "httpx", specifier = ">=0.25" }, - { name = "idna", specifier = ">=3.15" }, - { name = "pyright", specifier = ">=1.1" }, - { name = "pytest", specifier = ">=9.0.3" }, - { name = "pytest-asyncio", specifier = ">=0.24" }, - { name = "pyyaml", specifier = ">=6.0" }, - { name = "ruff", specifier = ">=0.4" }, -] +source = { git = "https://github.com/microsoft/amplifier-bundle-context-intelligence?rev=v0.1.1#b722074f17a354816ebf5adcf0881b1562a2cbc5" } [[package]] name = "amplifier-core" @@ -34,7 +21,7 @@ dependencies = [ [[package]] name = "amplifier-module-hook-context-intelligence" -version = "0.1.1" +version = "0.1.2" source = { editable = "." } dependencies = [ { name = "amplifier-bundle-context-intelligence" }, @@ -54,7 +41,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "amplifier-bundle-context-intelligence", directory = "../../" }, + { name = "amplifier-bundle-context-intelligence", git = "https://github.com/microsoft/amplifier-bundle-context-intelligence?rev=v0.1.1" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "idna", specifier = ">=3.15" }, ] diff --git a/modules/tool-context-intelligence-upload/uv.lock b/modules/tool-context-intelligence-upload/uv.lock index 30be24e..6097820 100644 --- a/modules/tool-context-intelligence-upload/uv.lock +++ b/modules/tool-context-intelligence-upload/uv.lock @@ -5,24 +5,11 @@ requires-python = ">=3.11" [[package]] name = "amplifier-bundle-context-intelligence" version = "0.1.1" -source = { directory = "../../" } - -[package.metadata] - -[package.metadata.requires-dev] -dev = [ - { name = "httpx", specifier = ">=0.25" }, - { name = "idna", specifier = ">=3.15" }, - { name = "pyright", specifier = ">=1.1" }, - { name = "pytest", specifier = ">=9.0.3" }, - { name = "pytest-asyncio", specifier = ">=0.24" }, - { name = "pyyaml", specifier = ">=6.0" }, - { name = "ruff", specifier = ">=0.4" }, -] +source = { git = "https://github.com/microsoft/amplifier-bundle-context-intelligence?rev=v0.1.1#b722074f17a354816ebf5adcf0881b1562a2cbc5" } [[package]] name = "amplifier-module-hook-context-intelligence" -version = "0.1.1" +version = "0.1.2" source = { editable = "../hook-context-intelligence" } dependencies = [ { name = "amplifier-bundle-context-intelligence" }, @@ -32,7 +19,7 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "amplifier-bundle-context-intelligence", directory = "../../" }, + { name = "amplifier-bundle-context-intelligence", git = "https://github.com/microsoft/amplifier-bundle-context-intelligence?rev=v0.1.1" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "idna", specifier = ">=3.15" }, ] @@ -49,7 +36,7 @@ dev = [ [[package]] name = "amplifier-module-tool-context-intelligence-upload" -version = "0.1.0" +version = "0.1.1" source = { editable = "." } dependencies = [ { name = "amplifier-bundle-context-intelligence" }, @@ -68,7 +55,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "amplifier-bundle-context-intelligence", directory = "../../" }, + { name = "amplifier-bundle-context-intelligence", git = "https://github.com/microsoft/amplifier-bundle-context-intelligence?rev=v0.1.1" }, { name = "amplifier-module-hook-context-intelligence", editable = "../hook-context-intelligence" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "idna", specifier = ">=3.15" },