Skip to content

feat(core)!: unify rich results, canonical imports, and ordered injections for 2.0 - #109

Merged
Brian Krabach (bkrabach) merged 32 commits into
mainfrom
feat/tool-result-content
Sep 21, 2026
Merged

Brian Krabach (bkrabach) merged 32 commits into
mainfrom
feat/tool-result-content

Conversation

@bkrabach

@bkrabach Brian Krabach (bkrabach) commented Sep 12, 2026 •

Copy link
Copy Markdown
Collaborator

Tool results lose rich content across native and RPC boundaries, source validation can import a different module identity than runtime mounting, and combined hook injections can lose per-item lifetime and provenance. This carrier preserves rich results and canonical module identity, adds ordered context injections, and reconciles native session metadata, model pricing, precise usage cost, and asynchronous JavaScript hooks.

The complete changes from #103, #110, and #111 are included by Git ancestry on current main, including #112 typed module-load diagnostics. The CLI prerequisite microsoft/amplifier-app-cli#358 is merged at 409eb088.

Version and migration:

  • The candidate is 2.0.0 because public Rust ToolResult protobuf conversions become fallible and public result/model struct literals gain fields.
  • docs/MIGRATING_TO_2_0.md documents Rust caller changes, strict source identity, ordered injection ownership, native-wheel requirements, and CLI-first rollout. Existing Python/JSON callers may omit new optional fields.
  • Native regression coverage exercises mixed durable/ephemeral injections, registry-bound provenance, batch validation before writes/budget charges, ordered persistence, and metadata preservation.
  • The smoke runner now fails on every nonzero amplifier exit, including failures whose output does not match a known exception pattern.

Validation at head 35f7aaed5816c76fa698ae685649b51e3acd8cc9:

  • All eight GitHub checks passed, including Python 3.11/3.12/3.13, native Node bindings, default/WASM Rust, formatting/Clippy, protobuf reproducibility, and CLA.
  • Local native Core 2.0.0: 1,115 Python tests passed, 1 skipped; 523 default Rust unit/integration/doc tests passed; 70 Node tests passed; default, WASM, and Node Clippy passed. The complete WASM suite also passed before the version-only bump.
  • All four Python protobuf stubs reproduce byte-for-byte. Mock smoke-runner process exits 0, 7, and 124 produce the expected success, failure, and timeout outcomes.
  • CLI full suite passed in separate environments against published Core 1.6.1 and native Core 2.0.0: 2,412 passed, 45 skipped, 13 deselected, 1 expected failure each; 34 focused source/credential tests also passed with each version.
  • Current Unified consumer boundaries: 77 passed, 1 skipped. The actual Unified 0.19.19 cache/diagnostic fixture passed all four entrypoints with zero model calls, including strict invalid-module metadata. These used an isolated native debug-wheel environment with explicitly reused qualified dependencies.
  • A fresh Linux aarch64 release wheel built on Spark and passed pristine import checks plus the default Docker recipe smoke. The qualifying run used merged CLI 409eb088, Foundation c6b33a3b, and Core 2.0.0, exited 0, and completed the real recipe-author example. No CLI/Foundation local-source override or prompt change was used. The script used --skip-build immediately after the separate fresh Docker build of this exact source.

Release-wheel SHA256: 7494b52ba1342e8f9bb3d7409933b62216cc39edcbeb59305826f66261608a0e.

Local disk exhaustion and the first smoke run's pre-merge CLI resolution are retained in review evidence; the final qualifying build and smoke ran on Spark. This source merge does not tag or publish packages and does not claim an upgrade of any running host or worker.

Manoj Prabhakar Paidiparthy and others added 22 commits June 30, 2026 15:37
Add a Pricing model (input/output per-million rates, optional
cache-read/cache-write rates, currency, as_of) and an optional
`pricing` field on ModelInfo. Providers can now surface their existing
internal rate tables (e.g., the Anthropic provider's _RATES dict)
through /v1/models so HTTP-bridge applications such as
amplifier-app-opencode can display cost estimates without maintaining
their own hardcoded pricing tables.

Backwards-compatible: pricing defaults to None, so providers that
don't populate it (local providers like ollama, self-hosted backends
like vllm) are unaffected, and existing ModelInfo construction call
sites continue to work unchanged.

Fixes: microsoft-amplifier/amplifier-support#295

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Applies triage feedback to the Pricing model added in 8977778:

- Removed the `as_of` date field entirely. All Pricing fields are now
  float/str only -- no dates. The unused `date` import is removed too.
- Added ISO 4217 currency validation via a field_validator: currency
  must match `^[A-Z]{3}$`.
- Added a docstring note clarifying that Pricing rate fields use float
  (not Decimal) because they are display-only estimates for /v1/models,
  distinct from Usage.cost_usd which is Decimal and rejects float.

Tests: removed as_of assertions, added a JSON round-trip test
(model_dump / model_dump(mode="json") / model_dump_json all succeed
now that there are no date fields) and a currency validation test
covering valid and invalid ISO 4217 codes.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Threads the Pricing model added in 8977778 through the full Rust
ecosystem: native crate, WASM guest crate, proto wire format, gRPC
bridge, and equivalence tests.

- crates/amplifier-core/src/models.rs: adds a native `Pricing` struct
  (input_per_million, output_per_million, optional cache rates,
  currency defaulting to "USD") and `ModelInfo.pricing: Option<Pricing>`.
- crates/amplifier-guest/src/types.rs: duplicates the `Pricing` struct
  (this crate has no amplifier-core dependency) and adds the same
  `pricing` field to its `ModelInfo`. Updates existing tests to cover
  the new field.
- proto/amplifier_module.proto: adds `string pricing_json = 7` to
  `ModelInfo`, mirroring the existing `defaults_json` string-blob
  pattern rather than a nested message type. Regenerates
  src/generated/amplifier.module.rs via `cargo build` (protoc
  installed locally).
- crates/amplifier-core/src/generated/conversions.rs: extends the
  native <-> proto ModelInfo conversions for pricing/pricing_json.
  Proto -> native intentionally returns None (not a synthetic
  default) on parse failure, since there is no meaningful default
  price. Adds roundtrip and failure-mode tests.
- crates/amplifier-core/src/bridges/grpc_provider.rs: adds
  `parse_pricing_json`, threaded through `list_models()`, with unit
  tests for the valid/empty/invalid cases.
- crates/amplifier-core/src/bridges/wasm_provider.rs: no changes
  needed -- it deserializes directly into the native `ModelInfo` via
  `serde_json::from_slice`, so `pricing` is picked up automatically
  via `#[serde(default)]`.
- crates/amplifier-core/src/generated/equivalence_tests.rs: extends
  the ModelInfo proto equivalence test to cover `pricing_json`.
- tests/fixtures/wasm/src/echo-provider/src/lib.rs and
  crates/amplifier-guest/src/lib.rs: update existing ModelInfo
  literals for the new required field.
- bindings/python/tests/test_schema_sync.py: adds a Python <-> JSON
  round-trip test for ModelInfo.pricing.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
CI's rustfmt (stable) wraps the pricing_json line differently than
the local rustfmt run that produced the prior commit. Applying the
CI-preferred formatting to unblock the fmt check on PR #92.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…ust kernel

`docs/specs/CONTRIBUTION_CHANNELS.md` lists `session.metadata` as a runtime
passthrough channel; `tests/test_session_metadata.py` specifies it; and
`python/amplifier_core/session.py` implements it. The Rust switchover shipped
without it.

Production does `from amplifier_core import AmplifierSession`, which is
`RustSession` (`python/amplifier_core/__init__.py`). Its lifecycle emit built
the payload from `{session_id, parent_id}` only, so configured metadata was
dropped before any hook saw it. The pure-Rust kernel had the same omission.
`session:fork` was unaffected -- it is emitted by the shared Python helper
`_session_init.py`, which already honored the contract. So one contract had
three payload constructions and two of them disagreed with it.

The metadata tests were green throughout, because they import the *pure-Python*
`amplifier_core.session.AmplifierSession` -- the class no runtime consumer
executes. That blind spot is what let this ship dead.

- `session_metadata_passthrough()` in `crates/amplifier-core/src/session.rs`:
  one shared reader, so the Rust emit paths cannot drift apart again. Mirrors
  the Python kernel's `if session_metadata:` guard, so absent *or* empty
  metadata leaves the payload byte-identical to before.
- Merged into the bindings emit (cached at construction alongside
  `session_id`/`parent_id`) and into the pure-Rust emit.
- `bindings/python/tests/test_session_metadata_rust.py`: the parallel suite
  against `RustSession` that the existing tests could not provide.

Additive only. No new event, no new top-level payload key, no schema change.

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Related to #90. Preserve optional exact decimal cost text through Rust, protobuf, Python, and WASM boundaries.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Related to #61. Exercise Promise-returning hook handlers in a child process and preserve generated Node binding declarations.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Related to #101, #95, #100, #104, #107, and #108. Pin workflow actions and record the reviewed dependency updates.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Refresh the fixture hash and make concurrency and test logging regressions deterministic.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Ensure Python and native/WASM dispatch use the coordinator registry, and verify mounted deny-hook behavior.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Derive the proto-check generator versions from uv.lock and compare all four committed Python stubs byte-for-byte, including the package import adjustment. Refresh the checked-in schema stub from the locked toolchain and trigger the workflow when its inputs change.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Prefer current Python TaskLocals for coroutine hooks and retain only the registration event loop as a native-callback fallback. Add loop and context propagation coverage plus a real passthrough orchestrator emit-hook regression fixture and rebuilt fixture binary.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Write generated protobuf output to pytest temporary directories, assert the expected files exist, and refresh the two root stubs from the locked generator without modifying tracked sources during the test suites.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@bkrabach Brian Krabach (bkrabach) changed the title feat(core): add canonical text and image content to ToolResult feat(core): add rich tool results, session metadata, and pricing Sep 12, 2026
Related to #110.

Integrates all original PR #110 commits as ancestry while retaining the canonical source-module loading implementation and regression coverage.

Version metadata is reconciled to provisional 1.6.1 pending the core owner SemVer decision; this commit does not select or authorize the 1.6.2 release candidate.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Add independent async resolver coverage for same-source module reuse and cross-source collision rejection.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@bkrabach Brian Krabach (bkrabach) changed the title feat(core): add rich tool results, session metadata, and pricing feat(core)!: unify rich results, canonical imports, and ordered injections for 2.0 Sep 21, 2026
@bkrabach
Brian Krabach (bkrabach) marked this pull request as ready for review September 21, 2026 10:48
@bkrabach
Brian Krabach (bkrabach) merged commit 4f53e0f into main Sep 21, 2026
8 checks passed
@bkrabach

Copy link
Copy Markdown
Collaborator Author

Combined-family landing receipt: this PR was merged at 4f53e0f666aa370ec7e579bf282b7a4b6c96fbbc after CLI companion microsoft/amplifier-app-cli#358 merged at 409eb088c8a0fea652315e4ea0dcec949672829d.

The reviewed head 35f7aaed5816c76fa698ae685649b51e3acd8cc9 and merged main have identical tree 6e33e97fb6330343e41e3ecfc86775a7195fbda5. Heads of #103, #110, and #111 are all ancestors of this carrier. GitHub marked those PRs merged through this inclusion; they were not independently merged into main.

All eight pre-merge CI checks passed. Additional combined-state evidence: 1,115 Python tests; 523 default Rust tests; 70 Node tests; full CLI 2,412 tests against both published Core 1.6.1 and native Core 2.0.0; current Unified boundaries 77 passed/1 skipped; actual Unified 0.19.19 four cache/diagnostic entrypoints 4 passed with zero model calls. Fresh Linux release-wheel pristine imports and the unmodified default recipe prompt passed with exit 0 using merged CLI 409eb088 and Foundation c6b33a3b.

The release wheel has SHA256 7494b52ba1342e8f9bb3d7409933b62216cc39edcbeb59305826f66261608a0e. Migration instructions are in docs/MIGRATING_TO_2_0.md. No version tag, package publication, or production installation was performed by this review lane.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants