feat(core)!: unify rich results, canonical imports, and ordered injections for 2.0 - #109
Conversation
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>
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>
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>
|
Combined-family landing receipt: this PR was merged at The reviewed head 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 The release wheel has SHA256 |
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:
ToolResultprotobuf conversions become fallible and public result/model struct literals gain fields.docs/MIGRATING_TO_2_0.mddocuments 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.Validation at head
35f7aaed5816c76fa698ae685649b51e3acd8cc9:409eb088, Foundationc6b33a3b, 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-buildimmediately 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.