feat: host config layer + drop hostCapabilities surface#27
Merged
Conversation
Adds the locked design for a persistent host-set config layer between sealed bundle.md and per-turn argv. Key decisions: - 2-tier resolution: --config flag > $AMPLIFIER_AGENT_CONFIG env. No XDG default. - Hard error on missing path in either tier. - YAML with yaml.safe_load only. - 4 top-level keys (mcp, approval, provider, allowProtocolSkew) as pass-through to module configs (tool-mcp, hooks-approval, provider modules). - Layered merge over bundle defaults. - Bundle gains default_provider: field; provider_detect.detect_provider() is removed as vestigial. - Strict-by-default validation: no escape hatch on unknown keys. - amplifier-agent config show extended to report resolved path + source. - XDG resolution consolidated through persistence.py. - Drops argv flags: --env-allowlist, --env-extra, --allow-protocol-skew. - Drops env var: AMPLIFIER_AGENT_ALLOW_PROTOCOL_SKEW. Supersedes Mode A amendment §3 surface. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…ion) 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Remove the --host-capabilities click option, function parameter, and parser invocation from single_turn.py. Insert a transitional host_capabilities = None binding so downstream call sites (engine wiring, mount preset, fingerprint) keep compiling until A3/A4/A5 land. The removal-guardrail test (test_host_capabilities_flag_not_in_help) now PASSES. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…velope) Remove the host_capabilities keyword-only argument from _build_envelope and the conditional that wrote it into metadata. Update the success-path call site in run() to stop passing host_capabilities. Append a guardrail test (test_success_envelope_metadata_excludes_host_capabilities) that verifies hostCapabilities never appears in success envelope metadata. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…r_envelope) 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…sitional shim Remove host_capabilities from _write_audit signature, audit dict body, and all three call sites (AaaError, generic Exception, success paths). Delete the transitional 'host_capabilities = None' shim placed in Task A2. Adds test_audit_dict_excludes_host_capabilities which patches session_state_dir to tmp_path, calls _write_audit without the removed kwarg, reads the audit JSON, and asserts hostCapabilities is absent. grep host_capabilities src/amplifier_agent_cli/modes/single_turn.py returns zero hits. Module imports cleanly. All 4 removal-guardrail tests pass. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…w-up) The InitializeHostParams TypedDict was deleted in 26906d7 but the InitializeParams.host field still referenced it, causing NameError when _gen.main ran. This was a missed step in Task B2. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Removes the two now-obsolete protocol schema files and prunes their entries from test_protocol_gen.py expected set. The schema generator no longer emits them since the underlying TypedDicts were dropped in 26906d7. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…lope
The --host-capabilities CLI flag was removed in prior commits; this test
exercised that removed surface and now fails with click exit code 2
('No such option: --host-capabilities'). Deleting the obsolete test.
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)
Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…+ update consumer sets 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…v emission Removes the hostCapabilities field from the AssembleArgvInput interface and the corresponding emission block from assembleArgv(). Adds a regression test asserting that argv emitted for a minimal session contains no 'host'-prefixed flag. Note: session.ts (lines 117, 251) and index.ts (line 163) still reference hostCapabilities; tsc --noEmit will fail until task F3 removes the host? field from SpawnAgentParams and the SessionHandle plumbing.
Removes the HostCapabilities import/re-export, the `host?` field from SpawnAgentParams, and the spread that forwarded `host.capabilities` to SessionHandle. Also cleans up the trailing references in session.ts: the HostCapabilities import, the `hostCapabilities?` field on SessionHandleParams, and the now-unrecognized `hostCapabilities` key passed to assembleArgv (a0e02f0 already dropped that field). BREAKING: callers passing `params.host` now get a TS error and silent runtime drop. Tests: tsc --noEmit clean; vitest run 62/62 pass. Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Remove the HostCapabilities interface, the InitializeHostParams envelope, and the host? field on InitializeParams. Also strip orphaned JSDoc blocks left behind by the deletions. Task: F4 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…with ts) Aligns Python wrapper with TS wrapper changes (a0e02f0, 86291bf, 193492f). Removes the host parameter from spawn_agent signature, docstring, conditional host_capabilities extraction block, and SessionHandleParams constructor call. argv_builder still accepts host_capabilities directly; that path is cleaned in G2. Tests: 48/48 pass. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Remove the host_capabilities keyword parameter and its conditional emission from assemble_argv(). Invert the corresponding test to assert the --host-capabilities flag is not present in the produced argv. Part of drop-host-capabilities sequence. session.py still passes host_capabilities= to assemble_argv — that call site is broken at runtime until the follow-up session.py task lands. No tests currently exercise the session.py->assemble_argv path, so the full Python wrapper test suite passes. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
….2.0 rename) The audit-trail test was still using the pre-protocol-0.2.0 --mcp-servers inline JSON flag, which was renamed to --mcp-config-path (path-based) in commit ea51d05. This rename was missed when that PR landed and was caught by Phase 1 H2 full-suite verification. Replaces inline JSON with a tmpfile path; updates the audit assertion from mcpServersDigest to mcpConfigPathDigest (the path digest the engine now emits).
…1 follow-up) Phase 1 missed deletion: G2 dropped host_capabilities from assemble_argv, but SessionHandleParams still held the field and threaded it into the assemble_argv call. Remove both the dataclass field and the caller arg. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
… (B2 follow-up) Three tests in test_wire_types_v01.py asserted shapes that no longer exist: - test_host_capabilities_typed_dict_exists: HostCapabilities TypedDict was removed by the drop-host-capabilities work (B2). - test_initialize_params_has_mcp_servers_field: the 'mcpServers' field was superseded by 'mcpConfigPath' in the protocol-0.2.0 rename. - test_initialize_params_has_host_field: the 'host' field was removed by B2 together with HostCapabilities. Delete those three tests. test_mcp_server_config_typed_dict_exists remains valid (McpServerConfig is still part of the protocol surface) and is kept. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…lizeParams (C1 follow-up) InitializeParams.schema.json still carried a $ref to InitializeHostParams.schema.json even though that schema file was deleted in C1, leaving a dangling reference. The schemas/ tree is generator output — regenerate it from the authoritative TypedDicts via 'python -m amplifier_agent_lib.protocol._gen'. This: - removes the 'host' property (dangling InitializeHostParams $ref) — the C1 Phase 1 miss we're fixing - removes the now-renamed 'mcpServers' property, replacing it with 'mcpConfigPath' (protocol-0.2.0 rename, source already updated in methods.py — generator output was just stale) - bumps the protocol version banner in spec.md from 0.1.0 to 0.2.0 to match PROTOCOL_VERSION in methods.py 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…llow-up) The committed dist tree still contained old code referencing hostCapabilities, HostCapabilities, and InitializeHostParams from before Phase 1's drop- host-capabilities work. Running 'npm run build' regenerates: - src/types.ts via the prebuild step (gen-types from the now-clean JSON schemas — see C1 follow-up) - dist/ via tsc After the rebuild, dist/ no longer references any of the removed symbols. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Add test_config_show_succeeds_when_config_malformed: write a host config with truncated JSON, invoke 'config show --config <path>', and assert exit_code == 0 with parsed=None and parse_error.code == 'config_malformed_json'. Operators must be able to locate the offending config file before they can debug its contents, so config show stays exit-0 even when the loader raises ConfigError and surfaces the loader's error code under host_config.parse_error. Implementation already lives in F3; this test locks the contract. Implements D8. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Auto-fixed by `ruff check --fix` as part of G4 Step 3 verification. No functional change.
…s, not phantom keys
The previous code passed dict(prepared.mount_plan) to merge_config() as
bundle_modules, treating mount_plan's top-level section names ("tools",
"hooks", "providers") as if they were module IDs. The merger expects
{module_id: config_dict}, so merged.get("tool-mcp", {}) always returned {}.
The .update() then wrote merged results into phantom top-level keys
(mount_plan["tool-mcp"]) that the kernel ignored, since the kernel reads
tool/hook/provider configs from the list entries at
mount_plan["tools"][n]["config"] etc. Net effect: every mcp:, approval:,
and provider.config: override in the host config was silently dropped.
The fix builds a proper {module_id: config_dict} view from the list
entries, runs merge_config(), then writes merged values back into the
SAME list entries in-place. The kernel now sees host overrides where
foundation's mount logic reads them.
Tests:
- Replace the masked _FakePrepared fixture in test_runtime_config_merge.py
with one that mirrors Bundle.to_mount_plan()'s real shape (lists of
{module, config, source} dicts at tools/hooks/providers).
- Add per-section assertions that merged values land in the list entries
and NOT in phantom top-level keys.
- Add end-to-end regression test in tests/config/test_integration.py.
Diagnosed by bug-hunter; the unit test masked the bug because it used the
wrong mount_plan shape (module IDs at the top level — the shape the merger
expects, but not the shape PreparedBundle.mount_plan actually has).
…NFIG (D4) The CLI --mcp-config-path flag has been forwarded to tool-mcp via the AMPLIFIER_MCP_CONFIG env var since the wire protocol introduced it, but the equivalent host-config path (mcp.configPath in YAML/JSON) was never wired. configPath is an engine-level convenience key, not a tool-mcp config key — tool-mcp's own config.py picks it up from the env var via its standard priority chain. When both CLI and host config provide a path, CLI wins (matches the documented precedence: explicit invocation flags > config file). Tests: - test_mcp_config_path_in_host_sets_env_var: host config → env var. - test_cli_mcp_config_path_takes_precedence_over_host: CLI > host. Both tests use monkeypatch.delenv to start from a known state and let monkeypatch's teardown restore the prior env.
…roke wheel build The packages = ["src/amplifier_agent_lib"] entry already ships everything under protocol/schemas/ and protocol/conformance/fixtures/. The additional force-include entries for those directories caused hatchling to reject the build with: ValueError: A second file is being added to the wheel archive at the same path: amplifier_agent_lib/protocol/schemas/AgentShutdownParams.schema.json. Surfaced when reinstalling the host-config branch into a Digital Twin Universe. Closes 2 of the 17 pre-existing failures previously noted as out of scope (test_bundle_packaging, test_phase_2_1_packaging).
Profile generated by amplifier-tester:setup-digital-twin during PR
validation. Mirrors this branch to a local Gitea instance and provisions
amplifier-agent 0.3.0 in an Incus container so reviewers can verify the
host config layer + hostCapabilities removal end-to-end.
Launch:
amplifier-digital-twin launch \\
.amplifier/digital-twin-universe/profiles/amplifier-agent-host-config-pr27.yaml \\
--var GITEA_URL=<your-gitea-url> --var GITEA_TOKEN=<your-token>
…vitest bump) Resolves 10 conflicts between this PR's hostCapabilities removal + host config layer work and main's protocol-0.2.0 rename pass (#24). Strategy: combine both changes — our hostCapabilities deletions are preserved; main's mcpServers → mcpConfigPath renames are preserved. The deleted initialize-with-host-capabilities.yaml fixture stays deleted (modify/delete resolved in favor of our deletion). Side effect: PR #24's protocol-0.2.0 fixes close most of the pre-existing tech debt that this PR's description previously documented as out of scope.
manojp99
added a commit
that referenced
this pull request
Jun 3, 2026
…g + env var) (#29) * test(engine): add removal guardrail for --mcp-config-path argv flag Pure intent-capture commit (RED): the assertions in this test file FAIL against the current source. The matching implementation drops in the next commit (chore(engine)!: drop --mcp-config-path argv flag). Mirrors the Phase 1 cleanup pattern from tests/cli/test_drop_host_capabilities.py: each guardrail asserts an absence at a specific seam — click --help output, click usage rejection, _TurnSpec dataclass fields, make_turn_handler signature, and _runtime.py source — so future refactors that re-introduce the flag fail loudly at this layer instead of via downstream regressions. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * chore(engine)!: drop --mcp-config-path argv flag Pure removal, no flag tolerance — click rejects with `Error: No such option '--mcp-config-path'` (exit 2). Mirrors Phase 1's hostCapabilities removal posture. After PR #27 merged the host config layer (commit 70121c3) and PR #24 renamed `--mcp-servers` to `--mcp-config-path`, three equivalent paths set AMPLIFIER_MCP_CONFIG for tool-mcp: (1) host_config["mcp"]["configPath"] — host policy via config file (2) AMPLIFIER_MCP_CONFIG env var — read natively by tool-mcp (3) --mcp-config-path argv flag — redundant survivor Per Mode A amendment §2.5 D9 + host config D10, per-invocation flags stay argv and host policy moves to config. `mcpConfigPath` is host policy. This commit removes path (3); paths (1) and (2) remain. Engine changes (src/amplifier_agent_cli/modes/single_turn.py): - Drop @click.option("--mcp-config-path") declaration and the matching `mcp_config_path` parameter on run(). - Drop the §(5b) validation block that gated the flag value as a real file (mcp_config_path_invalid). - Drop `mcp_config_path` from the _TurnSpec dataclass and from the make_turn_handler kwargs in _execute_turn. - Drop `mcp_config_path` parameter on _write_audit and the `mcpConfigPathDigest` audit field. The field was only populated by the argv flag; no remaining surface feeds it. The envDigest precedent of preserving stable digests with empty placeholders does not apply here — the field carried no information once the source was gone, so dropping it cleanly is preferable. Engine changes (src/amplifier_agent_lib/_runtime.py): - Drop the `mcp_config_path` parameter on make_turn_handler. - Drop the CLI-flag → AMPLIFIER_MCP_CONFIG translation block. - The host_config["mcp"]["configPath"] → AMPLIFIER_MCP_CONFIG block (added by 70121c3) remains; the `not mcp_config_path` precedence guard is dropped because the CLI path is gone. - The wire-side `handle_initialize` path (`params["mcpConfigPath"]` → `_wire_mcp_config_path` → AMPLIFIER_MCP_CONFIG) is untouched; it is protocol-0.2.0 surface, not argv surface. Test updates: - tests/cli/test_drop_mcp_config_path_flag.py (added in the previous commit) now passes — all five guardrails green. - tests/cli/test_drop_host_capabilities.py: drop the obsolete mcp_config_path=None kwarg from the _write_audit call. - tests/cli/test_mode_a_audit_trail.py: rewrite to invoke `run` without the removed flag and assert mcpConfigPathDigest is absent from the audit (negative guardrail). - tests/test_runtime_config_merge.py: drop test_cli_mcp_config_path_takes_precedence_over_host (precedence semantics are gone with the CLI path). The host-config translation test stays. - tests/test_runtime_mcp_threading.py: drop the two make_turn_handler CLI-path tests; rename the surviving "no source" test to reflect host_config being the only engine-side translation site. The wire-side handle_initialize tests are untouched. Cross-repo follow-up: amplifier-nc-provider's adapter currently passes `--mcp-config-path` to the engine subprocess (this was set up by the PR #24 rename). It will break against this engine. Same shape as Phase 1's hostCapabilities NC issue — file a tracking issue in the adapter repo to migrate the spilled path forwarding from the argv flag to AMPLIFIER_MCP_CONFIG via the subprocess environment. BREAKING CHANGE: The `--mcp-config-path` argv flag was removed from `amplifier-agent run`. Callers must migrate to one of: (1) host config: `mcp.configPath: /path/to/mcp.json` in the file consumed by --config; the engine translates it to AMPLIFIER_MCP_CONFIG at make_turn_handler boot. (2) ambient env: set AMPLIFIER_MCP_CONFIG=/path in the engine's subprocess environment; tool-mcp reads it natively via its config-discovery priority chain. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * chore(wrapper-py)!: drop mcp_config_path from assemble_argv + spawn_agent Lockstep with the engine drop (chore(engine)!: drop --mcp-config-path argv flag). The Python wrapper still spills the supplied mcp_servers dict to a 0600 tmpfile (CR-A); the forwarding path changes from argv flag to subprocess env var. argv_builder.py: - Drop `mcp_config_path` parameter from `assemble_argv` and the `--mcp-config-path` emission block. Note the new path in the docstring (AMPLIFIER_MCP_CONFIG injected into subprocess env by SessionHandle._make_iterable, or set by the host directly). session.py: - Drop the `mcp_config_path=spill["config_path"]` kwarg from the `assemble_argv` call in `_make_iterable`. - Build a fresh subprocess env dict per submit; when the spill produced a path, inject `AMPLIFIER_MCP_CONFIG=<path>` into it and pass that to `asyncio.create_subprocess_exec`. The SessionHandle's stored `subprocess_env` is never mutated. - Update the step-numbered comment block to reflect the env-var forwarding mechanism. mcp_spill.py: - Docstring updates only — replace references to "engine receives the plain file path via --mcp-config-path" with the new "caller injects the spilled path into the engine's subprocess environment as AMPLIFIER_MCP_CONFIG" description. __init__.py: - Update the spawn_agent() docstring for `mcp_servers` to describe the env-var forwarding mechanism. tests/test_argv_builder.py: - Rename case (iv) from "threaded as bare path when caller pre-spilled" to "flag is not emitted". - Add case (v): asserts `assemble_argv(..., mcp_config_path=...)` raises TypeError so callers that still pass the obsolete kwarg fail loudly instead of silently no-opping. BREAKING CHANGE: assemble_argv() no longer accepts the `mcp_config_path` keyword argument. Callers using the public spawn_agent API are unaffected — the wrapper handles the env-var injection internally. Callers depending on the lower-level argv_builder must remove the kwarg and inject AMPLIFIER_MCP_CONFIG into their subprocess environment themselves. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * chore(wrapper-ts)!: drop mcpConfigPath from AssembleArgvInput + argv emission Lockstep with the engine drop (chore(engine)!: drop --mcp-config-path argv flag) and the Python wrapper drop (chore(wrapper-py)!: drop mcp_config_path from assemble_argv + spawn_agent). The TypeScript wrapper still spills the supplied mcpServers map to a 0600 tmpfile (CR-A); the forwarding path changes from argv flag to subprocess env var. src/argv-builder.ts: - Drop `mcpConfigPath` field from `AssembleArgvInput`. - Drop the `--mcp-config-path` emission block in `assembleArgv`. - Document the new forwarding mechanism (AMPLIFIER_MCP_CONFIG injected into subprocess env by SessionHandle.makeIterable, or set by the host directly). src/session.ts: - Drop the `mcpConfigPath: spill.configPath ?? undefined` field from the `assembleArgv` call in `makeIterable`. - Build a fresh `subprocessEnv` per submit; when the spill produced a path, inject `AMPLIFIER_MCP_CONFIG=<path>` into it and pass that object to `childSpawn`. The SessionHandle's stored `params.subprocessEnv` is never mutated. - Update the step-numbered JSDoc to reflect the env-var forwarding mechanism and the dropped argv flag. - Update the `mcpServers` field's JSDoc on `SessionHandleParams`. src/mcp-spill.ts: - Docstring updates only — replace references to "engine receives the plain file path via --mcp-config-path" with the new description. src/index.ts: - Update the JSDoc on `SpawnAgentParams.mcpServers` to describe env-var forwarding. test/argv-builder.test.ts: - Rename case (iv) from "threaded as plain path" to "is not emitted (removed surface)". - Add case (v): a compile-time guardrail using `@ts-expect-error` to assert `AssembleArgvInput` no longer accepts `mcpConfigPath`; if a future refactor re-adds the field, the directive becomes a build error. dist/*: regenerated by `npm run build` — these are committed artifacts in this wrapper. Source-of-truth changes live in src/ and test/; the dist/ delta is mechanical. BREAKING CHANGE: `AssembleArgvInput` no longer exposes the `mcpConfigPath` field. Callers using the public `spawnAgent` API are unaffected — the wrapper handles env-var injection internally. Callers depending on the lower-level `assembleArgv` must remove the field and inject `AMPLIFIER_MCP_CONFIG` into their subprocess environment themselves. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --------- Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com> Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
manojp99
added a commit
that referenced
this pull request
Jun 3, 2026
…from wrappers (sync with engine) (#31) * chore(wrapper-ts)!: drop envAllowlist, envExtra, allowProtocolSkew from AssembleArgvInput + argv emission The engine removed the --env-allowlist, --env-extra, and --allow-protocol-skew argv flags in PR #27 (host config layer). The TypeScript wrapper was still emitting them when the corresponding AssembleArgvInput / SessionHandleParams / SpawnAgentParams fields were set, which made engine click reject the invocation with UsageError (exit 2) for any wrapper consumer that supplied them. This commit removes: - envAllowlist, envExtra, allowProtocolSkew from AssembleArgvInput and the three argv.push(...) blocks in assembleArgv() - envAllowlist, envExtra, allowProtocolSkew from SessionHandleParams and the threading through to assembleArgv() - allowProtocolSkew from SpawnAgentParams and the threading through to new SessionHandle(...) SpawnAgentParams.env = { allowlist, extra } is preserved unchanged - the wrapper still composes the subprocess environment via buildEnv(). Only the FORWARDING of those values as argv flags to the engine is removed. argv-builder tests are extended with @ts-expect-error compile-time guardrails and runtime negative assertions for all three flags, mirroring PR #29's removal pattern for --mcp-config-path. NC follow-up: the NC adapter (amplifier-module-provider-nc) may pass envAllowlist / envExtra / allowProtocolSkew to spawnAgent(); a follow-up adapter PR will catch it up. BREAKING CHANGE: SpawnAgentParams.allowProtocolSkew, SessionHandleParams.envAllowlist / envExtra / allowProtocolSkew, and the corresponding AssembleArgvInput fields are removed. Hosts that need the skew override now set host_config.allowProtocolSkew: true in the JSON config file. Hosts that need custom env composition either set $AMPLIFIER_AGENT_CONFIG in the subprocess env or pass --config <path> per turn. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * chore(wrapper-py)!: drop env_allowlist, env_extra, allow_protocol_skew from spawn_agent + assemble_argv The engine removed the --env-allowlist, --env-extra, and --allow-protocol-skew argv flags in PR #27 (host config layer). The Python wrapper was still emitting them when the corresponding kwargs were set, which made engine click reject the invocation with UsageError (exit 2) for any wrapper consumer that supplied them. This commit removes: - env_allowlist, env_extra, allow_protocol_skew kwargs from assemble_argv and the three argv.extend(...) / argv.append(...) blocks - env_allowlist, env_extra, allow_protocol_skew fields from SessionHandleParams (and the unused `field` import that they required) plus the threading into assemble_argv - allow_protocol_skew kwarg from spawn_agent and the threading into SessionHandleParams spawn_agent(env={"allowlist": ..., "extra": ...}) is preserved unchanged - the wrapper still composes the subprocess environment via build_env(). Only the FORWARDING of those values as argv flags to the engine is removed. test_argv_builder is extended with three TypeError-rejected kwarg tests and three "flag not emitted" negative assertions, mirroring PR #29's removal pattern for --mcp-config-path. NC follow-up: the NC adapter (amplifier-module-provider-nc) may pass env_allowlist / env_extra / allow_protocol_skew to spawn_agent(); a follow-up adapter PR will catch it up. BREAKING CHANGE: spawn_agent.allow_protocol_skew, SessionHandleParams.env_allowlist / env_extra / allow_protocol_skew, and the corresponding assemble_argv kwargs are removed. Hosts that need the skew override now set host_config.allowProtocolSkew: true in the JSON config file. Hosts that need custom env composition either set $AMPLIFIER_AGENT_CONFIG in the subprocess env or pass --config <path> per turn. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> * chore(wrapper-ts): rebuild dist after wrapper API removals Regenerates wrappers/typescript/dist/ to reflect the source removals in 796f10d (drop envAllowlist, envExtra, allowProtocolSkew from AssembleArgvInput / SessionHandleParams / SpawnAgentParams + argv emission). Mirrors PR #29's pattern of committing the rebuilt dist alongside the source change so consumers using the published package see the API narrowing immediately. No additional source changes. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --------- Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com> Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
manojp99
added a commit
that referenced
this pull request
Jun 3, 2026
…#27, #29, #31) (#32) * fix(conformance): rename runner refs to initialize-with-mcp-config-path (post-#24) PR #24 renamed the wire-shape fixture from ``initialize-with-mcpservers.yaml`` to ``initialize-with-mcp-config-path.yaml`` but left three hardcoded references to the old name behind: * wrappers/conformance/test/runner-ts.test.ts (TS conformance suite) * wrappers/conformance/tests/test_runner_py.py (Py conformance suite) * tests/test_phase_2_1_exit_gate.py (engine-side fixture-set guard) All three have been failing since PR #24. The conformance suites showed up as "1 pre-existing failure each" in PRs #27, #29, and #31, so wrapper/engine drift could land unseen during the entire window in which we did most of the v0.3.0 argv cleanup -- the exact class of bug the conformance suite is supposed to catch. This commit restores the baseline to green by pointing each reference at the surviving wire-protocol fixture name. No fixture data changes, no engine logic changes. Verification (this commit, host machine): * wrappers/conformance/ (TS): 5 passed (was 4 passed, 1 failed) * wrappers/conformance/ (Py): 5 passed (was 4 passed, 1 failed) * tests/test_phase_2_1_exit_gate.py: passes (was failing) Out of scope (separate cleanup, noted for the PR body): * tests/cli/test_mode_a_v2_envelope.py still has 3 pre-existing failures referencing the removed ``--mcp-servers`` flag. Not touched here per the conformance-restore PR scope. * chore(conformance): align version_skew remediation text with post-#27 host-config surface PR #27 dropped the --allow-protocol-skew argv flag and moved protocol-skew opt-in into the host config file (allowProtocolSkew: true, surfaced through --config). The engine's real protocol_version_mismatch remediation string was updated in lockstep (src/amplifier_agent_lib/engine.py:160-163). The version_skew wire-shape fixture's scripted server response still carried the old 'pass --allow-protocol-skew' remediation text, drifting it from current engine behavior even though no assertion in the fixture exercises the field directly. Update the scripted response to match the engine's current text so the fixture remains an honest exemplar of the wire-protocol surface post-#27/#29/#31. Companion to PR #31 fixture sweep. No engine logic changes, no assertions changed, no test outcome changes. * test(conformance): add baseline + protocol-skew-override wire-shape fixtures Extend the conformance suite with two wire-protocol fixtures that lock in the post-cleanup surface and the previously-uncovered override branch of the version-skew contract: * initialize-baseline.yaml -- canonical minimum init + turn/submit + result/final flow with only protocol-required params (no mcpConfigPath, no allowProtocolSkew, no hostCapabilities, no envAllowlist, no envExtra). Locks in the wire shape that survives PR #27 (host config + drop hostCapabilities), PR #29 (drop --mcp-config-path argv), and PR #31 (drop env-allowlist / env-extra / allow-protocol-skew from wrappers). Any future re-introduction of those legacy fields on the wire must be an intentional, reviewed addition rather than silent drift. * initialize-with-protocol-skew-override.yaml -- the 'permits the handshake' branch of design §8 D6, companion to version_skew.yaml which covers only the strict-refuse branch. Client sends allowProtocolSkew=true (now sourced from the host config file, not from a --allow-protocol-skew argv flag) and a mismatched protocolVersion; server returns a successful sessionState instead of protocol_version_mismatch. Both new fixtures are wired into the TS and Python conformance runners and acknowledged in the two fixture-set guard tests (tests/test_protocol_conformance_fixtures.py and tests/test_phase_2_1_exit_gate.py). Scope note: the conformance runners use scripted JSON-RPC wire replay (ScriptedTransport) -- they do NOT spawn the engine subprocess. Argv-level 'loud failure' invariants for the dropped flags (--host-capabilities, --env-allowlist, --env-extra, --allow-protocol-skew, --mcp-config-path) are already locked in by the engine-side click-CliRunner tests at tests/cli/test_drop_host_capabilities.py and tests/cli/test_drop_mcp_config_path_flag.py. Extending the conformance runner to also exercise argv-level invariants would require subprocess invocation and changes to the loader at src/amplifier_agent_lib/protocol/conformance/loader.py (engine-internal, off limits per the PR scope) and is intentionally left for a future PR. Verification (host machine): * wrappers/conformance/ (TS): 7 passed (was 5 after rename commit) * wrappers/conformance/ (Py): 7 passed (was 5 after rename commit) * tests/test_protocol_conformance_fixtures.py: 17 passed (was 16; the new fixtures load and validate) * tests/test_phase_2_1_exit_gate.py: passes (now acknowledges the new fixtures in the sorted-name guard) * Engine suite (uv run pytest -q --ignore=wrappers): 519 passed, 3 pre-existing failures in tests/cli/test_mode_a_v2_envelope.py (unchanged from PR #31's pre-existing baseline -- they reference the long-removed --mcp-servers flag and are tracked for a separate cleanup). * Wrappers/python: 48 passed; wrappers/typescript: 63 passed; manual smoke confirms --host-capabilities / --env-allowlist / --env-extra / --allow-protocol-skew / --mcp-config-path all reject with click UsageError ('no such option'). --------- Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
Bump the wire protocol version to reflect accumulated backward-incompatible changes shipped under the 0.4.0 release window: - metadata.hostCapabilities removed from response envelope (#27) - InitializeParams.host removed (#27) - InitializeParams.mcpServers renamed to mcpConfigPath (#24) - skills field added (host config skills: block, #30) Old wrappers pinned to '0.2.0' should hard-fail handshake with a typed protocol_version_mismatch error and exit 2 — verified manually: $ uv run amplifier-agent run --protocol-version 0.2.0 --session-id sm 'hi' {... "code": "protocol_version_mismatch" ...} EXIT=2 $ uv run amplifier-agent run --protocol-version 0.3.0 --session-id sm 'hi' {... "reply": "..." ...} EXIT=0 Updated sites (audited via 'git grep "0.2.0" src/ tests/'): - src/amplifier_agent_lib/protocol/methods.py — PROTOCOL_VERSION constant - src/amplifier_agent_lib/protocol/spec.md — regenerated artifact - 9 conformance fixtures' protocolVersion: literals (setup + initialize params) - version_skew.yaml — serverVersion in expected error.data - 6 test files pinning protocolVersion in wrapper-side InitializeParams Left as historical references (per release-issue guidance): - loader.py docstring example (illustrative fixture shape) - test_protocol_conformance_fixtures.py's self-contained _VALID_FIXTURE (loader smoke test, not engine-compat) - serverInfo.version: "0.2.0" in fixture script result blocks (not asserted by conformance harness — engine emits __version__ at runtime; fixture scripts are descriptive, only the explicit assertions: block is verified) BREAKING CHANGE: Wire protocol 0.2.0 -> 0.3.0. Old wrappers pinned to 0.2.0 will hard-fail handshake with protocol_version_mismatch (exit 2). Reinstall both engine and wrapper, or set allowProtocolSkew: true in host config.
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
Engine version bump for the host-config-layer release window. Pairs with the wire PROTOCOL_VERSION bump (0.2.0 -> 0.3.0) and consolidates argv/wire surface removals shipped in PRs #27, #29, #30, #31. Verified: $ uv run amplifier-agent --version amplifier-agent, version 0.4.0 BREAKING CHANGE: Engine version 0.3.0 -> 0.4.0. Wire protocol 0.2.0 -> 0.3.0 shipped in the same release. Old wrappers fail handshake. See CHANGELOG.md for the full argv/wire/API removal list.
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
Python wrapper version bump to pair with the engine 0.4.0 release. Same major.minor as engine — the two move together. The wrapper's compiled PROTOCOL_VERSION (sourced from amplifier_agent_lib) follows the engine bump 0.2.0 -> 0.3.0 transitively. BREAKING CHANGE: SpawnAgentParams API removed envAllowlist, envExtra, allowProtocolSkew, host, and mcpConfigPath fields across PRs #27, #29, #31. Callers must migrate to host_config (JSON file passed via --config or $AMPLIFIER_AGENT_CONFIG) or env var injection (AMPLIFIER_MCP_CONFIG).
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
The TS wrapper jumps minor (0.4.0 -> 0.5.0) rather than tracking the
engine's major.minor (0.4.0) because of release-window history:
- 0.4.0 was already published to npm (verified: 'npm view
amplifier-agent-ts versions' lists 0.3.0, 0.3.1, 0.4.0)
- 0.4.0 was published by PR #17 (path-based MCP config delivery,
pre-#27/#29/#30/#31)
- Since the 0.4.0 publish, PRs #27, #29, #30, #31 have all landed,
removing breaking surface from the TS wrapper API:
* SpawnAgentParams.host / HostCapabilities type (#27)
* mcpConfigPath field + argv emission (#29)
* envAllowlist / envExtra / allowProtocolSkew fields (#31)
We cannot republish 0.4.0 with different code, and the accumulated changes
are breaking (not a patch). Bumping to 0.5.0 puts the next npm release on
a fresh, unpublished version. If you have context I'm missing about a
prior decision to keep TS major.minor tied to engine major.minor, override
with a follow-up bump.
BREAKING CHANGE: TS wrapper API removed SpawnAgentParams.host,
HostCapabilities type, InitializeHostParams type (#27); mcpConfigPath field
+ argv emission (#29); envAllowlist, envExtra, allowProtocolSkew fields
(#31). Callers must migrate to AMPLIFIER_MCP_CONFIG env var and a
host_config JSON file passed via --config.
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
, #32) Replace the [Unreleased] section with a full [0.4.0] - 2026-06-03 entry that consolidates the host-config-layer release window: PR #27 - Host config layer + drop hostCapabilities surface PR #29 - Drop --mcp-config-path argv (subsumed by host config + env var) PR #30 - host-config skills: block + tool-skills bundle composition PR #31 - Drop env-allowlist, env-extra, allow-protocol-skew from wrappers PR #32 - Restore conformance suite Highlights: - 4 argv flags + 1 env var removed (subsumed by host config layer) - hostCapabilities fully removed from envelope, initialize, and wrapper API - 5th host-config block 'skills:' (D11/D12/D13) - Wire protocol 0.2.0 -> 0.3.0 (BREAKING) - Engine 0.3.0 -> 0.4.0, Python wrapper 0.3.0 -> 0.4.0, TS wrapper 0.4.0 -> 0.5.0 Also documents the cross-repo follow-ups that downstream consumers (notably amplifier-module-provider-nc) must catch up on but are NOT part of this release.
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
Closes the last 4 Python CI failures on this release branch. (1) tests/cli/test_config_show.py::test_config_show_reports_default_when_env_absent Click's CliRunner.invoke(env=...) MERGES the env dict with os.environ instead of replacing it. GitHub Actions runners set XDG_CONFIG_HOME by default, which leaked into the test and made source='env:XDG_CONFIG_HOME' instead of the 'default' the test was asserting. Now uses monkeypatch.delenv() to explicitly remove XDG_CONFIG_HOME / XDG_CACHE_HOME / XDG_STATE_HOME before invoking. (2) tests/cli/test_mode_a_v2_envelope.py The three test_mcp_servers_* tests (inline_json_parsed, at_path_form, malformed_json_yields_argv_envelope) target the --mcp-servers argv flag. That flag was renamed to --mcp-config-path by PR #24 and then fully removed by PR #29. The tests have been failing as 'pre-existing baseline' through PRs #27, #29, #31, #32, and #33's earlier baselines. They test removed surface and should never have been kept. Replaced with an inline comment naming the removal context and pointing at the removal guardrail at tests/cli/test_drop_mcp_config_path_flag.py. Local: 532 passed, 3 skipped, 0 failed (full pytest tests/).
manojp99
added a commit
that referenced
this pull request
Jun 3, 2026
…ce restored (#33) * chore(protocol)!: bump wire PROTOCOL_VERSION 0.2.0 -> 0.3.0 Bump the wire protocol version to reflect accumulated backward-incompatible changes shipped under the 0.4.0 release window: - metadata.hostCapabilities removed from response envelope (#27) - InitializeParams.host removed (#27) - InitializeParams.mcpServers renamed to mcpConfigPath (#24) - skills field added (host config skills: block, #30) Old wrappers pinned to '0.2.0' should hard-fail handshake with a typed protocol_version_mismatch error and exit 2 — verified manually: $ uv run amplifier-agent run --protocol-version 0.2.0 --session-id sm 'hi' {... "code": "protocol_version_mismatch" ...} EXIT=2 $ uv run amplifier-agent run --protocol-version 0.3.0 --session-id sm 'hi' {... "reply": "..." ...} EXIT=0 Updated sites (audited via 'git grep "0.2.0" src/ tests/'): - src/amplifier_agent_lib/protocol/methods.py — PROTOCOL_VERSION constant - src/amplifier_agent_lib/protocol/spec.md — regenerated artifact - 9 conformance fixtures' protocolVersion: literals (setup + initialize params) - version_skew.yaml — serverVersion in expected error.data - 6 test files pinning protocolVersion in wrapper-side InitializeParams Left as historical references (per release-issue guidance): - loader.py docstring example (illustrative fixture shape) - test_protocol_conformance_fixtures.py's self-contained _VALID_FIXTURE (loader smoke test, not engine-compat) - serverInfo.version: "0.2.0" in fixture script result blocks (not asserted by conformance harness — engine emits __version__ at runtime; fixture scripts are descriptive, only the explicit assertions: block is verified) BREAKING CHANGE: Wire protocol 0.2.0 -> 0.3.0. Old wrappers pinned to 0.2.0 will hard-fail handshake with protocol_version_mismatch (exit 2). Reinstall both engine and wrapper, or set allowProtocolSkew: true in host config. * chore(engine)!: bump amplifier-agent version 0.3.0 -> 0.4.0 Engine version bump for the host-config-layer release window. Pairs with the wire PROTOCOL_VERSION bump (0.2.0 -> 0.3.0) and consolidates argv/wire surface removals shipped in PRs #27, #29, #30, #31. Verified: $ uv run amplifier-agent --version amplifier-agent, version 0.4.0 BREAKING CHANGE: Engine version 0.3.0 -> 0.4.0. Wire protocol 0.2.0 -> 0.3.0 shipped in the same release. Old wrappers fail handshake. See CHANGELOG.md for the full argv/wire/API removal list. * chore(wrapper-py)!: bump Python wrapper version 0.3.0 -> 0.4.0 Python wrapper version bump to pair with the engine 0.4.0 release. Same major.minor as engine — the two move together. The wrapper's compiled PROTOCOL_VERSION (sourced from amplifier_agent_lib) follows the engine bump 0.2.0 -> 0.3.0 transitively. BREAKING CHANGE: SpawnAgentParams API removed envAllowlist, envExtra, allowProtocolSkew, host, and mcpConfigPath fields across PRs #27, #29, #31. Callers must migrate to host_config (JSON file passed via --config or $AMPLIFIER_AGENT_CONFIG) or env var injection (AMPLIFIER_MCP_CONFIG). * chore(wrapper-ts)!: bump amplifier-agent-ts version 0.4.0 -> 0.5.0 The TS wrapper jumps minor (0.4.0 -> 0.5.0) rather than tracking the engine's major.minor (0.4.0) because of release-window history: - 0.4.0 was already published to npm (verified: 'npm view amplifier-agent-ts versions' lists 0.3.0, 0.3.1, 0.4.0) - 0.4.0 was published by PR #17 (path-based MCP config delivery, pre-#27/#29/#30/#31) - Since the 0.4.0 publish, PRs #27, #29, #30, #31 have all landed, removing breaking surface from the TS wrapper API: * SpawnAgentParams.host / HostCapabilities type (#27) * mcpConfigPath field + argv emission (#29) * envAllowlist / envExtra / allowProtocolSkew fields (#31) We cannot republish 0.4.0 with different code, and the accumulated changes are breaking (not a patch). Bumping to 0.5.0 puts the next npm release on a fresh, unpublished version. If you have context I'm missing about a prior decision to keep TS major.minor tied to engine major.minor, override with a follow-up bump. BREAKING CHANGE: TS wrapper API removed SpawnAgentParams.host, HostCapabilities type, InitializeHostParams type (#27); mcpConfigPath field + argv emission (#29); envAllowlist, envExtra, allowProtocolSkew fields (#31). Callers must migrate to AMPLIFIER_MCP_CONFIG env var and a host_config JSON file passed via --config. * docs(changelog): consolidate 0.4.0 release notes (PRs #27, #29, #30, #31, #32) Replace the [Unreleased] section with a full [0.4.0] - 2026-06-03 entry that consolidates the host-config-layer release window: PR #27 - Host config layer + drop hostCapabilities surface PR #29 - Drop --mcp-config-path argv (subsumed by host config + env var) PR #30 - host-config skills: block + tool-skills bundle composition PR #31 - Drop env-allowlist, env-extra, allow-protocol-skew from wrappers PR #32 - Restore conformance suite Highlights: - 4 argv flags + 1 env var removed (subsumed by host config layer) - hostCapabilities fully removed from envelope, initialize, and wrapper API - 5th host-config block 'skills:' (D11/D12/D13) - Wire protocol 0.2.0 -> 0.3.0 (BREAKING) - Engine 0.3.0 -> 0.4.0, Python wrapper 0.3.0 -> 0.4.0, TS wrapper 0.4.0 -> 0.5.0 Also documents the cross-repo follow-ups that downstream consumers (notably amplifier-module-provider-nc) must catch up on but are NOT part of this release. * fix(ci): commit uv.lock for deterministic dependency resolution The CI workflow uses astral-sh/setup-uv@v3 with enable-cache: true, which defaults to globbing **/uv.lock to compute the cache key. With uv.lock gitignored, every CI run failed at the install step with: No matches found for glob **/uv.lock Committing uv.lock fixes CI and aligns with Astral's recommended practice for reproducible builds. Catches reproducibility drift between contributors and CI/DTU. The lock is ~150KB. This was a pre-existing CI break on main (every recent CI run failing) that this version-bump release is unblocking as part of release-readiness. * fix(ci): install Node + pnpm for conformance parity tests tests/test_conformance_parity.py::test_ts_and_py_runners_agree[*] shells out to 'pnpm exec tsx runner_ts.ts' to cross-validate the TS runner against the Python runner. The Python CI job had no Node.js or pnpm installed, so all 10 parametrized cases failed with: FileNotFoundError: [Errno 2] No such file or directory: 'pnpm' Adds setup-node@v4, pnpm/action-setup@v3, and a pnpm-install step in wrappers/conformance/ before pytest runs. Pre-existing CI gap that this release branch is closing as part of release-readiness. * fix(ci): make XDG test hermetic + delete obsolete --mcp-servers tests Closes the last 4 Python CI failures on this release branch. (1) tests/cli/test_config_show.py::test_config_show_reports_default_when_env_absent Click's CliRunner.invoke(env=...) MERGES the env dict with os.environ instead of replacing it. GitHub Actions runners set XDG_CONFIG_HOME by default, which leaked into the test and made source='env:XDG_CONFIG_HOME' instead of the 'default' the test was asserting. Now uses monkeypatch.delenv() to explicitly remove XDG_CONFIG_HOME / XDG_CACHE_HOME / XDG_STATE_HOME before invoking. (2) tests/cli/test_mode_a_v2_envelope.py The three test_mcp_servers_* tests (inline_json_parsed, at_path_form, malformed_json_yields_argv_envelope) target the --mcp-servers argv flag. That flag was renamed to --mcp-config-path by PR #24 and then fully removed by PR #29. The tests have been failing as 'pre-existing baseline' through PRs #27, #29, #31, #32, and #33's earlier baselines. They test removed surface and should never have been kept. Replaced with an inline comment naming the removal context and pointing at the removal guardrail at tests/cli/test_drop_mcp_config_path_flag.py. Local: 532 passed, 3 skipped, 0 failed (full pytest tests/). --------- Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
This was referenced Jun 3, 2026
manojp99
added a commit
that referenced
this pull request
Jun 3, 2026
* fix(packaging): drop non-existent workspace members from pyproject.toml The [tool.uv.workspace] block declared three members but only wrappers/python actually exists in the tree. The two packages/... entries have never existed at any commit. Most uv versions tolerate this (warn or silently skip), but specific uv-version + config combinations would resolve the workspace install to an ancestor commit where pre-PR-#27 wheel-build duplicates were still present, producing confusing hatchling errors at uv tool install time. Declare only the real member: wrappers/python. * chore(release): bump engine to 0.4.1 + CHANGELOG entry --------- Co-authored-by: release <mpaidiparthy@microsoft.com>
manojp99
pushed a commit
that referenced
this pull request
Jun 3, 2026
…th (#1) Engine PR #27 / v0.4.0 added the --config <path> flag and the host_config layer (approval mode, MCP servers, provider defaults, allowProtocolSkew, etc.). The wrapper had no surface to forward this, so callers had to fall back to AMPLIFIER_AGENT_CONFIG in env.extra. This change: - Adds SpawnAgentParams.configPath?: string (public, @public TSDoc). - Adds AssembleArgvInput.configPath?: string. - assembleArgv emits --config <path> when configPath is set. - Threads configPath through SessionHandleParams to the per-submit argv assembly. Also drive-by adds approvalMode field to AssembleArgvInput (used by #10's commit). The argv-builder now reads input.approvalMode and emits -y / -n / nothing accordingly. Default remains -y for backward compat with callers that haven't opted into the approval API. Closes #1.
manojp99
added a commit
that referenced
this pull request
Jun 3, 2026
…, approval, getEngineInfo, +5 more) (#36) * feat(wrapper-ts): re-export internal helpers from index.ts (#5) Adds named re-exports from the package entry point so consumers can import internal helpers without reaching into private deep paths: assembleArgv, AssembleArgvInput resolveMcpConfigPath, cleanupSpillFile, McpSpillResult buildEnv, resolveBinaryPath, probeEngineVersion, DEFAULT_ALLOWLIST, BLOCKED_ENV_KEYS, ResolveBinaryPathOptions, BuildEnvOptions Transport, TransportOptions, ExitInfo checkProtocolVersion, VersionCheckResult, VersionCheckOk, VersionCheckFail, CheckProtocolVersionOptions parseRunOutput, STDERR_TAIL_BYTES, SubprocessOutcome makeApprovalHandler, ApprovalAdapter, ApprovalRequest, ApprovalHandler Each export is annotated @public. Closes #5. * feat(wrapper-ts): wire checkProtocolVersion() into init path (#9) spawnAgent() now probes the engine's protocol version once during initialization (via amplifier-agent version --json) and runs checkProtocolVersion() against PROTOCOL_VERSION_REQUIRED_BY_WRAPPER BEFORE constructing a SessionHandle. Mismatch fails fast wrapper-side with AaaError(protocol_version_mismatch), saving a full subprocess roundtrip later. Adds two new SpawnAgentParams fields: - allowProtocolSkew?: boolean — bypass the check (mirrors engine's host_config.allowProtocolSkew) - _engineVersionProbe?: () => Promise<EngineVersionPayload> — test-only injection point for the probe Also bumps PROTOCOL_VERSION_REQUIRED_BY_WRAPPER from "0.2.0" to "0.3.0" to match the engine's current wire protocol (amplifier_agent_lib.protocol.methods.PROTOCOL_VERSION). The wrapper was shipping with a stale pin; the new check would have surfaced this at startup. Closes #9. * feat(wrapper-ts): add runChildProcess injection point (#3) Adds SpawnAgentParams.runChildProcess?: ChildProcessFactory — a public seam to substitute the subprocess factory used inside SessionHandle. When set, the wrapper invokes the factory in place of child_process.spawn, preserving the same options shape (detached, stdio, env, optional cwd). Useful for: - Sandboxing (e.g. wrapping the child in a container or namespace) - Test doubles (e.g. EventEmitter fakes that drive scripted outputs) - Harness wrapping (e.g. observing the subprocess from outside) ChildProcessFactory is exported as a @public type from index.ts. Closes #3. * feat(wrapper-ts)!: wire Transport NDJSON pipeline + dispatch to display.onEvent (#2, #4, #6) The engine emits one JSON object per line on the child subprocess's stderr stream for each wire-protocol notification (progress, result/delta, result/final, thinking/delta, thinking/final, tool/started, tool/completed, approval/request, approval/timeout, plus wire-level error). Before this change the wrapper buffered stderr as raw text and silently dropped every event — the existing Transport class implemented NDJSON parsing but was never wired anywhere (dead code). This change: - Adds parseNdjsonStream(stream, {onJson, onNonJson?}) — a standalone helper extracted from the parsing logic Transport already had. Resolves when the stream emits 'close'. Exported @public. - Wires parseNdjsonStream onto child.stderr inside SessionHandle.makeIterable(). JSON lines are parsed into 'notification' DisplayEvents and dispatched to params.display?.onEvent. Non-JSON lines (and JSON lines, for completeness) are still accumulated into stderrBuf so the stderrTail surface on parseRunOutput remains diagnostically useful. - Extends the DisplayEvent discriminated union with a new {type: 'notification', method: string, params: unknown} variant. **BREAKING**: existing exhaustive switch statements on event.type will no longer be exhaustive without a notification branch. - Threads SpawnAgentParams.display through to SessionHandle so the callback that was previously silently dropped is now actually fired (Issue #4). Closes #2, #4, #6. BREAKING CHANGE: display.onEvent callbacks are now actually invoked with wire-event notifications. Callers that registered onEvent expecting it to be a no-op may observe new event flow. The DisplayEvent union has a new 'notification' variant; exhaustive switch statements need a corresponding branch. * feat(wrapper-ts): surface --config flag via SpawnAgentParams.configPath (#1) Engine PR #27 / v0.4.0 added the --config <path> flag and the host_config layer (approval mode, MCP servers, provider defaults, allowProtocolSkew, etc.). The wrapper had no surface to forward this, so callers had to fall back to AMPLIFIER_AGENT_CONFIG in env.extra. This change: - Adds SpawnAgentParams.configPath?: string (public, @public TSDoc). - Adds AssembleArgvInput.configPath?: string. - assembleArgv emits --config <path> when configPath is set. - Threads configPath through SessionHandleParams to the per-submit argv assembly. Also drive-by adds approvalMode field to AssembleArgvInput (used by #10's commit). The argv-builder now reads input.approvalMode and emits -y / -n / nothing accordingly. Default remains -y for backward compat with callers that haven't opted into the approval API. Closes #1. * feat(wrapper-ts)!: wire approval API to engine -y/-n + approval.mode (#10) Previously, SpawnAgentParams.approval threw AaaError( approval_not_supported_in_v1) whenever set because it required the mid-turn onRequest callback that v1 doesn't support. This change extends SpawnAgentParams.approval to also accept the static-policy shape { mode: 'yes' | 'no' | 'prompt' }, which maps to engine argv: - 'yes' -> -y (auto-allow every tool call) - 'no' -> -n (auto-deny every tool call) - 'prompt' -> emit no flag; engine falls back to host_config.approval.mode or the bundle's TTY-based default. This is how a host hands policy resolution back to the engine. The legacy { onRequest, timeoutMs } form still throws approval_not_supported_in_v1 — the Mode A wire has no mid-turn channel. Mid-turn callbacks will return when WG-4 lands. Engine compatibility: { mode: 'prompt' } requires amplifier-agent >= 0.4.0 (PR #34 added host_config.approval.mode). Closes #10. BREAKING CHANGE: SpawnAgentParams.approval is now a union shape; callers passing { mode } no longer hit approval_not_supported_in_v1. Callers that defensively catch that error need to remove the try/catch when migrating to the mode shape. * feat(wrapper-ts): implement getEngineInfo() — engineVersion + bundleDigest (#7) Closes the Task-9 TODO: getEngineInfo() now returns the values captured during the engine version probe that spawnAgent() runs at init (Issue #9). Previously both fields were hardcoded empty strings. - engineVersion populated from `amplifier-agent version --json` payload's `version` field. - bundleDigest populated from the probe payload's optional `bundleDigest` field. The engine's current `version --json` output (from admin/version_info.py) only emits {version, protocolVersion} — bundleDigest will be empty string until a future engine release exposes it. Forward-compatible: when the engine adds it, the wrapper picks it up automatically with no further changes. DONE_WITH_CONCERNS for the bundleDigest follow-up: filed as an engine-side ask for a future PR. The wrapper does what it can with the data the engine surface exposes today; the contract is wired so the field will populate the moment the engine emits it. Closes #7. * chore(wrapper-ts): rebuild dist after hardening release changes Mirrors PR #29 / #31 pattern: dist/ is tracked so consumers installing from the git tarball get the compiled artifacts without a build step. Regenerated from npm run build after issues #1, #2, #3, #4, #5, #6, #7, #9, #10 landed. * chore(release): bump amplifier-agent-ts to 0.6.0 + CHANGELOG Wrapper hardening release closing 8 consumer-reported gaps at 0.5.0: #1 configPath surface #2 stderr NDJSON parsing #3 runChildProcess injection #4 display.onEvent dispatch #5 public re-exports #6 Transport dead code (root cause of #2/#4) #7 getEngineInfo() implementation #9 checkProtocolVersion() wired into init path #10 approval API mapped to engine -y/-n + approval.mode Issue #8 in the consumer report was a misread — InitializeParams. mcpConfigPath is intentionally retained in protocol-0.3.0. No type change needed; the schema is canonical and correct. This is a minor bump per 0.x convention even though some changes are BREAKING — the wrapper hasn't shipped a 1.0 yet, so breaking changes ride minor bumps. See CHANGELOG for the BREAKING list. Engine compatibility: requires amplifier-agent >= 0.4.0. Pinned protocol: 0.3.0. --------- Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a persistent host-set config layer between the sealed bundle and per-turn argv,
and removes the
hostCapabilitiessurface that has zero read sites today.Implements two paired designs:
docs/designs/2026-06-01-drop-host-capabilities.md(Phase 1)docs/designs/2026-06-01-host-config-layer-revisit.md(Phase 2)Phase 1 — Drop
hostCapabilities(BREAKING)Removes the write-only
hostCapabilitiesinfrastructure across engine, wrappers, schemas, conformance fixtures, and tests. Both v1 capabilities (supports_steering,supports_structured_errors) resolved to "didn't need engine negotiation" — no behavior was gated on them.Breaking changes (wrapper API):
wrappers/typescript/src/index.ts: dropSpawnAgentParams.hostfield; drop exportedHostCapabilities+InitializeHostParamstypeswrappers/python/src/amplifier_agent_client/: drophost/host_capabilitiesparams fromspawn_agent,assemble_argv,SessionHandleParams--host-capabilitiesargv flag removed fromamplifier-agent run— old callers see clickUsageError, exit 2Cross-repo follow-up: the
nanoclawadapter must drophost: { capabilities: ... }from itsspawnAgentcall. Tracked separately. ← Reviewer action requiredPhase 2 — Host config layer
Adds
--config <path>resolution (flag >$AMPLIFIER_AGENT_CONFIGenv > no config tier → bundle defaults), JSON format withjson.load, pass-through schema mirroring downstream module configs, layered merge over bundle declarations.New surface:
--config <path>argv flag (wires the previously-stub atsingle_turn.py:406)$AMPLIFIER_AGENT_CONFIGenv varmcp,approval,provider,allowProtocolSkewRemoved argv surface (BREAKING — subsumed by config):
--env-allowlist,--env-extra,--allow-protocol-skewAMPLIFIER_AGENT_ALLOW_PROTOCOL_SKEWenv varInternal cleanup:
provider_detect.pydeleted (vestigial — provider selection now from config or newbundle.mddefault_provider:field)persistence.py(was duplicated inbundle/cache.pyandadmin/doctor.py)amplifier-agent config showextended to report resolved path, source tier, and parsed values — survives parse failures gracefullyNew module:
src/amplifier_agent_lib/config/{loader,merger}.py+tests/config/Stats
ruff checkTests
amplifier-agent run --host-capabilities '{}' "hi"→ clickUsageError, exit 2 ✓Pre-existing failures NOT introduced by this work
17 engine-suite failures pre-date this PR and are out of scope. Verified by
git stash+ re-run against the baseline. Root causes:test_engine.py,test_engine_with_real_bundle.py,test_phase_2_1_exit_gate.py,test_protocol_gen.pyhardcodeprotocolVersion: "0.1.0"but engine speaks0.2.0since commitea51d05--mcp-serversrename gap —test_mode_a_v2_envelope.py,test_single_turn_init_params.pyuse the renamed flag (renamed to--mcp-config-pathinea51d05)pyproject.tomlwheel-build duplicate-include —tool.hatch.build.targets.wheel.force-includedouble-countsprotocol/schemas/Recommend a follow-up tracking issue: "protocol-0.2.0 rename drift + wheel-build cleanup" — independent of this PR's scope.
Design decision history
This PR locks decisions D1–D10 of the host config layer revisit. Key choices made during design conversation:
safe_loadmandate, no wrapper YAML dep, easier library extensibility$HOMEcollisionmcp:,approval:,provider:mirror their module's schemas--protocol-versionSupersedes
Follow-up actions (out of scope)
host: { capabilities }from adapterspawnAgentcall" — text drafted indocs/plans/2026-06-01-drop-host-capabilities-implementation.mdH3pnpm-lock.yamlhas a pnpm-version-drift marker (.: {}) — unrelated, left uncommitted in this PR