diff --git a/Cargo.lock b/Cargo.lock index 169615e..6a1520b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "amplifier-core" -version = "1.0.9" +version = "1.0.10" dependencies = [ "chrono", "log", @@ -59,7 +59,7 @@ dependencies = [ [[package]] name = "amplifier-core-py" -version = "1.0.9" +version = "1.0.10" dependencies = [ "amplifier-core", "log", diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index b09c5e2..e2b1350 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -493,6 +493,7 @@ impl PySession { /// Rust controls the lifecycle: /// 1. Checks initialization flag (error if not initialized) /// 2. Emits pre-execution events (session:start or session:resume) + /// with optional `raw` field when session.raw=true /// 3. Delegates orchestrator call to `_session_exec.run_orchestrator()` /// via `into_future` (Python handles mount point access + kwargs) /// 4. Checks cancellation after execution @@ -512,32 +513,27 @@ impl PySession { // Step 2: Prepare the Python orchestrator coroutine (we have the GIL here) let helper = py.import("amplifier_core._session_exec")?; let run_fn = helper.getattr("run_orchestrator")?; - let debug_fn = helper.getattr("emit_debug_events")?; + let raw_fn = helper.getattr("emit_raw_field_if_configured")?; // Prepare the orchestrator call coroutine let orch_coro = run_fn.call1((self.coordinator.bind(py), &prompt))?; let orch_coro_py: Py = orch_coro.unbind(); - // Determine event names based on is_resumed - let (event_base, event_debug, event_raw) = if self.is_resumed { - ( - "session:resume", - "session:resume:debug", - "session:resume:raw", - ) + // Determine event name based on is_resumed + let event_base = if self.is_resumed { + "session:resume" } else { - ("session:start", "session:start:debug", "session:start:raw") + "session:start" }; - // Prepare debug events coroutine - let debug_coro = debug_fn.call1(( + // Prepare raw-field emission coroutine (no-op if session.raw=false) + let raw_coro = raw_fn.call1(( self.coordinator.bind(py), self.config.bind(py), &self.cached_session_id, - event_debug, - event_raw, + event_base, ))?; - let debug_coro_py: Py = debug_coro.unbind(); + let debug_coro_py: Py = raw_coro.unbind(); // Get the inner HookRegistry for direct Rust emit (avoids PyO3 Future/coroutine mismatch: // calling a #[pymethods] fn that uses future_into_py returns a Future object, but @@ -2632,35 +2628,14 @@ fn _engine(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(compute_delay, m)?)?; // ----------------------------------------------------------------------- - // Event constants — expose all 51 canonical events from amplifier_core + // Event constants — expose all 41 canonical events from amplifier_core // ----------------------------------------------------------------------- // Session lifecycle m.add("SESSION_START", amplifier_core::events::SESSION_START)?; - m.add( - "SESSION_START_DEBUG", - amplifier_core::events::SESSION_START_DEBUG, - )?; - m.add( - "SESSION_START_RAW", - amplifier_core::events::SESSION_START_RAW, - )?; m.add("SESSION_END", amplifier_core::events::SESSION_END)?; m.add("SESSION_FORK", amplifier_core::events::SESSION_FORK)?; - m.add( - "SESSION_FORK_DEBUG", - amplifier_core::events::SESSION_FORK_DEBUG, - )?; - m.add("SESSION_FORK_RAW", amplifier_core::events::SESSION_FORK_RAW)?; m.add("SESSION_RESUME", amplifier_core::events::SESSION_RESUME)?; - m.add( - "SESSION_RESUME_DEBUG", - amplifier_core::events::SESSION_RESUME_DEBUG, - )?; - m.add( - "SESSION_RESUME_RAW", - amplifier_core::events::SESSION_RESUME_RAW, - )?; // Prompt lifecycle m.add("PROMPT_SUBMIT", amplifier_core::events::PROMPT_SUBMIT)?; @@ -2688,19 +2663,9 @@ fn _engine(m: &Bound<'_, PyModule>) -> PyResult<()> { )?; m.add("PROVIDER_RESOLVE", amplifier_core::events::PROVIDER_RESOLVE)?; - // LLM request/response + // LLM events m.add("LLM_REQUEST", amplifier_core::events::LLM_REQUEST)?; - m.add( - "LLM_REQUEST_DEBUG", - amplifier_core::events::LLM_REQUEST_DEBUG, - )?; - m.add("LLM_REQUEST_RAW", amplifier_core::events::LLM_REQUEST_RAW)?; m.add("LLM_RESPONSE", amplifier_core::events::LLM_RESPONSE)?; - m.add( - "LLM_RESPONSE_DEBUG", - amplifier_core::events::LLM_RESPONSE_DEBUG, - )?; - m.add("LLM_RESPONSE_RAW", amplifier_core::events::LLM_RESPONSE_RAW)?; // Content block events m.add( diff --git a/bindings/python/tests/test_event_constants.py b/bindings/python/tests/test_event_constants.py index a38b845..e9b09c6 100644 --- a/bindings/python/tests/test_event_constants.py +++ b/bindings/python/tests/test_event_constants.py @@ -3,18 +3,12 @@ import pytest -# All 51 event constant names that should be importable from _engine +# All 41 event constant names that should be importable from _engine ALL_EVENT_NAMES = [ "SESSION_START", - "SESSION_START_DEBUG", - "SESSION_START_RAW", "SESSION_END", "SESSION_FORK", - "SESSION_FORK_DEBUG", - "SESSION_FORK_RAW", "SESSION_RESUME", - "SESSION_RESUME_DEBUG", - "SESSION_RESUME_RAW", "PROMPT_SUBMIT", "PROMPT_COMPLETE", "PLAN_START", @@ -27,11 +21,7 @@ "PROVIDER_TOOL_SEQUENCE_REPAIRED", "PROVIDER_RESOLVE", "LLM_REQUEST", - "LLM_REQUEST_DEBUG", - "LLM_REQUEST_RAW", "LLM_RESPONSE", - "LLM_RESPONSE_DEBUG", - "LLM_RESPONSE_RAW", "CONTENT_BLOCK_START", "CONTENT_BLOCK_DELTA", "CONTENT_BLOCK_END", @@ -60,7 +50,7 @@ class TestAllEventConstantsImportable: - """Test that all 51 event constants are importable from _engine and are strings.""" + """Test that all 41 event constants are importable from _engine and are strings.""" @pytest.mark.parametrize("name", ALL_EVENT_NAMES) def test_event_constant_importable_and_is_string(self, name): @@ -91,30 +81,30 @@ def test_provider_tool_sequence_repaired(self): class TestAllEventsList: - """Test that ALL_EVENTS is exposed as a list with all 51 items.""" + """Test that ALL_EVENTS is exposed as a list with all 41 items.""" def test_all_events_is_list(self): - from amplifier_core._engine import ALL_EVENTS + from amplifier_core.events import ALL_EVENTS assert isinstance(ALL_EVENTS, list), ( f"ALL_EVENTS should be a list, got {type(ALL_EVENTS)}" ) def test_all_events_count(self): - from amplifier_core._engine import ALL_EVENTS + from amplifier_core.events import ALL_EVENTS - assert len(ALL_EVENTS) == 51, f"Expected 51 events, got {len(ALL_EVENTS)}" + assert len(ALL_EVENTS) == 41, f"Expected 41 events, got {len(ALL_EVENTS)}" def test_all_events_contains_all_constants(self): - import amplifier_core._engine as engine - from amplifier_core._engine import ALL_EVENTS + import amplifier_core.events as events + from amplifier_core.events import ALL_EVENTS for name in ALL_EVENT_NAMES: - value = getattr(engine, name) + value = getattr(events, name) assert value in ALL_EVENTS, f"{name}={value!r} not found in ALL_EVENTS" def test_all_events_all_strings(self): - from amplifier_core._engine import ALL_EVENTS + from amplifier_core.events import ALL_EVENTS for event in ALL_EVENTS: assert isinstance(event, str), ( diff --git a/bindings/python/tests/test_python_stubs.py b/bindings/python/tests/test_python_stubs.py index 03d2c34..4c77073 100644 --- a/bindings/python/tests/test_python_stubs.py +++ b/bindings/python/tests/test_python_stubs.py @@ -23,7 +23,7 @@ def test_events_reexport_provider_throttle(): def test_events_reexport_all_events(): from amplifier_core.events import ALL_EVENTS - assert len(ALL_EVENTS) == 51 + assert len(ALL_EVENTS) == 41 def test_capabilities_reexport_tools(): diff --git a/bindings/python/tests/test_schema_sync.py b/bindings/python/tests/test_schema_sync.py index 5850f4b..62ecf22 100644 --- a/bindings/python/tests/test_schema_sync.py +++ b/bindings/python/tests/test_schema_sync.py @@ -119,7 +119,7 @@ def test_event_constants_match(): assert TOOL_ERROR == "tool:error" assert CANCEL_REQUESTED == "cancel:requested" assert CANCEL_COMPLETED == "cancel:completed" - assert len(ALL_EVENTS) == 51 + assert len(ALL_EVENTS) == 41 def test_hook_result_json_roundtrip(): diff --git a/bindings/python/tests/test_switchover_session.py b/bindings/python/tests/test_switchover_session.py index 62fe3ba..65af6ba 100644 --- a/bindings/python/tests/test_switchover_session.py +++ b/bindings/python/tests/test_switchover_session.py @@ -242,12 +242,12 @@ def test_session_exec_is_thin_helper(): """_session_exec.py must still exist as a thin boundary helper called by Rust. Rust's PySession::execute() imports amplifier_core._session_exec and calls - run_orchestrator() and emit_debug_events(). CANNOT be deleted. + run_orchestrator() and emit_raw_field_if_configured(). CANNOT be deleted. """ - from amplifier_core._session_exec import run_orchestrator, emit_debug_events + from amplifier_core._session_exec import run_orchestrator, emit_raw_field_if_configured assert callable(run_orchestrator) - assert callable(emit_debug_events) + assert callable(emit_raw_field_if_configured) def test_collect_helper_is_boundary_helper(): diff --git a/crates/amplifier-core/src/events.rs b/crates/amplifier-core/src/events.rs index c47a14d..5f8766a 100644 --- a/crates/amplifier-core/src/events.rs +++ b/crates/amplifier-core/src/events.rs @@ -2,8 +2,9 @@ //! //! Every hook, log entry, and observability span in Amplifier references events //! by these string constants. The taxonomy follows a `namespace:action` pattern -//! (e.g. `"session:start"`, `"tool:pre"`), with optional `:debug` / `:raw` -//! suffixes for verbosity tiers. +//! (e.g. `"session:start"`, `"tool:pre"`). Verbosity tiers (`:debug` / `:raw`) +//! have been removed — callers may include an optional `raw` field in event +//! payloads when `session.raw: true` is configured. //! //! # Categories //! @@ -13,7 +14,7 @@ //! | Prompt | `prompt:` | Prompt submission and completion | //! | Planning | `plan:` | Optional orchestration planning phases | //! | Provider | `provider:` | High-level provider call events | -//! | LLM | `llm:` | Raw LLM request/response with debug tiers | +//! | LLM | `llm:` | LLM request/response events | //! | Content Block | `content_block:` | Real-time streaming display events | //! | Thinking | `thinking:` | Model thinking/reasoning events | //! | Tool | `tool:` | Tool invocation lifecycle | @@ -30,24 +31,12 @@ /// A new session has started. pub const SESSION_START: &str = "session:start"; -/// Session start with debug-level detail. -pub const SESSION_START_DEBUG: &str = "session:start:debug"; -/// Session start with raw (full) detail. -pub const SESSION_START_RAW: &str = "session:start:raw"; /// A session has ended. pub const SESSION_END: &str = "session:end"; /// A session has been forked. pub const SESSION_FORK: &str = "session:fork"; -/// Session fork with debug-level detail. -pub const SESSION_FORK_DEBUG: &str = "session:fork:debug"; -/// Session fork with raw (full) detail. -pub const SESSION_FORK_RAW: &str = "session:fork:raw"; /// A session has been resumed. pub const SESSION_RESUME: &str = "session:resume"; -/// Session resume with debug-level detail. -pub const SESSION_RESUME_DEBUG: &str = "session:resume:debug"; -/// Session resume with raw (full) detail. -pub const SESSION_RESUME_RAW: &str = "session:resume:raw"; // --- Prompt lifecycle --- @@ -79,20 +68,12 @@ pub const PROVIDER_TOOL_SEQUENCE_REPAIRED: &str = "provider:tool_sequence_repair /// A provider has been resolved (selected for use). pub const PROVIDER_RESOLVE: &str = "provider:resolve"; -// --- LLM request/response (with debug tiers) --- +// --- LLM request/response --- /// An LLM request has been issued. pub const LLM_REQUEST: &str = "llm:request"; -/// LLM request with debug-level detail. -pub const LLM_REQUEST_DEBUG: &str = "llm:request:debug"; -/// LLM request with raw (full) detail. -pub const LLM_REQUEST_RAW: &str = "llm:request:raw"; /// An LLM response has been received. pub const LLM_RESPONSE: &str = "llm:response"; -/// LLM response with debug-level detail. -pub const LLM_RESPONSE_DEBUG: &str = "llm:response:debug"; -/// LLM response with raw (full) detail. -pub const LLM_RESPONSE_RAW: &str = "llm:response:raw"; // --- Content block events (real-time streaming display) --- @@ -177,15 +158,9 @@ pub const CANCEL_COMPLETED: &str = "cancel:completed"; /// matching the order used in the Python `ALL_EVENTS` list. pub const ALL_EVENTS: &[&str] = &[ SESSION_START, - SESSION_START_DEBUG, - SESSION_START_RAW, SESSION_END, SESSION_FORK, - SESSION_FORK_DEBUG, - SESSION_FORK_RAW, SESSION_RESUME, - SESSION_RESUME_DEBUG, - SESSION_RESUME_RAW, PROMPT_SUBMIT, PROMPT_COMPLETE, PLAN_START, @@ -198,11 +173,7 @@ pub const ALL_EVENTS: &[&str] = &[ PROVIDER_TOOL_SEQUENCE_REPAIRED, PROVIDER_RESOLVE, LLM_REQUEST, - LLM_REQUEST_DEBUG, - LLM_REQUEST_RAW, LLM_RESPONSE, - LLM_RESPONSE_DEBUG, - LLM_RESPONSE_RAW, CONTENT_BLOCK_START, CONTENT_BLOCK_DELTA, CONTENT_BLOCK_END, @@ -238,15 +209,9 @@ mod tests { #[test] fn session_constants() { assert_eq!(SESSION_START, "session:start"); - assert_eq!(SESSION_START_DEBUG, "session:start:debug"); - assert_eq!(SESSION_START_RAW, "session:start:raw"); assert_eq!(SESSION_END, "session:end"); assert_eq!(SESSION_FORK, "session:fork"); - assert_eq!(SESSION_FORK_DEBUG, "session:fork:debug"); - assert_eq!(SESSION_FORK_RAW, "session:fork:raw"); assert_eq!(SESSION_RESUME, "session:resume"); - assert_eq!(SESSION_RESUME_DEBUG, "session:resume:debug"); - assert_eq!(SESSION_RESUME_RAW, "session:resume:raw"); } #[test] @@ -272,11 +237,7 @@ mod tests { #[test] fn llm_constants() { assert_eq!(LLM_REQUEST, "llm:request"); - assert_eq!(LLM_REQUEST_DEBUG, "llm:request:debug"); - assert_eq!(LLM_REQUEST_RAW, "llm:request:raw"); assert_eq!(LLM_RESPONSE, "llm:response"); - assert_eq!(LLM_RESPONSE_DEBUG, "llm:response:debug"); - assert_eq!(LLM_RESPONSE_RAW, "llm:response:raw"); } #[test] @@ -379,26 +340,16 @@ mod tests { #[test] fn all_events_count() { - assert_eq!( - ALL_EVENTS.len(), - 51, - "Python source defines exactly 51 events" - ); + assert_eq!(ALL_EVENTS.len(), 41, "expected 41 canonical events"); } #[test] fn all_events_contains_every_constant() { let expected: &[&str] = &[ SESSION_START, - SESSION_START_DEBUG, - SESSION_START_RAW, SESSION_END, SESSION_FORK, - SESSION_FORK_DEBUG, - SESSION_FORK_RAW, SESSION_RESUME, - SESSION_RESUME_DEBUG, - SESSION_RESUME_RAW, PROMPT_SUBMIT, PROMPT_COMPLETE, PLAN_START, @@ -408,11 +359,7 @@ mod tests { PROVIDER_RETRY, PROVIDER_ERROR, LLM_REQUEST, - LLM_REQUEST_DEBUG, - LLM_REQUEST_RAW, LLM_RESPONSE, - LLM_RESPONSE_DEBUG, - LLM_RESPONSE_RAW, CONTENT_BLOCK_START, CONTENT_BLOCK_DELTA, CONTENT_BLOCK_END, diff --git a/docs/contracts/ORCHESTRATOR_CONTRACT.md b/docs/contracts/ORCHESTRATOR_CONTRACT.md index 88ab9db..44c5db2 100644 --- a/docs/contracts/ORCHESTRATOR_CONTRACT.md +++ b/docs/contracts/ORCHESTRATOR_CONTRACT.md @@ -2,11 +2,11 @@ contract_type: module_specification module_type: orchestrator contract_version: 1.0.0 -last_modified: 2025-01-29 +last_modified: 2026-03-05 related_files: - path: amplifier_core/interfaces.py#Orchestrator relationship: protocol_definition - lines: 26-52 + lines: 26-55 - path: amplifier_core/content_models.py relationship: event_content_types - path: ../specs/MOUNT_PLAN_SPECIFICATION.md @@ -50,6 +50,7 @@ class Orchestrator(Protocol): providers: dict[str, Provider], tools: dict[str, Tool], hooks: HookRegistry, + coordinator: ModuleCoordinator | None = None, ) -> str: """ Execute the agent loop with given prompt. @@ -60,6 +61,8 @@ class Orchestrator(Protocol): providers: Available LLM providers (keyed by name) tools: Available tools (keyed by name) hooks: Hook registry for lifecycle events + coordinator: Module coordinator for accessing shared services + (optional; passed by session.py in production) Returns: Final response string @@ -189,6 +192,54 @@ async def execute(self, prompt, context, providers, tools, hooks): | `turn_count` | int | Number of LLM call iterations | | `status` | string | Exit status: `"success"`, `"incomplete"`, or `"cancelled"` | +#### Required: execution:start and execution:end Events + +**All orchestrators MUST emit `execution:start` and `execution:end`** to mark the boundaries of every `execute()` invocation. These events are the primary observability signal used by the kernel for session lifecycle tracking, metrics, and tracing. + +- `execution:start` MUST be emitted at the **very beginning** of `execute()`, before any other work +- `execution:end` MUST be emitted on **ALL exit paths** — normal completion, error, and cancellation + +```python +async def execute(self, prompt, context, providers, tools, hooks, coordinator=None): + # REQUIRED: Emit at the very start of execute() + await hooks.emit("execution:start", {"prompt": prompt}) + + try: + # ... agent loop logic ... + + # REQUIRED: Emit on successful completion + await hooks.emit("execution:end", { + "response": final_response, + "status": "completed" + }) + return final_response + + except CancelledError: + # REQUIRED: Emit on cancellation + await hooks.emit("execution:end", { + "response": "", + "status": "cancelled" + }) + raise + + except Exception: + # REQUIRED: Emit on error + await hooks.emit("execution:end", { + "response": "", + "status": "error" + }) + raise +``` + +| Event | Field | Type | Description | +|-------|-------|------|-------------| +| `execution:start` | `prompt` | string | The user prompt passed to `execute()` | +| `execution:end` | `response` | string | Final response string (empty on error/cancellation) | +| `execution:end` | `status` | string | `"completed"`, `"cancelled"`, or `"error"` | + +> **Constants**: `execution:start` and `execution:end` are defined in `amplifier_core.events` +> (Python) and `amplifier_core::events` (Rust). Use the constants rather than string literals. + ### Hook Processing Handle HookResult actions: @@ -274,7 +325,9 @@ See [MOUNT_PLAN_SPECIFICATION.md](../specs/MOUNT_PLAN_SPECIFICATION.md) for full ## Observability -Register custom events your orchestrator emits: +Orchestrators **MUST** register the custom events they emit via the `observability.events` +contribution channel. This enables runtime introspection of which events are available and allows +tooling, dashboards, and other modules to discover orchestrator-specific signals. ```python coordinator.register_contributor( @@ -288,6 +341,10 @@ coordinator.register_contributor( ) ``` +> **Note**: The standard `execution:start`, `execution:end`, and `orchestrator:complete` events are +> registered by the kernel and do not need to be re-registered. Only register events that are +> unique to your orchestrator module. + See [CONTRIBUTION_CHANNELS.md](../specs/CONTRIBUTION_CHANNELS.md) for the pattern. --- @@ -312,19 +369,21 @@ Additional examples: ### Required -- [ ] Implements `execute(prompt, context, providers, tools, hooks) -> str` +- [ ] Implements `execute(prompt, context, providers, tools, hooks, coordinator=None) -> str` - [ ] `mount()` function with entry point in pyproject.toml +- [ ] **Emits `execution:start` with `{prompt}` at the very beginning of `execute()`** +- [ ] **Emits `execution:end` with `{response, status}` on ALL exit paths (success, error, cancellation)** - [ ] Emits standard events (provider:request/response, tool:pre/post) - [ ] **Emits `orchestrator:complete` at the end of execute()** - [ ] Handles HookResult actions appropriately - [ ] Manages context (add messages, check compaction) +- [ ] Registers custom observability events via `coordinator.register_contributor("observability.events", ...)` ### Recommended - [ ] Supports multiple providers - [ ] Implements max iterations limit (prevent infinite loops) - [ ] Handles provider errors gracefully -- [ ] Registers custom observability events - [ ] Supports streaming via async generators --- diff --git a/proto/amplifier_module_pb2.py b/proto/amplifier_module_pb2.py index 88fcbb3..53cf4ac 100644 --- a/proto/amplifier_module_pb2.py +++ b/proto/amplifier_module_pb2.py @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x61mplifier_module.proto\x12\x10\x61mplifier.module\"\x07\n\x05\x45mpty\"F\n\x08ToolSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x17\n\x0fparameters_json\x18\x03 \x01(\t\"9\n\x12ToolExecuteRequest\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x02 \x01(\t\"[\n\x13ToolExecuteResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06output\x18\x02 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x03 \x01(\t\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"\xd6\x01\n\nModuleInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x31\n\x0bmodule_type\x18\x04 \x01(\x0e\x32\x1c.amplifier.module.ModuleType\x12\x13\n\x0bmount_point\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x06 \x01(\t\x12\x1a\n\x12\x63onfig_schema_json\x18\x07 \x01(\t\x12\x14\n\x0c\x63\x61pabilities\x18\x08 \x03(\t\x12\x0e\n\x06\x61uthor\x18\t \x01(\t\"\x8c\x01\n\x0cMountRequest\x12:\n\x06\x63onfig\x18\x01 \x03(\x0b\x32*.amplifier.module.MountRequest.ConfigEntry\x12\x11\n\tmodule_id\x18\x02 \x01(\t\x1a-\n\x0b\x43onfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"_\n\rMountResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12.\n\x06status\x18\x03 \x01(\x0e\x32\x1e.amplifier.module.HealthStatus\"V\n\x13HealthCheckResponse\x12.\n\x06status\x18\x01 \x01(\x0e\x32\x1e.amplifier.module.HealthStatus\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xd9\x02\n\x0b\x43onfigField\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x35\n\nfield_type\x18\x02 \x01(\x0e\x32!.amplifier.module.ConfigFieldType\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x10\n\x08required\x18\x04 \x01(\x08\x12\x15\n\rdefault_value\x18\x05 \x01(\t\x12\x13\n\x0bplaceholder\x18\x06 \x01(\t\x12\x0f\n\x07options\x18\x07 \x03(\t\x12>\n\tshow_when\x18\x08 \x03(\x0b\x32+.amplifier.module.ConfigField.ShowWhenEntry\x12\x16\n\x0erequires_model\x18\t \x01(\x08\x12\x18\n\x10validation_regex\x18\n \x01(\t\x1a/\n\rShowWhenEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xbc\x01\n\rProviderError\x12\x37\n\nerror_type\x18\x01 \x01(\x0e\x32#.amplifier.module.ProviderErrorType\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x15\n\rprovider_name\x18\x03 \x01(\t\x12\r\n\x05model\x18\x04 \x01(\t\x12\x13\n\x0bstatus_code\x18\x05 \x01(\x05\x12\x11\n\tretryable\x18\x06 \x01(\x08\x12\x13\n\x0bretry_after\x18\x07 \x01(\x01\"\x97\x01\n\tToolError\x12\x33\n\nerror_type\x18\x01 \x01(\x0e\x32\x1f.amplifier.module.ToolErrorType\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\ttool_name\x18\x03 \x01(\t\x12\x0e\n\x06stdout\x18\x04 \x01(\t\x12\x0e\n\x06stderr\x18\x05 \x01(\t\x12\x11\n\texit_code\x18\x06 \x01(\x05\"d\n\tHookError\x12\x33\n\nerror_type\x18\x01 \x01(\x0e\x32\x1f.amplifier.module.HookErrorType\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\thook_name\x18\x03 \x01(\t\"\xef\x01\n\x0e\x41mplifierError\x12\x39\n\x0eprovider_error\x18\x01 \x01(\x0b\x32\x1f.amplifier.module.ProviderErrorH\x00\x12\x31\n\ntool_error\x18\x02 \x01(\x0b\x32\x1b.amplifier.module.ToolErrorH\x00\x12\x31\n\nhook_error\x18\x03 \x01(\x0b\x32\x1b.amplifier.module.HookErrorH\x00\x12\x17\n\rgeneric_error\x18\x04 \x01(\tH\x00\x12\x1a\n\x10validation_error\x18\x05 \x01(\tH\x00\x42\x07\n\x05\x65rror\"\x19\n\tTextBlock\x12\x0c\n\x04text\x18\x01 \x01(\t\"E\n\rThinkingBlock\x12\x10\n\x08thinking\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\t\"%\n\x15RedactedThinkingBlock\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\"=\n\rToolCallBlock\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\ninput_json\x18\x03 \x01(\t\"<\n\x0fToolResultBlock\x12\x14\n\x0ctool_call_id\x18\x01 \x01(\t\x12\x13\n\x0boutput_json\x18\x02 \x01(\t\"C\n\nImageBlock\x12\x12\n\nmedia_type\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x13\n\x0bsource_json\x18\x03 \x01(\t\"2\n\x0eReasoningBlock\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x0f\n\x07summary\x18\x02 \x01(\t\"\xf1\x03\n\x0c\x43ontentBlock\x12\x31\n\ntext_block\x18\x01 \x01(\x0b\x32\x1b.amplifier.module.TextBlockH\x00\x12\x39\n\x0ethinking_block\x18\x02 \x01(\x0b\x32\x1f.amplifier.module.ThinkingBlockH\x00\x12J\n\x17redacted_thinking_block\x18\x03 \x01(\x0b\x32\'.amplifier.module.RedactedThinkingBlockH\x00\x12:\n\x0ftool_call_block\x18\x04 \x01(\x0b\x32\x1f.amplifier.module.ToolCallBlockH\x00\x12>\n\x11tool_result_block\x18\x05 \x01(\x0b\x32!.amplifier.module.ToolResultBlockH\x00\x12\x33\n\x0bimage_block\x18\x06 \x01(\x0b\x32\x1c.amplifier.module.ImageBlockH\x00\x12;\n\x0freasoning_block\x18\x07 \x01(\x0b\x32 .amplifier.module.ReasoningBlockH\x00\x12\x30\n\nvisibility\x18\x08 \x01(\x0e\x32\x1c.amplifier.module.VisibilityB\x07\n\x05\x62lock\"B\n\x10\x43ontentBlockList\x12.\n\x06\x62locks\x18\x01 \x03(\x0b\x32\x1e.amplifier.module.ContentBlock\"\xca\x01\n\x07Message\x12$\n\x04role\x18\x01 \x01(\x0e\x32\x16.amplifier.module.Role\x12\x16\n\x0ctext_content\x18\x02 \x01(\tH\x00\x12;\n\rblock_content\x18\x03 \x01(\x0b\x32\".amplifier.module.ContentBlockListH\x00\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x14\n\x0ctool_call_id\x18\x05 \x01(\t\x12\x15\n\rmetadata_json\x18\x06 \x01(\tB\t\n\x07\x63ontent\"C\n\x0fToolCallMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x16\n\x0e\x61rguments_json\x18\x03 \x01(\t\"K\n\rToolSpecProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x17\n\x0fparameters_json\x18\x03 \x01(\t\"7\n\x10JsonSchemaFormat\x12\x13\n\x0bschema_json\x18\x01 \x01(\t\x12\x0e\n\x06strict\x18\x02 \x01(\x08\"u\n\x0eResponseFormat\x12\x0e\n\x04text\x18\x01 \x01(\x08H\x00\x12\x0e\n\x04json\x18\x02 \x01(\x08H\x00\x12\x39\n\x0bjson_schema\x18\x03 \x01(\x0b\x32\".amplifier.module.JsonSchemaFormatH\x00\x42\x08\n\x06\x66ormat\"\xa3\x01\n\x05Usage\x12\x15\n\rprompt_tokens\x18\x01 \x01(\x05\x12\x19\n\x11\x63ompletion_tokens\x18\x02 \x01(\x05\x12\x14\n\x0ctotal_tokens\x18\x03 \x01(\x05\x12\x18\n\x10reasoning_tokens\x18\x04 \x01(\x05\x12\x19\n\x11\x63\x61\x63he_read_tokens\x18\x05 \x01(\x05\x12\x1d\n\x15\x63\x61\x63he_creation_tokens\x18\x06 \x01(\x05\"@\n\x0b\x44\x65gradation\x12\x11\n\trequested\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tual\x18\x02 \x01(\t\x12\x0e\n\x06reason\x18\x03 \x01(\t\"\x9a\x03\n\x0b\x43hatRequest\x12+\n\x08messages\x18\x01 \x03(\x0b\x32\x19.amplifier.module.Message\x12.\n\x05tools\x18\x02 \x03(\x0b\x32\x1f.amplifier.module.ToolSpecProto\x12\x39\n\x0fresponse_format\x18\x03 \x01(\x0b\x32 .amplifier.module.ResponseFormat\x12\x13\n\x0btemperature\x18\x04 \x01(\x01\x12\r\n\x05top_p\x18\x05 \x01(\x01\x12\x19\n\x11max_output_tokens\x18\x06 \x01(\x05\x12\x17\n\x0f\x63onversation_id\x18\x07 \x01(\t\x12\x0e\n\x06stream\x18\x08 \x01(\x08\x12\x15\n\rmetadata_json\x18\t \x01(\t\x12\r\n\x05model\x18\n \x01(\t\x12\x13\n\x0btool_choice\x18\x0b \x01(\t\x12\x0c\n\x04stop\x18\x0c \x03(\t\x12\x18\n\x10reasoning_effort\x18\r \x01(\t\x12\x0f\n\x07timeout\x18\x0e \x01(\x01\x12\x17\n\x0f\x65xtensions_json\x18\x0f \x01(\t\"\xe0\x01\n\x0c\x43hatResponse\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x35\n\ntool_calls\x18\x02 \x03(\x0b\x32!.amplifier.module.ToolCallMessage\x12&\n\x05usage\x18\x03 \x01(\x0b\x32\x17.amplifier.module.Usage\x12\x32\n\x0b\x64\x65gradation\x18\x04 \x01(\x0b\x32\x1d.amplifier.module.Degradation\x12\x15\n\rfinish_reason\x18\x05 \x01(\t\x12\x15\n\rmetadata_json\x18\x06 \x01(\t\"F\n\nToolResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0boutput_json\x18\x02 \x01(\t\x12\x12\n\nerror_json\x18\x03 \x01(\t\"\x8d\x04\n\nHookResult\x12,\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1c.amplifier.module.HookAction\x12\x11\n\tdata_json\x18\x02 \x01(\t\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x19\n\x11\x63ontext_injection\x18\x04 \x01(\t\x12\x46\n\x16\x63ontext_injection_role\x18\x05 \x01(\x0e\x32&.amplifier.module.ContextInjectionRole\x12\x11\n\tephemeral\x18\x06 \x01(\x08\x12\x17\n\x0f\x61pproval_prompt\x18\x07 \x01(\t\x12\x18\n\x10\x61pproval_options\x18\x08 \x03(\t\x12\x18\n\x10\x61pproval_timeout\x18\t \x01(\x01\x12;\n\x10\x61pproval_default\x18\n \x01(\x0e\x32!.amplifier.module.ApprovalDefault\x12\x17\n\x0fsuppress_output\x18\x0b \x01(\x08\x12\x14\n\x0cuser_message\x18\x0c \x01(\t\x12>\n\x12user_message_level\x18\r \x01(\x0e\x32\".amplifier.module.UserMessageLevel\x12\x1b\n\x13user_message_source\x18\x0e \x01(\t\x12\"\n\x1a\x61ppend_to_last_tool_result\x18\x0f \x01(\x08\"\x8d\x01\n\tModelInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\x12\x16\n\x0e\x63ontext_window\x18\x03 \x01(\x05\x12\x19\n\x11max_output_tokens\x18\x04 \x01(\x05\x12\x14\n\x0c\x63\x61pabilities\x18\x05 \x03(\t\x12\x15\n\rdefaults_json\x18\x06 \x01(\t\"\xb7\x01\n\x0cProviderInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12+\n\x06models\x18\x04 \x03(\x0b\x32\x1b.amplifier.module.ModelInfo\x12\x34\n\rconfig_fields\x18\x05 \x03(\x0b\x32\x1d.amplifier.module.ConfigField\x12\x15\n\rmetadata_json\x18\x06 \x01(\t\"o\n\x0f\x41pprovalRequest\x12\x11\n\ttool_name\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x14\n\x0c\x64\x65tails_json\x18\x03 \x01(\t\x12\x12\n\nrisk_level\x18\x04 \x01(\t\x12\x0f\n\x07timeout\x18\x05 \x01(\x01\"F\n\x10\x41pprovalResponse\x12\x10\n\x08\x61pproved\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x10\n\x08remember\x18\x03 \x01(\x08\"A\n\x12ListModelsResponse\x12+\n\x06models\x18\x01 \x03(\x0b\x32\x1b.amplifier.module.ModelInfo\"O\n\x16ParseToolCallsResponse\x12\x35\n\ntool_calls\x18\x01 \x03(\x0b\x32!.amplifier.module.ToolCallMessage\"@\n\x1aOrchestratorExecuteRequest\x12\x0e\n\x06prompt\x18\x01 \x01(\t\x12\x12\n\nsession_id\x18\x02 \x01(\t\">\n\x1bOrchestratorExecuteResponse\x12\x10\n\x08response\x18\x01 \x01(\t\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"?\n\x11\x41\x64\x64MessageRequest\x12*\n\x07message\x18\x01 \x01(\x0b\x32\x19.amplifier.module.Message\"B\n\x13GetMessagesResponse\x12+\n\x08messages\x18\x01 \x03(\x0b\x32\x19.amplifier.module.Message\"J\n\x1bGetMessagesForRequestParams\x12\x14\n\x0ctoken_budget\x18\x01 \x01(\x05\x12\x15\n\rprovider_name\x18\x02 \x01(\t\"A\n\x12SetMessagesRequest\x12+\n\x08messages\x18\x01 \x03(\x0b\x32\x19.amplifier.module.Message\"5\n\x11HookHandleRequest\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x11\n\tdata_json\x18\x02 \x01(\t\"d\n\x1b\x43ompleteWithProviderRequest\x12\x15\n\rprovider_name\x18\x01 \x01(\t\x12.\n\x07request\x18\x02 \x01(\x0b\x32\x1d.amplifier.module.ChatRequest\";\n\x12\x45xecuteToolRequest\x12\x11\n\ttool_name\x18\x01 \x01(\t\x12\x12\n\ninput_json\x18\x02 \x01(\t\"3\n\x0f\x45mitHookRequest\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x11\n\tdata_json\x18\x02 \x01(\t\"V\n\x19\x45mitHookAndCollectRequest\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x11\n\tdata_json\x18\x02 \x01(\t\x12\x17\n\x0ftimeout_seconds\x18\x03 \x01(\x01\"4\n\x1a\x45mitHookAndCollectResponse\x12\x16\n\x0eresponses_json\x18\x01 \x03(\t\"(\n\x12GetMessagesRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\"Y\n\x17KernelAddMessageRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12*\n\x07message\x18\x02 \x01(\x0b\x32\x19.amplifier.module.Message\"a\n\x17GetMountedModuleRequest\x12\x13\n\x0bmodule_name\x18\x01 \x01(\t\x12\x31\n\x0bmodule_type\x18\x02 \x01(\x0e\x32\x1c.amplifier.module.ModuleType\"U\n\x18GetMountedModuleResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12*\n\x04info\x18\x02 \x01(\x0b\x32\x1c.amplifier.module.ModuleInfo\"=\n\x19RegisterCapabilityRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nvalue_json\x18\x02 \x01(\t\"$\n\x14GetCapabilityRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\":\n\x15GetCapabilityResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12\x12\n\nvalue_json\x18\x02 \x01(\t*\xbc\x01\n\nModuleType\x12\x1b\n\x17MODULE_TYPE_UNSPECIFIED\x10\x00\x12\x18\n\x14MODULE_TYPE_PROVIDER\x10\x01\x12\x14\n\x10MODULE_TYPE_TOOL\x10\x02\x12\x14\n\x10MODULE_TYPE_HOOK\x10\x03\x12\x16\n\x12MODULE_TYPE_MEMORY\x10\x04\x12\x19\n\x15MODULE_TYPE_GUARDRAIL\x10\x05\x12\x18\n\x14MODULE_TYPE_APPROVAL\x10\x06*\x82\x01\n\x0cHealthStatus\x12\x1d\n\x19HEALTH_STATUS_UNSPECIFIED\x10\x00\x12\x19\n\x15HEALTH_STATUS_SERVING\x10\x01\x12\x1d\n\x19HEALTH_STATUS_NOT_SERVING\x10\x02\x12\x19\n\x15HEALTH_STATUS_UNKNOWN\x10\x03*\xad\x01\n\x0f\x43onfigFieldType\x12!\n\x1d\x43ONFIG_FIELD_TYPE_UNSPECIFIED\x10\x00\x12\x1c\n\x18\x43ONFIG_FIELD_TYPE_STRING\x10\x01\x12\x1c\n\x18\x43ONFIG_FIELD_TYPE_NUMBER\x10\x02\x12\x1d\n\x19\x43ONFIG_FIELD_TYPE_BOOLEAN\x10\x03\x12\x1c\n\x18\x43ONFIG_FIELD_TYPE_SECRET\x10\x04*\xd8\x02\n\x11ProviderErrorType\x12#\n\x1fPROVIDER_ERROR_TYPE_UNSPECIFIED\x10\x00\x12\x1c\n\x18PROVIDER_ERROR_TYPE_AUTH\x10\x01\x12\"\n\x1ePROVIDER_ERROR_TYPE_RATE_LIMIT\x10\x02\x12&\n\"PROVIDER_ERROR_TYPE_CONTEXT_LENGTH\x10\x03\x12\'\n#PROVIDER_ERROR_TYPE_INVALID_REQUEST\x10\x04\x12&\n\"PROVIDER_ERROR_TYPE_CONTENT_FILTER\x10\x05\x12#\n\x1fPROVIDER_ERROR_TYPE_UNAVAILABLE\x10\x06\x12\x1f\n\x1bPROVIDER_ERROR_TYPE_TIMEOUT\x10\x07\x12\x1d\n\x19PROVIDER_ERROR_TYPE_OTHER\x10\x08*\x8c\x01\n\rToolErrorType\x12\x1f\n\x1bTOOL_ERROR_TYPE_UNSPECIFIED\x10\x00\x12\x1d\n\x19TOOL_ERROR_TYPE_EXECUTION\x10\x01\x12\x1e\n\x1aTOOL_ERROR_TYPE_VALIDATION\x10\x02\x12\x1b\n\x17TOOL_ERROR_TYPE_TIMEOUT\x10\x03*\x8c\x01\n\rHookErrorType\x12\x1f\n\x1bHOOK_ERROR_TYPE_UNSPECIFIED\x10\x00\x12\x1d\n\x19HOOK_ERROR_TYPE_EXECUTION\x10\x01\x12\x1e\n\x1aHOOK_ERROR_TYPE_VALIDATION\x10\x02\x12\x1b\n\x17HOOK_ERROR_TYPE_TIMEOUT\x10\x03*\x86\x01\n\x04Role\x12\x14\n\x10ROLE_UNSPECIFIED\x10\x00\x12\x0f\n\x0bROLE_SYSTEM\x10\x01\x12\r\n\tROLE_USER\x10\x02\x12\x12\n\x0eROLE_ASSISTANT\x10\x03\x12\r\n\tROLE_TOOL\x10\x04\x12\x11\n\rROLE_FUNCTION\x10\x05\x12\x12\n\x0eROLE_DEVELOPER\x10\x06*o\n\nVisibility\x12\x1a\n\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eVISIBILITY_ALL\x10\x01\x12\x17\n\x13VISIBILITY_LLM_ONLY\x10\x02\x12\x18\n\x14VISIBILITY_USER_ONLY\x10\x03*\xab\x01\n\nHookAction\x12\x1b\n\x17HOOK_ACTION_UNSPECIFIED\x10\x00\x12\x18\n\x14HOOK_ACTION_CONTINUE\x10\x01\x12\x16\n\x12HOOK_ACTION_MODIFY\x10\x02\x12\x14\n\x10HOOK_ACTION_DENY\x10\x03\x12\x1e\n\x1aHOOK_ACTION_INJECT_CONTEXT\x10\x04\x12\x18\n\x14HOOK_ACTION_ASK_USER\x10\x05*\xa8\x01\n\x14\x43ontextInjectionRole\x12&\n\"CONTEXT_INJECTION_ROLE_UNSPECIFIED\x10\x00\x12!\n\x1d\x43ONTEXT_INJECTION_ROLE_SYSTEM\x10\x01\x12\x1f\n\x1b\x43ONTEXT_INJECTION_ROLE_USER\x10\x02\x12$\n CONTEXT_INJECTION_ROLE_ASSISTANT\x10\x03*l\n\x0f\x41pprovalDefault\x12 \n\x1c\x41PPROVAL_DEFAULT_UNSPECIFIED\x10\x00\x12\x1c\n\x18\x41PPROVAL_DEFAULT_APPROVE\x10\x01\x12\x19\n\x15\x41PPROVAL_DEFAULT_DENY\x10\x02*\x91\x01\n\x10UserMessageLevel\x12\"\n\x1eUSER_MESSAGE_LEVEL_UNSPECIFIED\x10\x00\x12\x1b\n\x17USER_MESSAGE_LEVEL_INFO\x10\x01\x12\x1e\n\x1aUSER_MESSAGE_LEVEL_WARNING\x10\x02\x12\x1c\n\x18USER_MESSAGE_LEVEL_ERROR\x10\x03\x32\xa5\x01\n\x0bToolService\x12>\n\x07GetSpec\x12\x17.amplifier.module.Empty\x1a\x1a.amplifier.module.ToolSpec\x12V\n\x07\x45xecute\x12$.amplifier.module.ToolExecuteRequest\x1a%.amplifier.module.ToolExecuteResponse2\x9f\x03\n\x0fProviderService\x12\x42\n\x07GetInfo\x12\x17.amplifier.module.Empty\x1a\x1e.amplifier.module.ProviderInfo\x12K\n\nListModels\x12\x17.amplifier.module.Empty\x1a$.amplifier.module.ListModelsResponse\x12I\n\x08\x43omplete\x12\x1d.amplifier.module.ChatRequest\x1a\x1e.amplifier.module.ChatResponse\x12T\n\x11\x43ompleteStreaming\x12\x1d.amplifier.module.ChatRequest\x1a\x1e.amplifier.module.ChatResponse0\x01\x12Z\n\x0eParseToolCalls\x12\x1e.amplifier.module.ChatResponse\x1a(.amplifier.module.ParseToolCallsResponse2}\n\x13OrchestratorService\x12\x66\n\x07\x45xecute\x12,.amplifier.module.OrchestratorExecuteRequest\x1a-.amplifier.module.OrchestratorExecuteResponse2\xa3\x03\n\x0e\x43ontextService\x12J\n\nAddMessage\x12#.amplifier.module.AddMessageRequest\x1a\x17.amplifier.module.Empty\x12M\n\x0bGetMessages\x12\x17.amplifier.module.Empty\x1a%.amplifier.module.GetMessagesResponse\x12m\n\x15GetMessagesForRequest\x12-.amplifier.module.GetMessagesForRequestParams\x1a%.amplifier.module.GetMessagesResponse\x12L\n\x0bSetMessages\x12$.amplifier.module.SetMessagesRequest\x1a\x17.amplifier.module.Empty\x12\x39\n\x05\x43lear\x12\x17.amplifier.module.Empty\x1a\x17.amplifier.module.Empty2Z\n\x0bHookService\x12K\n\x06Handle\x12#.amplifier.module.HookHandleRequest\x1a\x1c.amplifier.module.HookResult2k\n\x0f\x41pprovalService\x12X\n\x0fRequestApproval\x12!.amplifier.module.ApprovalRequest\x1a\".amplifier.module.ApprovalResponse2\xcb\x07\n\rKernelService\x12\x65\n\x14\x43ompleteWithProvider\x12-.amplifier.module.CompleteWithProviderRequest\x1a\x1e.amplifier.module.ChatResponse\x12p\n\x1d\x43ompleteWithProviderStreaming\x12-.amplifier.module.CompleteWithProviderRequest\x1a\x1e.amplifier.module.ChatResponse0\x01\x12Q\n\x0b\x45xecuteTool\x12$.amplifier.module.ExecuteToolRequest\x1a\x1c.amplifier.module.ToolResult\x12\x46\n\x08\x45mitHook\x12!.amplifier.module.EmitHookRequest\x1a\x17.amplifier.module.Empty\x12o\n\x12\x45mitHookAndCollect\x12+.amplifier.module.EmitHookAndCollectRequest\x1a,.amplifier.module.EmitHookAndCollectResponse\x12Z\n\x0bGetMessages\x12$.amplifier.module.GetMessagesRequest\x1a%.amplifier.module.GetMessagesResponse\x12P\n\nAddMessage\x12).amplifier.module.KernelAddMessageRequest\x1a\x17.amplifier.module.Empty\x12i\n\x10GetMountedModule\x12).amplifier.module.GetMountedModuleRequest\x1a*.amplifier.module.GetMountedModuleResponse\x12Z\n\x12RegisterCapability\x12+.amplifier.module.RegisterCapabilityRequest\x1a\x17.amplifier.module.Empty\x12`\n\rGetCapability\x12&.amplifier.module.GetCapabilityRequest\x1a\'.amplifier.module.GetCapabilityResponse2\xaf\x02\n\x0fModuleLifecycle\x12H\n\x05Mount\x12\x1e.amplifier.module.MountRequest\x1a\x1f.amplifier.module.MountResponse\x12;\n\x07\x43leanup\x12\x17.amplifier.module.Empty\x1a\x17.amplifier.module.Empty\x12M\n\x0bHealthCheck\x12\x17.amplifier.module.Empty\x1a%.amplifier.module.HealthCheckResponse\x12\x46\n\rGetModuleInfo\x12\x17.amplifier.module.Empty\x1a\x1c.amplifier.module.ModuleInfob\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x61mplifier_module.proto\x12\x10\x61mplifier.module\"\x07\n\x05\x45mpty\"F\n\x08ToolSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x17\n\x0fparameters_json\x18\x03 \x01(\t\"9\n\x12ToolExecuteRequest\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x02 \x01(\t\"[\n\x13ToolExecuteResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06output\x18\x02 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x03 \x01(\t\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"\xd6\x01\n\nModuleInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x31\n\x0bmodule_type\x18\x04 \x01(\x0e\x32\x1c.amplifier.module.ModuleType\x12\x13\n\x0bmount_point\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x06 \x01(\t\x12\x1a\n\x12\x63onfig_schema_json\x18\x07 \x01(\t\x12\x14\n\x0c\x63\x61pabilities\x18\x08 \x03(\t\x12\x0e\n\x06\x61uthor\x18\t \x01(\t\"\x8c\x01\n\x0cMountRequest\x12:\n\x06\x63onfig\x18\x01 \x03(\x0b\x32*.amplifier.module.MountRequest.ConfigEntry\x12\x11\n\tmodule_id\x18\x02 \x01(\t\x1a-\n\x0b\x43onfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"_\n\rMountResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12.\n\x06status\x18\x03 \x01(\x0e\x32\x1e.amplifier.module.HealthStatus\"V\n\x13HealthCheckResponse\x12.\n\x06status\x18\x01 \x01(\x0e\x32\x1e.amplifier.module.HealthStatus\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xca\x02\n\x0b\x43onfigField\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\x12\x35\n\nfield_type\x18\x03 \x01(\x0e\x32!.amplifier.module.ConfigFieldType\x12\x0e\n\x06prompt\x18\x04 \x01(\t\x12\x0f\n\x07\x65nv_var\x18\x05 \x01(\t\x12\x0f\n\x07\x63hoices\x18\x06 \x03(\t\x12\x10\n\x08required\x18\x07 \x01(\x08\x12\x15\n\rdefault_value\x18\x08 \x01(\t\x12>\n\tshow_when\x18\t \x03(\x0b\x32+.amplifier.module.ConfigField.ShowWhenEntry\x12\x16\n\x0erequires_model\x18\n \x01(\x08\x1a/\n\rShowWhenEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xbc\x01\n\rProviderError\x12\x37\n\nerror_type\x18\x01 \x01(\x0e\x32#.amplifier.module.ProviderErrorType\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x15\n\rprovider_name\x18\x03 \x01(\t\x12\r\n\x05model\x18\x04 \x01(\t\x12\x13\n\x0bstatus_code\x18\x05 \x01(\x05\x12\x11\n\tretryable\x18\x06 \x01(\x08\x12\x13\n\x0bretry_after\x18\x07 \x01(\x01\"\x97\x01\n\tToolError\x12\x33\n\nerror_type\x18\x01 \x01(\x0e\x32\x1f.amplifier.module.ToolErrorType\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\ttool_name\x18\x03 \x01(\t\x12\x0e\n\x06stdout\x18\x04 \x01(\t\x12\x0e\n\x06stderr\x18\x05 \x01(\t\x12\x11\n\texit_code\x18\x06 \x01(\x05\"d\n\tHookError\x12\x33\n\nerror_type\x18\x01 \x01(\x0e\x32\x1f.amplifier.module.HookErrorType\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\thook_name\x18\x03 \x01(\t\"\xef\x01\n\x0e\x41mplifierError\x12\x39\n\x0eprovider_error\x18\x01 \x01(\x0b\x32\x1f.amplifier.module.ProviderErrorH\x00\x12\x31\n\ntool_error\x18\x02 \x01(\x0b\x32\x1b.amplifier.module.ToolErrorH\x00\x12\x31\n\nhook_error\x18\x03 \x01(\x0b\x32\x1b.amplifier.module.HookErrorH\x00\x12\x17\n\rgeneric_error\x18\x04 \x01(\tH\x00\x12\x1a\n\x10validation_error\x18\x05 \x01(\tH\x00\x42\x07\n\x05\x65rror\"\x19\n\tTextBlock\x12\x0c\n\x04text\x18\x01 \x01(\t\"E\n\rThinkingBlock\x12\x10\n\x08thinking\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\t\"%\n\x15RedactedThinkingBlock\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\"=\n\rToolCallBlock\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\ninput_json\x18\x03 \x01(\t\"<\n\x0fToolResultBlock\x12\x14\n\x0ctool_call_id\x18\x01 \x01(\t\x12\x13\n\x0boutput_json\x18\x02 \x01(\t\"C\n\nImageBlock\x12\x12\n\nmedia_type\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x13\n\x0bsource_json\x18\x03 \x01(\t\"2\n\x0eReasoningBlock\x12\x0f\n\x07\x63ontent\x18\x01 \x03(\t\x12\x0f\n\x07summary\x18\x02 \x03(\t\"\xf1\x03\n\x0c\x43ontentBlock\x12\x31\n\ntext_block\x18\x01 \x01(\x0b\x32\x1b.amplifier.module.TextBlockH\x00\x12\x39\n\x0ethinking_block\x18\x02 \x01(\x0b\x32\x1f.amplifier.module.ThinkingBlockH\x00\x12J\n\x17redacted_thinking_block\x18\x03 \x01(\x0b\x32\'.amplifier.module.RedactedThinkingBlockH\x00\x12:\n\x0ftool_call_block\x18\x04 \x01(\x0b\x32\x1f.amplifier.module.ToolCallBlockH\x00\x12>\n\x11tool_result_block\x18\x05 \x01(\x0b\x32!.amplifier.module.ToolResultBlockH\x00\x12\x33\n\x0bimage_block\x18\x06 \x01(\x0b\x32\x1c.amplifier.module.ImageBlockH\x00\x12;\n\x0freasoning_block\x18\x07 \x01(\x0b\x32 .amplifier.module.ReasoningBlockH\x00\x12\x30\n\nvisibility\x18\x08 \x01(\x0e\x32\x1c.amplifier.module.VisibilityB\x07\n\x05\x62lock\"B\n\x10\x43ontentBlockList\x12.\n\x06\x62locks\x18\x01 \x03(\x0b\x32\x1e.amplifier.module.ContentBlock\"\xca\x01\n\x07Message\x12$\n\x04role\x18\x01 \x01(\x0e\x32\x16.amplifier.module.Role\x12\x16\n\x0ctext_content\x18\x02 \x01(\tH\x00\x12;\n\rblock_content\x18\x03 \x01(\x0b\x32\".amplifier.module.ContentBlockListH\x00\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x14\n\x0ctool_call_id\x18\x05 \x01(\t\x12\x15\n\rmetadata_json\x18\x06 \x01(\tB\t\n\x07\x63ontent\"C\n\x0fToolCallMessage\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x16\n\x0e\x61rguments_json\x18\x03 \x01(\t\"K\n\rToolSpecProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x17\n\x0fparameters_json\x18\x03 \x01(\t\"7\n\x10JsonSchemaFormat\x12\x13\n\x0bschema_json\x18\x01 \x01(\t\x12\x0e\n\x06strict\x18\x02 \x01(\x08\"u\n\x0eResponseFormat\x12\x0e\n\x04text\x18\x01 \x01(\x08H\x00\x12\x0e\n\x04json\x18\x02 \x01(\x08H\x00\x12\x39\n\x0bjson_schema\x18\x03 \x01(\x0b\x32\".amplifier.module.JsonSchemaFormatH\x00\x42\x08\n\x06\x66ormat\"\xa3\x01\n\x05Usage\x12\x15\n\rprompt_tokens\x18\x01 \x01(\x05\x12\x19\n\x11\x63ompletion_tokens\x18\x02 \x01(\x05\x12\x14\n\x0ctotal_tokens\x18\x03 \x01(\x05\x12\x18\n\x10reasoning_tokens\x18\x04 \x01(\x05\x12\x19\n\x11\x63\x61\x63he_read_tokens\x18\x05 \x01(\x05\x12\x1d\n\x15\x63\x61\x63he_creation_tokens\x18\x06 \x01(\x05\"@\n\x0b\x44\x65gradation\x12\x11\n\trequested\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tual\x18\x02 \x01(\t\x12\x0e\n\x06reason\x18\x03 \x01(\t\"\x81\x03\n\x0b\x43hatRequest\x12+\n\x08messages\x18\x01 \x03(\x0b\x32\x19.amplifier.module.Message\x12.\n\x05tools\x18\x02 \x03(\x0b\x32\x1f.amplifier.module.ToolSpecProto\x12\x39\n\x0fresponse_format\x18\x03 \x01(\x0b\x32 .amplifier.module.ResponseFormat\x12\x13\n\x0btemperature\x18\x04 \x01(\x01\x12\r\n\x05top_p\x18\x05 \x01(\x01\x12\x19\n\x11max_output_tokens\x18\x06 \x01(\x05\x12\x17\n\x0f\x63onversation_id\x18\x07 \x01(\t\x12\x0e\n\x06stream\x18\x08 \x01(\x08\x12\x15\n\rmetadata_json\x18\t \x01(\t\x12\r\n\x05model\x18\n \x01(\t\x12\x13\n\x0btool_choice\x18\x0b \x01(\t\x12\x0c\n\x04stop\x18\x0c \x03(\t\x12\x18\n\x10reasoning_effort\x18\r \x01(\t\x12\x0f\n\x07timeout\x18\x0e \x01(\x01\"\xe0\x01\n\x0c\x43hatResponse\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x35\n\ntool_calls\x18\x02 \x03(\x0b\x32!.amplifier.module.ToolCallMessage\x12&\n\x05usage\x18\x03 \x01(\x0b\x32\x17.amplifier.module.Usage\x12\x32\n\x0b\x64\x65gradation\x18\x04 \x01(\x0b\x32\x1d.amplifier.module.Degradation\x12\x15\n\rfinish_reason\x18\x05 \x01(\t\x12\x15\n\rmetadata_json\x18\x06 \x01(\t\"F\n\nToolResult\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0boutput_json\x18\x02 \x01(\t\x12\x12\n\nerror_json\x18\x03 \x01(\t\"\x8d\x04\n\nHookResult\x12,\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1c.amplifier.module.HookAction\x12\x11\n\tdata_json\x18\x02 \x01(\t\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x19\n\x11\x63ontext_injection\x18\x04 \x01(\t\x12\x46\n\x16\x63ontext_injection_role\x18\x05 \x01(\x0e\x32&.amplifier.module.ContextInjectionRole\x12\x11\n\tephemeral\x18\x06 \x01(\x08\x12\x17\n\x0f\x61pproval_prompt\x18\x07 \x01(\t\x12\x18\n\x10\x61pproval_options\x18\x08 \x03(\t\x12\x18\n\x10\x61pproval_timeout\x18\t \x01(\x01\x12;\n\x10\x61pproval_default\x18\n \x01(\x0e\x32!.amplifier.module.ApprovalDefault\x12\x17\n\x0fsuppress_output\x18\x0b \x01(\x08\x12\x14\n\x0cuser_message\x18\x0c \x01(\t\x12>\n\x12user_message_level\x18\r \x01(\x0e\x32\".amplifier.module.UserMessageLevel\x12\x1b\n\x13user_message_source\x18\x0e \x01(\t\x12\"\n\x1a\x61ppend_to_last_tool_result\x18\x0f \x01(\x08\"\x8d\x01\n\tModelInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\x12\x16\n\x0e\x63ontext_window\x18\x03 \x01(\x05\x12\x19\n\x11max_output_tokens\x18\x04 \x01(\x05\x12\x14\n\x0c\x63\x61pabilities\x18\x05 \x03(\t\x12\x15\n\rdefaults_json\x18\x06 \x01(\t\"\xb0\x01\n\x0cProviderInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\x12\x1b\n\x13\x63redential_env_vars\x18\x03 \x03(\t\x12\x14\n\x0c\x63\x61pabilities\x18\x04 \x03(\t\x12\x15\n\rdefaults_json\x18\x05 \x01(\t\x12\x34\n\rconfig_fields\x18\x06 \x03(\x0b\x32\x1d.amplifier.module.ConfigField\"o\n\x0f\x41pprovalRequest\x12\x11\n\ttool_name\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x14\n\x0c\x64\x65tails_json\x18\x03 \x01(\t\x12\x12\n\nrisk_level\x18\x04 \x01(\t\x12\x0f\n\x07timeout\x18\x05 \x01(\x01\"F\n\x10\x41pprovalResponse\x12\x10\n\x08\x61pproved\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x10\n\x08remember\x18\x03 \x01(\x08\"A\n\x12ListModelsResponse\x12+\n\x06models\x18\x01 \x03(\x0b\x32\x1b.amplifier.module.ModelInfo\"O\n\x16ParseToolCallsResponse\x12\x35\n\ntool_calls\x18\x01 \x03(\x0b\x32!.amplifier.module.ToolCallMessage\"@\n\x1aOrchestratorExecuteRequest\x12\x0e\n\x06prompt\x18\x01 \x01(\t\x12\x12\n\nsession_id\x18\x02 \x01(\t\">\n\x1bOrchestratorExecuteResponse\x12\x10\n\x08response\x18\x01 \x01(\t\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"?\n\x11\x41\x64\x64MessageRequest\x12*\n\x07message\x18\x01 \x01(\x0b\x32\x19.amplifier.module.Message\"B\n\x13GetMessagesResponse\x12+\n\x08messages\x18\x01 \x03(\x0b\x32\x19.amplifier.module.Message\"J\n\x1bGetMessagesForRequestParams\x12\x14\n\x0ctoken_budget\x18\x01 \x01(\x05\x12\x15\n\rprovider_name\x18\x02 \x01(\t\"A\n\x12SetMessagesRequest\x12+\n\x08messages\x18\x01 \x03(\x0b\x32\x19.amplifier.module.Message\"5\n\x11HookHandleRequest\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x11\n\tdata_json\x18\x02 \x01(\t\"d\n\x1b\x43ompleteWithProviderRequest\x12\x15\n\rprovider_name\x18\x01 \x01(\t\x12.\n\x07request\x18\x02 \x01(\x0b\x32\x1d.amplifier.module.ChatRequest\";\n\x12\x45xecuteToolRequest\x12\x11\n\ttool_name\x18\x01 \x01(\t\x12\x12\n\ninput_json\x18\x02 \x01(\t\"3\n\x0f\x45mitHookRequest\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x11\n\tdata_json\x18\x02 \x01(\t\"V\n\x19\x45mitHookAndCollectRequest\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x11\n\tdata_json\x18\x02 \x01(\t\x12\x17\n\x0ftimeout_seconds\x18\x03 \x01(\x01\"4\n\x1a\x45mitHookAndCollectResponse\x12\x16\n\x0eresponses_json\x18\x01 \x03(\t\"(\n\x12GetMessagesRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\"Y\n\x17KernelAddMessageRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12*\n\x07message\x18\x02 \x01(\x0b\x32\x19.amplifier.module.Message\"a\n\x17GetMountedModuleRequest\x12\x13\n\x0bmodule_name\x18\x01 \x01(\t\x12\x31\n\x0bmodule_type\x18\x02 \x01(\x0e\x32\x1c.amplifier.module.ModuleType\"U\n\x18GetMountedModuleResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12*\n\x04info\x18\x02 \x01(\x0b\x32\x1c.amplifier.module.ModuleInfo\"=\n\x19RegisterCapabilityRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nvalue_json\x18\x02 \x01(\t\"$\n\x14GetCapabilityRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\":\n\x15GetCapabilityResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12\x12\n\nvalue_json\x18\x02 \x01(\t*\xbc\x01\n\nModuleType\x12\x1b\n\x17MODULE_TYPE_UNSPECIFIED\x10\x00\x12\x18\n\x14MODULE_TYPE_PROVIDER\x10\x01\x12\x14\n\x10MODULE_TYPE_TOOL\x10\x02\x12\x14\n\x10MODULE_TYPE_HOOK\x10\x03\x12\x16\n\x12MODULE_TYPE_MEMORY\x10\x04\x12\x19\n\x15MODULE_TYPE_GUARDRAIL\x10\x05\x12\x18\n\x14MODULE_TYPE_APPROVAL\x10\x06*\x82\x01\n\x0cHealthStatus\x12\x1d\n\x19HEALTH_STATUS_UNSPECIFIED\x10\x00\x12\x19\n\x15HEALTH_STATUS_SERVING\x10\x01\x12\x1d\n\x19HEALTH_STATUS_NOT_SERVING\x10\x02\x12\x19\n\x15HEALTH_STATUS_UNKNOWN\x10\x03*\xad\x01\n\x0f\x43onfigFieldType\x12!\n\x1d\x43ONFIG_FIELD_TYPE_UNSPECIFIED\x10\x00\x12\x1c\n\x18\x43ONFIG_FIELD_TYPE_STRING\x10\x01\x12\x1c\n\x18\x43ONFIG_FIELD_TYPE_NUMBER\x10\x02\x12\x1d\n\x19\x43ONFIG_FIELD_TYPE_BOOLEAN\x10\x03\x12\x1c\n\x18\x43ONFIG_FIELD_TYPE_SECRET\x10\x04*\xd8\x02\n\x11ProviderErrorType\x12#\n\x1fPROVIDER_ERROR_TYPE_UNSPECIFIED\x10\x00\x12\x1c\n\x18PROVIDER_ERROR_TYPE_AUTH\x10\x01\x12\"\n\x1ePROVIDER_ERROR_TYPE_RATE_LIMIT\x10\x02\x12&\n\"PROVIDER_ERROR_TYPE_CONTEXT_LENGTH\x10\x03\x12\'\n#PROVIDER_ERROR_TYPE_INVALID_REQUEST\x10\x04\x12&\n\"PROVIDER_ERROR_TYPE_CONTENT_FILTER\x10\x05\x12#\n\x1fPROVIDER_ERROR_TYPE_UNAVAILABLE\x10\x06\x12\x1f\n\x1bPROVIDER_ERROR_TYPE_TIMEOUT\x10\x07\x12\x1d\n\x19PROVIDER_ERROR_TYPE_OTHER\x10\x08*\x8c\x01\n\rToolErrorType\x12\x1f\n\x1bTOOL_ERROR_TYPE_UNSPECIFIED\x10\x00\x12\x1d\n\x19TOOL_ERROR_TYPE_EXECUTION\x10\x01\x12\x1e\n\x1aTOOL_ERROR_TYPE_VALIDATION\x10\x02\x12\x1b\n\x17TOOL_ERROR_TYPE_TIMEOUT\x10\x03*\x8c\x01\n\rHookErrorType\x12\x1f\n\x1bHOOK_ERROR_TYPE_UNSPECIFIED\x10\x00\x12\x1d\n\x19HOOK_ERROR_TYPE_EXECUTION\x10\x01\x12\x1e\n\x1aHOOK_ERROR_TYPE_VALIDATION\x10\x02\x12\x1b\n\x17HOOK_ERROR_TYPE_TIMEOUT\x10\x03*\x86\x01\n\x04Role\x12\x14\n\x10ROLE_UNSPECIFIED\x10\x00\x12\x0f\n\x0bROLE_SYSTEM\x10\x01\x12\r\n\tROLE_USER\x10\x02\x12\x12\n\x0eROLE_ASSISTANT\x10\x03\x12\r\n\tROLE_TOOL\x10\x04\x12\x11\n\rROLE_FUNCTION\x10\x05\x12\x12\n\x0eROLE_DEVELOPER\x10\x06*o\n\nVisibility\x12\x1a\n\x16VISIBILITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eVISIBILITY_ALL\x10\x01\x12\x17\n\x13VISIBILITY_LLM_ONLY\x10\x02\x12\x18\n\x14VISIBILITY_USER_ONLY\x10\x03*\xab\x01\n\nHookAction\x12\x1b\n\x17HOOK_ACTION_UNSPECIFIED\x10\x00\x12\x18\n\x14HOOK_ACTION_CONTINUE\x10\x01\x12\x16\n\x12HOOK_ACTION_MODIFY\x10\x02\x12\x14\n\x10HOOK_ACTION_DENY\x10\x03\x12\x1e\n\x1aHOOK_ACTION_INJECT_CONTEXT\x10\x04\x12\x18\n\x14HOOK_ACTION_ASK_USER\x10\x05*\xa8\x01\n\x14\x43ontextInjectionRole\x12&\n\"CONTEXT_INJECTION_ROLE_UNSPECIFIED\x10\x00\x12!\n\x1d\x43ONTEXT_INJECTION_ROLE_SYSTEM\x10\x01\x12\x1f\n\x1b\x43ONTEXT_INJECTION_ROLE_USER\x10\x02\x12$\n CONTEXT_INJECTION_ROLE_ASSISTANT\x10\x03*l\n\x0f\x41pprovalDefault\x12 \n\x1c\x41PPROVAL_DEFAULT_UNSPECIFIED\x10\x00\x12\x1c\n\x18\x41PPROVAL_DEFAULT_APPROVE\x10\x01\x12\x19\n\x15\x41PPROVAL_DEFAULT_DENY\x10\x02*\x91\x01\n\x10UserMessageLevel\x12\"\n\x1eUSER_MESSAGE_LEVEL_UNSPECIFIED\x10\x00\x12\x1b\n\x17USER_MESSAGE_LEVEL_INFO\x10\x01\x12\x1e\n\x1aUSER_MESSAGE_LEVEL_WARNING\x10\x02\x12\x1c\n\x18USER_MESSAGE_LEVEL_ERROR\x10\x03\x32\xa5\x01\n\x0bToolService\x12>\n\x07GetSpec\x12\x17.amplifier.module.Empty\x1a\x1a.amplifier.module.ToolSpec\x12V\n\x07\x45xecute\x12$.amplifier.module.ToolExecuteRequest\x1a%.amplifier.module.ToolExecuteResponse2\x9f\x03\n\x0fProviderService\x12\x42\n\x07GetInfo\x12\x17.amplifier.module.Empty\x1a\x1e.amplifier.module.ProviderInfo\x12K\n\nListModels\x12\x17.amplifier.module.Empty\x1a$.amplifier.module.ListModelsResponse\x12I\n\x08\x43omplete\x12\x1d.amplifier.module.ChatRequest\x1a\x1e.amplifier.module.ChatResponse\x12T\n\x11\x43ompleteStreaming\x12\x1d.amplifier.module.ChatRequest\x1a\x1e.amplifier.module.ChatResponse0\x01\x12Z\n\x0eParseToolCalls\x12\x1e.amplifier.module.ChatResponse\x1a(.amplifier.module.ParseToolCallsResponse2}\n\x13OrchestratorService\x12\x66\n\x07\x45xecute\x12,.amplifier.module.OrchestratorExecuteRequest\x1a-.amplifier.module.OrchestratorExecuteResponse2\xa3\x03\n\x0e\x43ontextService\x12J\n\nAddMessage\x12#.amplifier.module.AddMessageRequest\x1a\x17.amplifier.module.Empty\x12M\n\x0bGetMessages\x12\x17.amplifier.module.Empty\x1a%.amplifier.module.GetMessagesResponse\x12m\n\x15GetMessagesForRequest\x12-.amplifier.module.GetMessagesForRequestParams\x1a%.amplifier.module.GetMessagesResponse\x12L\n\x0bSetMessages\x12$.amplifier.module.SetMessagesRequest\x1a\x17.amplifier.module.Empty\x12\x39\n\x05\x43lear\x12\x17.amplifier.module.Empty\x1a\x17.amplifier.module.Empty2Z\n\x0bHookService\x12K\n\x06Handle\x12#.amplifier.module.HookHandleRequest\x1a\x1c.amplifier.module.HookResult2k\n\x0f\x41pprovalService\x12X\n\x0fRequestApproval\x12!.amplifier.module.ApprovalRequest\x1a\".amplifier.module.ApprovalResponse2\xd0\x07\n\rKernelService\x12\x65\n\x14\x43ompleteWithProvider\x12-.amplifier.module.CompleteWithProviderRequest\x1a\x1e.amplifier.module.ChatResponse\x12p\n\x1d\x43ompleteWithProviderStreaming\x12-.amplifier.module.CompleteWithProviderRequest\x1a\x1e.amplifier.module.ChatResponse0\x01\x12Q\n\x0b\x45xecuteTool\x12$.amplifier.module.ExecuteToolRequest\x1a\x1c.amplifier.module.ToolResult\x12K\n\x08\x45mitHook\x12!.amplifier.module.EmitHookRequest\x1a\x1c.amplifier.module.HookResult\x12o\n\x12\x45mitHookAndCollect\x12+.amplifier.module.EmitHookAndCollectRequest\x1a,.amplifier.module.EmitHookAndCollectResponse\x12Z\n\x0bGetMessages\x12$.amplifier.module.GetMessagesRequest\x1a%.amplifier.module.GetMessagesResponse\x12P\n\nAddMessage\x12).amplifier.module.KernelAddMessageRequest\x1a\x17.amplifier.module.Empty\x12i\n\x10GetMountedModule\x12).amplifier.module.GetMountedModuleRequest\x1a*.amplifier.module.GetMountedModuleResponse\x12Z\n\x12RegisterCapability\x12+.amplifier.module.RegisterCapabilityRequest\x1a\x17.amplifier.module.Empty\x12`\n\rGetCapability\x12&.amplifier.module.GetCapabilityRequest\x1a\'.amplifier.module.GetCapabilityResponse2\xaf\x02\n\x0fModuleLifecycle\x12H\n\x05Mount\x12\x1e.amplifier.module.MountRequest\x1a\x1f.amplifier.module.MountResponse\x12;\n\x07\x43leanup\x12\x17.amplifier.module.Empty\x1a\x17.amplifier.module.Empty\x12M\n\x0bHealthCheck\x12\x17.amplifier.module.Empty\x1a%.amplifier.module.HealthCheckResponse\x12\x46\n\rGetModuleInfo\x12\x17.amplifier.module.Empty\x1a\x1c.amplifier.module.ModuleInfob\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -35,30 +35,30 @@ _globals['_MOUNTREQUEST_CONFIGENTRY']._serialized_options = b'8\001' _globals['_CONFIGFIELD_SHOWWHENENTRY']._loaded_options = None _globals['_CONFIGFIELD_SHOWWHENENTRY']._serialized_options = b'8\001' - _globals['_MODULETYPE']._serialized_start=6772 - _globals['_MODULETYPE']._serialized_end=6960 - _globals['_HEALTHSTATUS']._serialized_start=6963 - _globals['_HEALTHSTATUS']._serialized_end=7093 - _globals['_CONFIGFIELDTYPE']._serialized_start=7096 - _globals['_CONFIGFIELDTYPE']._serialized_end=7269 - _globals['_PROVIDERERRORTYPE']._serialized_start=7272 - _globals['_PROVIDERERRORTYPE']._serialized_end=7616 - _globals['_TOOLERRORTYPE']._serialized_start=7619 - _globals['_TOOLERRORTYPE']._serialized_end=7759 - _globals['_HOOKERRORTYPE']._serialized_start=7762 - _globals['_HOOKERRORTYPE']._serialized_end=7902 - _globals['_ROLE']._serialized_start=7905 - _globals['_ROLE']._serialized_end=8039 - _globals['_VISIBILITY']._serialized_start=8041 - _globals['_VISIBILITY']._serialized_end=8152 - _globals['_HOOKACTION']._serialized_start=8155 - _globals['_HOOKACTION']._serialized_end=8326 - _globals['_CONTEXTINJECTIONROLE']._serialized_start=8329 - _globals['_CONTEXTINJECTIONROLE']._serialized_end=8497 - _globals['_APPROVALDEFAULT']._serialized_start=8499 - _globals['_APPROVALDEFAULT']._serialized_end=8607 - _globals['_USERMESSAGELEVEL']._serialized_start=8610 - _globals['_USERMESSAGELEVEL']._serialized_end=8755 + _globals['_MODULETYPE']._serialized_start=6725 + _globals['_MODULETYPE']._serialized_end=6913 + _globals['_HEALTHSTATUS']._serialized_start=6916 + _globals['_HEALTHSTATUS']._serialized_end=7046 + _globals['_CONFIGFIELDTYPE']._serialized_start=7049 + _globals['_CONFIGFIELDTYPE']._serialized_end=7222 + _globals['_PROVIDERERRORTYPE']._serialized_start=7225 + _globals['_PROVIDERERRORTYPE']._serialized_end=7569 + _globals['_TOOLERRORTYPE']._serialized_start=7572 + _globals['_TOOLERRORTYPE']._serialized_end=7712 + _globals['_HOOKERRORTYPE']._serialized_start=7715 + _globals['_HOOKERRORTYPE']._serialized_end=7855 + _globals['_ROLE']._serialized_start=7858 + _globals['_ROLE']._serialized_end=7992 + _globals['_VISIBILITY']._serialized_start=7994 + _globals['_VISIBILITY']._serialized_end=8105 + _globals['_HOOKACTION']._serialized_start=8108 + _globals['_HOOKACTION']._serialized_end=8279 + _globals['_CONTEXTINJECTIONROLE']._serialized_start=8282 + _globals['_CONTEXTINJECTIONROLE']._serialized_end=8450 + _globals['_APPROVALDEFAULT']._serialized_start=8452 + _globals['_APPROVALDEFAULT']._serialized_end=8560 + _globals['_USERMESSAGELEVEL']._serialized_start=8563 + _globals['_USERMESSAGELEVEL']._serialized_end=8708 _globals['_EMPTY']._serialized_start=44 _globals['_EMPTY']._serialized_end=51 _globals['_TOOLSPEC']._serialized_start=53 @@ -78,121 +78,121 @@ _globals['_HEALTHCHECKRESPONSE']._serialized_start=734 _globals['_HEALTHCHECKRESPONSE']._serialized_end=820 _globals['_CONFIGFIELD']._serialized_start=823 - _globals['_CONFIGFIELD']._serialized_end=1168 - _globals['_CONFIGFIELD_SHOWWHENENTRY']._serialized_start=1121 - _globals['_CONFIGFIELD_SHOWWHENENTRY']._serialized_end=1168 - _globals['_PROVIDERERROR']._serialized_start=1171 - _globals['_PROVIDERERROR']._serialized_end=1359 - _globals['_TOOLERROR']._serialized_start=1362 - _globals['_TOOLERROR']._serialized_end=1513 - _globals['_HOOKERROR']._serialized_start=1515 - _globals['_HOOKERROR']._serialized_end=1615 - _globals['_AMPLIFIERERROR']._serialized_start=1618 - _globals['_AMPLIFIERERROR']._serialized_end=1857 - _globals['_TEXTBLOCK']._serialized_start=1859 - _globals['_TEXTBLOCK']._serialized_end=1884 - _globals['_THINKINGBLOCK']._serialized_start=1886 - _globals['_THINKINGBLOCK']._serialized_end=1955 - _globals['_REDACTEDTHINKINGBLOCK']._serialized_start=1957 - _globals['_REDACTEDTHINKINGBLOCK']._serialized_end=1994 - _globals['_TOOLCALLBLOCK']._serialized_start=1996 - _globals['_TOOLCALLBLOCK']._serialized_end=2057 - _globals['_TOOLRESULTBLOCK']._serialized_start=2059 - _globals['_TOOLRESULTBLOCK']._serialized_end=2119 - _globals['_IMAGEBLOCK']._serialized_start=2121 - _globals['_IMAGEBLOCK']._serialized_end=2188 - _globals['_REASONINGBLOCK']._serialized_start=2190 - _globals['_REASONINGBLOCK']._serialized_end=2240 - _globals['_CONTENTBLOCK']._serialized_start=2243 - _globals['_CONTENTBLOCK']._serialized_end=2740 - _globals['_CONTENTBLOCKLIST']._serialized_start=2742 - _globals['_CONTENTBLOCKLIST']._serialized_end=2808 - _globals['_MESSAGE']._serialized_start=2811 - _globals['_MESSAGE']._serialized_end=3013 - _globals['_TOOLCALLMESSAGE']._serialized_start=3015 - _globals['_TOOLCALLMESSAGE']._serialized_end=3082 - _globals['_TOOLSPECPROTO']._serialized_start=3084 - _globals['_TOOLSPECPROTO']._serialized_end=3159 - _globals['_JSONSCHEMAFORMAT']._serialized_start=3161 - _globals['_JSONSCHEMAFORMAT']._serialized_end=3216 - _globals['_RESPONSEFORMAT']._serialized_start=3218 - _globals['_RESPONSEFORMAT']._serialized_end=3335 - _globals['_USAGE']._serialized_start=3338 - _globals['_USAGE']._serialized_end=3501 - _globals['_DEGRADATION']._serialized_start=3503 - _globals['_DEGRADATION']._serialized_end=3567 - _globals['_CHATREQUEST']._serialized_start=3570 - _globals['_CHATREQUEST']._serialized_end=3980 - _globals['_CHATRESPONSE']._serialized_start=3983 - _globals['_CHATRESPONSE']._serialized_end=4207 - _globals['_TOOLRESULT']._serialized_start=4209 - _globals['_TOOLRESULT']._serialized_end=4279 - _globals['_HOOKRESULT']._serialized_start=4282 - _globals['_HOOKRESULT']._serialized_end=4807 - _globals['_MODELINFO']._serialized_start=4810 - _globals['_MODELINFO']._serialized_end=4951 - _globals['_PROVIDERINFO']._serialized_start=4954 - _globals['_PROVIDERINFO']._serialized_end=5137 - _globals['_APPROVALREQUEST']._serialized_start=5139 - _globals['_APPROVALREQUEST']._serialized_end=5250 - _globals['_APPROVALRESPONSE']._serialized_start=5252 - _globals['_APPROVALRESPONSE']._serialized_end=5322 - _globals['_LISTMODELSRESPONSE']._serialized_start=5324 - _globals['_LISTMODELSRESPONSE']._serialized_end=5389 - _globals['_PARSETOOLCALLSRESPONSE']._serialized_start=5391 - _globals['_PARSETOOLCALLSRESPONSE']._serialized_end=5470 - _globals['_ORCHESTRATOREXECUTEREQUEST']._serialized_start=5472 - _globals['_ORCHESTRATOREXECUTEREQUEST']._serialized_end=5536 - _globals['_ORCHESTRATOREXECUTERESPONSE']._serialized_start=5538 - _globals['_ORCHESTRATOREXECUTERESPONSE']._serialized_end=5600 - _globals['_ADDMESSAGEREQUEST']._serialized_start=5602 - _globals['_ADDMESSAGEREQUEST']._serialized_end=5665 - _globals['_GETMESSAGESRESPONSE']._serialized_start=5667 - _globals['_GETMESSAGESRESPONSE']._serialized_end=5733 - _globals['_GETMESSAGESFORREQUESTPARAMS']._serialized_start=5735 - _globals['_GETMESSAGESFORREQUESTPARAMS']._serialized_end=5809 - _globals['_SETMESSAGESREQUEST']._serialized_start=5811 - _globals['_SETMESSAGESREQUEST']._serialized_end=5876 - _globals['_HOOKHANDLEREQUEST']._serialized_start=5878 - _globals['_HOOKHANDLEREQUEST']._serialized_end=5931 - _globals['_COMPLETEWITHPROVIDERREQUEST']._serialized_start=5933 - _globals['_COMPLETEWITHPROVIDERREQUEST']._serialized_end=6033 - _globals['_EXECUTETOOLREQUEST']._serialized_start=6035 - _globals['_EXECUTETOOLREQUEST']._serialized_end=6094 - _globals['_EMITHOOKREQUEST']._serialized_start=6096 - _globals['_EMITHOOKREQUEST']._serialized_end=6147 - _globals['_EMITHOOKANDCOLLECTREQUEST']._serialized_start=6149 - _globals['_EMITHOOKANDCOLLECTREQUEST']._serialized_end=6235 - _globals['_EMITHOOKANDCOLLECTRESPONSE']._serialized_start=6237 - _globals['_EMITHOOKANDCOLLECTRESPONSE']._serialized_end=6289 - _globals['_GETMESSAGESREQUEST']._serialized_start=6291 - _globals['_GETMESSAGESREQUEST']._serialized_end=6331 - _globals['_KERNELADDMESSAGEREQUEST']._serialized_start=6333 - _globals['_KERNELADDMESSAGEREQUEST']._serialized_end=6422 - _globals['_GETMOUNTEDMODULEREQUEST']._serialized_start=6424 - _globals['_GETMOUNTEDMODULEREQUEST']._serialized_end=6521 - _globals['_GETMOUNTEDMODULERESPONSE']._serialized_start=6523 - _globals['_GETMOUNTEDMODULERESPONSE']._serialized_end=6608 - _globals['_REGISTERCAPABILITYREQUEST']._serialized_start=6610 - _globals['_REGISTERCAPABILITYREQUEST']._serialized_end=6671 - _globals['_GETCAPABILITYREQUEST']._serialized_start=6673 - _globals['_GETCAPABILITYREQUEST']._serialized_end=6709 - _globals['_GETCAPABILITYRESPONSE']._serialized_start=6711 - _globals['_GETCAPABILITYRESPONSE']._serialized_end=6769 - _globals['_TOOLSERVICE']._serialized_start=8758 - _globals['_TOOLSERVICE']._serialized_end=8923 - _globals['_PROVIDERSERVICE']._serialized_start=8926 - _globals['_PROVIDERSERVICE']._serialized_end=9341 - _globals['_ORCHESTRATORSERVICE']._serialized_start=9343 - _globals['_ORCHESTRATORSERVICE']._serialized_end=9468 - _globals['_CONTEXTSERVICE']._serialized_start=9471 - _globals['_CONTEXTSERVICE']._serialized_end=9890 - _globals['_HOOKSERVICE']._serialized_start=9892 - _globals['_HOOKSERVICE']._serialized_end=9982 - _globals['_APPROVALSERVICE']._serialized_start=9984 - _globals['_APPROVALSERVICE']._serialized_end=10091 - _globals['_KERNELSERVICE']._serialized_start=10094 - _globals['_KERNELSERVICE']._serialized_end=11065 - _globals['_MODULELIFECYCLE']._serialized_start=11068 - _globals['_MODULELIFECYCLE']._serialized_end=11371 + _globals['_CONFIGFIELD']._serialized_end=1153 + _globals['_CONFIGFIELD_SHOWWHENENTRY']._serialized_start=1106 + _globals['_CONFIGFIELD_SHOWWHENENTRY']._serialized_end=1153 + _globals['_PROVIDERERROR']._serialized_start=1156 + _globals['_PROVIDERERROR']._serialized_end=1344 + _globals['_TOOLERROR']._serialized_start=1347 + _globals['_TOOLERROR']._serialized_end=1498 + _globals['_HOOKERROR']._serialized_start=1500 + _globals['_HOOKERROR']._serialized_end=1600 + _globals['_AMPLIFIERERROR']._serialized_start=1603 + _globals['_AMPLIFIERERROR']._serialized_end=1842 + _globals['_TEXTBLOCK']._serialized_start=1844 + _globals['_TEXTBLOCK']._serialized_end=1869 + _globals['_THINKINGBLOCK']._serialized_start=1871 + _globals['_THINKINGBLOCK']._serialized_end=1940 + _globals['_REDACTEDTHINKINGBLOCK']._serialized_start=1942 + _globals['_REDACTEDTHINKINGBLOCK']._serialized_end=1979 + _globals['_TOOLCALLBLOCK']._serialized_start=1981 + _globals['_TOOLCALLBLOCK']._serialized_end=2042 + _globals['_TOOLRESULTBLOCK']._serialized_start=2044 + _globals['_TOOLRESULTBLOCK']._serialized_end=2104 + _globals['_IMAGEBLOCK']._serialized_start=2106 + _globals['_IMAGEBLOCK']._serialized_end=2173 + _globals['_REASONINGBLOCK']._serialized_start=2175 + _globals['_REASONINGBLOCK']._serialized_end=2225 + _globals['_CONTENTBLOCK']._serialized_start=2228 + _globals['_CONTENTBLOCK']._serialized_end=2725 + _globals['_CONTENTBLOCKLIST']._serialized_start=2727 + _globals['_CONTENTBLOCKLIST']._serialized_end=2793 + _globals['_MESSAGE']._serialized_start=2796 + _globals['_MESSAGE']._serialized_end=2998 + _globals['_TOOLCALLMESSAGE']._serialized_start=3000 + _globals['_TOOLCALLMESSAGE']._serialized_end=3067 + _globals['_TOOLSPECPROTO']._serialized_start=3069 + _globals['_TOOLSPECPROTO']._serialized_end=3144 + _globals['_JSONSCHEMAFORMAT']._serialized_start=3146 + _globals['_JSONSCHEMAFORMAT']._serialized_end=3201 + _globals['_RESPONSEFORMAT']._serialized_start=3203 + _globals['_RESPONSEFORMAT']._serialized_end=3320 + _globals['_USAGE']._serialized_start=3323 + _globals['_USAGE']._serialized_end=3486 + _globals['_DEGRADATION']._serialized_start=3488 + _globals['_DEGRADATION']._serialized_end=3552 + _globals['_CHATREQUEST']._serialized_start=3555 + _globals['_CHATREQUEST']._serialized_end=3940 + _globals['_CHATRESPONSE']._serialized_start=3943 + _globals['_CHATRESPONSE']._serialized_end=4167 + _globals['_TOOLRESULT']._serialized_start=4169 + _globals['_TOOLRESULT']._serialized_end=4239 + _globals['_HOOKRESULT']._serialized_start=4242 + _globals['_HOOKRESULT']._serialized_end=4767 + _globals['_MODELINFO']._serialized_start=4770 + _globals['_MODELINFO']._serialized_end=4911 + _globals['_PROVIDERINFO']._serialized_start=4914 + _globals['_PROVIDERINFO']._serialized_end=5090 + _globals['_APPROVALREQUEST']._serialized_start=5092 + _globals['_APPROVALREQUEST']._serialized_end=5203 + _globals['_APPROVALRESPONSE']._serialized_start=5205 + _globals['_APPROVALRESPONSE']._serialized_end=5275 + _globals['_LISTMODELSRESPONSE']._serialized_start=5277 + _globals['_LISTMODELSRESPONSE']._serialized_end=5342 + _globals['_PARSETOOLCALLSRESPONSE']._serialized_start=5344 + _globals['_PARSETOOLCALLSRESPONSE']._serialized_end=5423 + _globals['_ORCHESTRATOREXECUTEREQUEST']._serialized_start=5425 + _globals['_ORCHESTRATOREXECUTEREQUEST']._serialized_end=5489 + _globals['_ORCHESTRATOREXECUTERESPONSE']._serialized_start=5491 + _globals['_ORCHESTRATOREXECUTERESPONSE']._serialized_end=5553 + _globals['_ADDMESSAGEREQUEST']._serialized_start=5555 + _globals['_ADDMESSAGEREQUEST']._serialized_end=5618 + _globals['_GETMESSAGESRESPONSE']._serialized_start=5620 + _globals['_GETMESSAGESRESPONSE']._serialized_end=5686 + _globals['_GETMESSAGESFORREQUESTPARAMS']._serialized_start=5688 + _globals['_GETMESSAGESFORREQUESTPARAMS']._serialized_end=5762 + _globals['_SETMESSAGESREQUEST']._serialized_start=5764 + _globals['_SETMESSAGESREQUEST']._serialized_end=5829 + _globals['_HOOKHANDLEREQUEST']._serialized_start=5831 + _globals['_HOOKHANDLEREQUEST']._serialized_end=5884 + _globals['_COMPLETEWITHPROVIDERREQUEST']._serialized_start=5886 + _globals['_COMPLETEWITHPROVIDERREQUEST']._serialized_end=5986 + _globals['_EXECUTETOOLREQUEST']._serialized_start=5988 + _globals['_EXECUTETOOLREQUEST']._serialized_end=6047 + _globals['_EMITHOOKREQUEST']._serialized_start=6049 + _globals['_EMITHOOKREQUEST']._serialized_end=6100 + _globals['_EMITHOOKANDCOLLECTREQUEST']._serialized_start=6102 + _globals['_EMITHOOKANDCOLLECTREQUEST']._serialized_end=6188 + _globals['_EMITHOOKANDCOLLECTRESPONSE']._serialized_start=6190 + _globals['_EMITHOOKANDCOLLECTRESPONSE']._serialized_end=6242 + _globals['_GETMESSAGESREQUEST']._serialized_start=6244 + _globals['_GETMESSAGESREQUEST']._serialized_end=6284 + _globals['_KERNELADDMESSAGEREQUEST']._serialized_start=6286 + _globals['_KERNELADDMESSAGEREQUEST']._serialized_end=6375 + _globals['_GETMOUNTEDMODULEREQUEST']._serialized_start=6377 + _globals['_GETMOUNTEDMODULEREQUEST']._serialized_end=6474 + _globals['_GETMOUNTEDMODULERESPONSE']._serialized_start=6476 + _globals['_GETMOUNTEDMODULERESPONSE']._serialized_end=6561 + _globals['_REGISTERCAPABILITYREQUEST']._serialized_start=6563 + _globals['_REGISTERCAPABILITYREQUEST']._serialized_end=6624 + _globals['_GETCAPABILITYREQUEST']._serialized_start=6626 + _globals['_GETCAPABILITYREQUEST']._serialized_end=6662 + _globals['_GETCAPABILITYRESPONSE']._serialized_start=6664 + _globals['_GETCAPABILITYRESPONSE']._serialized_end=6722 + _globals['_TOOLSERVICE']._serialized_start=8711 + _globals['_TOOLSERVICE']._serialized_end=8876 + _globals['_PROVIDERSERVICE']._serialized_start=8879 + _globals['_PROVIDERSERVICE']._serialized_end=9294 + _globals['_ORCHESTRATORSERVICE']._serialized_start=9296 + _globals['_ORCHESTRATORSERVICE']._serialized_end=9421 + _globals['_CONTEXTSERVICE']._serialized_start=9424 + _globals['_CONTEXTSERVICE']._serialized_end=9843 + _globals['_HOOKSERVICE']._serialized_start=9845 + _globals['_HOOKSERVICE']._serialized_end=9935 + _globals['_APPROVALSERVICE']._serialized_start=9937 + _globals['_APPROVALSERVICE']._serialized_end=10044 + _globals['_KERNELSERVICE']._serialized_start=10047 + _globals['_KERNELSERVICE']._serialized_end=11023 + _globals['_MODULELIFECYCLE']._serialized_start=11026 + _globals['_MODULELIFECYCLE']._serialized_end=11329 # @@protoc_insertion_point(module_scope) diff --git a/proto/amplifier_module_pb2_grpc.py b/proto/amplifier_module_pb2_grpc.py index 9a93798..1c5c8cd 100644 --- a/proto/amplifier_module_pb2_grpc.py +++ b/proto/amplifier_module_pb2_grpc.py @@ -906,7 +906,7 @@ def __init__(self, channel): self.EmitHook = channel.unary_unary( '/amplifier.module.KernelService/EmitHook', request_serializer=amplifier__module__pb2.EmitHookRequest.SerializeToString, - response_deserializer=amplifier__module__pb2.Empty.FromString, + response_deserializer=amplifier__module__pb2.HookResult.FromString, _registered_method=True) self.EmitHookAndCollect = channel.unary_unary( '/amplifier.module.KernelService/EmitHookAndCollect', @@ -1030,7 +1030,7 @@ def add_KernelServiceServicer_to_server(servicer, server): 'EmitHook': grpc.unary_unary_rpc_method_handler( servicer.EmitHook, request_deserializer=amplifier__module__pb2.EmitHookRequest.FromString, - response_serializer=amplifier__module__pb2.Empty.SerializeToString, + response_serializer=amplifier__module__pb2.HookResult.SerializeToString, ), 'EmitHookAndCollect': grpc.unary_unary_rpc_method_handler( servicer.EmitHookAndCollect, @@ -1170,7 +1170,7 @@ def EmitHook(request, target, '/amplifier.module.KernelService/EmitHook', amplifier__module__pb2.EmitHookRequest.SerializeToString, - amplifier__module__pb2.Empty.FromString, + amplifier__module__pb2.HookResult.FromString, options, channel_credentials, insecure, diff --git a/python/amplifier_core/_session_exec.py b/python/amplifier_core/_session_exec.py index baeb87c..e92564d 100644 --- a/python/amplifier_core/_session_exec.py +++ b/python/amplifier_core/_session_exec.py @@ -62,42 +62,37 @@ async def run_orchestrator(coordinator: Any, prompt: str) -> str: return result -async def emit_debug_events( +async def emit_raw_field_if_configured( coordinator: Any, config: dict, session_id: str, - event_debug: str, - event_raw: str, + event_base: str, ) -> None: - """Emit debug/raw events if debug flags are set in config. + """Emit the base session event with an optional raw field. - Separated from Rust because it needs Python utilities - (redact_secrets, truncate_values). + When session.raw=true, a redacted copy of the full config is included + as the 'raw' field on the base event. + + This helper is called from the Rust PyO3 bridge's execute() path and + handles the Python utilities (redact_secrets) needed for raw payloads. + + Args: + coordinator: The coordinator with hooks. + config: Full session mount plan. + session_id: Current session ID. + event_base: The base event name (e.g. 'session:start' or 'session:resume'). """ - from .utils import redact_secrets, truncate_values + from .utils import redact_secrets session_config = config.get("session", {}) - debug = session_config.get("debug", False) - raw_debug = session_config.get("raw_debug", False) - - if debug: - mount_plan_safe = redact_secrets(truncate_values(config)) - await coordinator.hooks.emit( - event_debug, - { - "lvl": "DEBUG", - "session_id": session_id, - "mount_plan": mount_plan_safe, - }, - ) + raw = session_config.get("raw", False) - if debug and raw_debug: - mount_plan_redacted = redact_secrets(config) + if raw: + raw_payload = redact_secrets(config) await coordinator.hooks.emit( - event_raw, + event_base, { - "lvl": "DEBUG", "session_id": session_id, - "mount_plan": mount_plan_redacted, + "raw": raw_payload, }, ) diff --git a/python/amplifier_core/events.py b/python/amplifier_core/events.py index b2ad06a..36d1775 100644 --- a/python/amplifier_core/events.py +++ b/python/amplifier_core/events.py @@ -7,15 +7,9 @@ from amplifier_core._engine import ( # Session lifecycle SESSION_START, - SESSION_START_DEBUG, - SESSION_START_RAW, SESSION_END, SESSION_FORK, - SESSION_FORK_DEBUG, - SESSION_FORK_RAW, SESSION_RESUME, - SESSION_RESUME_DEBUG, - SESSION_RESUME_RAW, # Prompt lifecycle PROMPT_SUBMIT, PROMPT_COMPLETE, @@ -32,11 +26,7 @@ PROVIDER_RESOLVE, # LLM events LLM_REQUEST, - LLM_REQUEST_DEBUG, - LLM_REQUEST_RAW, LLM_RESPONSE, - LLM_RESPONSE_DEBUG, - LLM_RESPONSE_RAW, # Content block events CONTENT_BLOCK_START, CONTENT_BLOCK_DELTA, @@ -70,21 +60,14 @@ # Cancellation lifecycle CANCEL_REQUESTED, CANCEL_COMPLETED, - # Aggregate list ALL_EVENTS, ) __all__ = [ "SESSION_START", - "SESSION_START_DEBUG", - "SESSION_START_RAW", "SESSION_END", "SESSION_FORK", - "SESSION_FORK_DEBUG", - "SESSION_FORK_RAW", "SESSION_RESUME", - "SESSION_RESUME_DEBUG", - "SESSION_RESUME_RAW", "PROMPT_SUBMIT", "PROMPT_COMPLETE", "PLAN_START", @@ -97,11 +80,7 @@ "PROVIDER_TOOL_SEQUENCE_REPAIRED", "PROVIDER_RESOLVE", "LLM_REQUEST", - "LLM_REQUEST_DEBUG", - "LLM_REQUEST_RAW", "LLM_RESPONSE", - "LLM_RESPONSE_DEBUG", - "LLM_RESPONSE_RAW", "CONTENT_BLOCK_START", "CONTENT_BLOCK_DELTA", "CONTENT_BLOCK_END", diff --git a/python/amplifier_core/session.py b/python/amplifier_core/session.py index d641d7a..b2db664 100644 --- a/python/amplifier_core/session.py +++ b/python/amplifier_core/session.py @@ -11,7 +11,7 @@ from .coordinator import ModuleCoordinator from .loader import ModuleLoader from .models import SessionStatus -from .utils import redact_secrets, truncate_values +from .utils import redact_secrets if TYPE_CHECKING: from .approval import ApprovalSystem @@ -272,44 +272,20 @@ async def initialize(self) -> None: # Emit session:fork event if this is a child session if self.parent_id: - from .events import SESSION_FORK, SESSION_FORK_DEBUG, SESSION_FORK_RAW + from .events import SESSION_FORK - await self.coordinator.hooks.emit( - SESSION_FORK, - { - "parent": self.parent_id, - "session_id": self.session_id, - }, - ) - - # Debug config from mount plan session_config = self.config.get("session", {}) - debug = session_config.get("debug", False) - raw_debug = session_config.get("raw_debug", False) + session_metadata = session_config.get("metadata", {}) + raw = session_config.get("raw", False) - if debug: - mount_plan_safe = redact_secrets(truncate_values(self.config)) - await self.coordinator.hooks.emit( - SESSION_FORK_DEBUG, - { - "lvl": "DEBUG", - "parent": self.parent_id, - "session_id": self.session_id, - "mount_plan": mount_plan_safe, - }, - ) - - if debug and raw_debug: - mount_plan_redacted = redact_secrets(self.config) - await self.coordinator.hooks.emit( - SESSION_FORK_RAW, - { - "lvl": "DEBUG", - "parent": self.parent_id, - "session_id": self.session_id, - "mount_plan": mount_plan_redacted, - }, - ) + payload: dict = { + "parent": self.parent_id, + "session_id": self.session_id, + **({"metadata": session_metadata} if session_metadata else {}), + } + if raw: + payload["raw"] = redact_secrets(self.config) + await self.coordinator.hooks.emit(SESSION_FORK, payload) logger.info(f"Session {self.session_id} initialized successfully") @@ -330,59 +306,24 @@ async def execute(self, prompt: str) -> str: if not self._initialized: await self.initialize() - from .events import ( - SESSION_RESUME, - SESSION_RESUME_DEBUG, - SESSION_RESUME_RAW, - SESSION_START, - SESSION_START_DEBUG, - SESSION_START_RAW, - ) + from .events import SESSION_RESUME, SESSION_START # Choose event type based on whether this is a new or resumed session - if self._is_resumed: - event_base = SESSION_RESUME - event_debug = SESSION_RESUME_DEBUG - event_raw = SESSION_RESUME_RAW - else: - event_base = SESSION_START - event_debug = SESSION_START_DEBUG - event_raw = SESSION_START_RAW + event_base = SESSION_RESUME if self._is_resumed else SESSION_START # Emit session lifecycle event from kernel (single source of truth) - await self.coordinator.hooks.emit( - event_base, - { - "session_id": self.session_id, - "parent_id": self.parent_id, - }, - ) - session_config = self.config.get("session", {}) - debug = session_config.get("debug", False) - raw_debug = session_config.get("raw_debug", False) - - if debug: - mount_plan_safe = redact_secrets(truncate_values(self.config)) - await self.coordinator.hooks.emit( - event_debug, - { - "lvl": "DEBUG", - "session_id": self.session_id, - "mount_plan": mount_plan_safe, - }, - ) - - if debug and raw_debug: - mount_plan_redacted = redact_secrets(self.config) - await self.coordinator.hooks.emit( - event_raw, - { - "lvl": "DEBUG", - "session_id": self.session_id, - "mount_plan": mount_plan_redacted, - }, - ) + session_metadata = session_config.get("metadata", {}) + raw = session_config.get("raw", False) + + payload: dict = { + "session_id": self.session_id, + "parent_id": self.parent_id, + **({"metadata": session_metadata} if session_metadata else {}), + } + if raw: + payload["raw"] = redact_secrets(self.config) + await self.coordinator.hooks.emit(event_base, payload) orchestrator = self.coordinator.get("orchestrator") if not orchestrator: @@ -457,6 +398,23 @@ async def execute(self, prompt: str) -> str: async def cleanup(self: "AmplifierSession") -> None: """Clean up session resources.""" try: + # Emit SESSION_END before coordinator cleanup (matches Rust behavior) + if self._initialized: + try: + from .events import SESSION_END + + await self.coordinator.hooks.emit( + SESSION_END, + { + "session_id": self.session_id, + "status": self.status.status, + }, + ) + except Exception: + logger.debug( + "Failed to emit SESSION_END during cleanup", exc_info=True + ) + await self.coordinator.cleanup() finally: # Clean up sys.path modifications - must always run even if diff --git a/tests/test_all_events_from_engine.py b/tests/test_all_events_from_engine.py new file mode 100644 index 0000000..9c89ccf --- /dev/null +++ b/tests/test_all_events_from_engine.py @@ -0,0 +1,17 @@ +""" +Test that ALL_EVENTS in events.py is imported from _engine (not locally defined). + +This is a structural test: it verifies we don't have a duplicated local list +that can drift from the Rust-authoritative source. +""" + +from amplifier_core import _engine +from amplifier_core import events + + +def test_all_events_is_imported_from_engine(): + """ALL_EVENTS must be the object exported by the Rust _engine, not a local copy.""" + assert events.ALL_EVENTS is _engine.ALL_EVENTS, ( + "events.ALL_EVENTS is a local copy, not imported from _engine. " + "Remove the local list and add ALL_EVENTS to the _engine import." + ) diff --git a/tests/test_event_taxonomy.py b/tests/test_event_taxonomy.py index 3a65bdb..0ba11ff 100644 --- a/tests/test_event_taxonomy.py +++ b/tests/test_event_taxonomy.py @@ -30,28 +30,19 @@ def test_all_event_constants_in_all_events(): def test_events_follow_naming_convention(): - """Verify all events follow namespace:action or namespace:action:detail convention.""" - valid_detail_suffixes = {"debug", "raw"} + """Verify all events follow namespace:action convention.""" for event in events.ALL_EVENTS: assert ":" in event, f"Event {event} missing namespace separator ':'" parts = event.split(":") assert len(parts) >= 2, ( - f"Event {event} should follow namespace:action or namespace:action:detail convention" - ) - assert len(parts) <= 3, ( - f"Event {event} has too many ':' separators (max 3 parts: namespace:action:detail)" + f"Event {event} should follow namespace:action convention" ) + # All events must be exactly 2 parts (namespace:action) + assert len(parts) == 2, f"Event {event} has more than 2 ':' parts" namespace = parts[0] action = parts[1] assert namespace, f"Event {event} has empty namespace" assert action, f"Event {event} has empty action" - if len(parts) == 3: - detail = parts[2] - assert detail, f"Event {event} has empty detail suffix" - assert detail in valid_detail_suffixes, ( - f"Event {event} has unexpected detail suffix '{detail}' " - f"(expected one of: {valid_detail_suffixes})" - ) # Allow lowercase with underscores assert event.islower() or "_" in event, ( f"Event {event} not lowercase/snake_case" diff --git a/tests/test_session.py b/tests/test_session.py index 38e5cbc..eb0941c 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -209,3 +209,100 @@ async def test_session_with_custom_loader(): session = PyAmplifierSession(config, loader=custom_loader) assert session.loader is custom_loader + + +@pytest.mark.asyncio +async def test_cleanup_emits_session_end(minimal_config): + """Test that cleanup() emits SESSION_END with session_id and status.""" + from amplifier_core.events import SESSION_END + from amplifier_core.models import HookResult + + session = PyAmplifierSession(minimal_config) + session._initialized = True + + # Track emitted events via a registered hook handler + emitted_events = [] + + async def capture_handler(event, data): + emitted_events.append((event, dict(data))) + return HookResult(action="continue") + + session.coordinator.hooks.on(SESSION_END, capture_handler, name="test-capture") + + # Mock coordinator.cleanup to avoid actual module cleanup + session.coordinator.cleanup = AsyncMock() + + await session.cleanup() + + # Filter for SESSION_END events + session_end_events = [(e, d) for e, d in emitted_events if e == SESSION_END] + + assert len(session_end_events) == 1, ( + f"Expected exactly 1 SESSION_END event, got {len(session_end_events)}" + ) + _, data = session_end_events[0] + assert "session_id" in data, "SESSION_END data must contain session_id" + assert "status" in data, "SESSION_END data must contain status" + assert data["session_id"] == session.session_id + + +@pytest.mark.asyncio +async def test_cleanup_does_not_emit_session_end_when_not_initialized(minimal_config): + """Test that cleanup() does NOT emit SESSION_END for uninitialized sessions.""" + from amplifier_core.events import SESSION_END + from amplifier_core.models import HookResult + + session = PyAmplifierSession(minimal_config) + # Do NOT set _initialized = True (default is False) + + # Track emitted events via a registered hook handler + emitted_events = [] + + async def capture_handler(event, data): + emitted_events.append((event, dict(data))) + return HookResult(action="continue") + + session.coordinator.hooks.on(SESSION_END, capture_handler, name="test-capture") + + # Mock coordinator.cleanup to avoid actual module cleanup + session.coordinator.cleanup = AsyncMock() + + await session.cleanup() + + # Filter for SESSION_END events + session_end_events = [(e, d) for e, d in emitted_events if e == SESSION_END] + + assert len(session_end_events) == 0, ( + f"Expected 0 SESSION_END events for uninitialized session, got {len(session_end_events)}" + ) + + +@pytest.mark.asyncio +async def test_cleanup_emits_session_end_before_coordinator_cleanup(minimal_config): + """Test that SESSION_END is emitted before coordinator.cleanup() runs.""" + from amplifier_core.events import SESSION_END + from amplifier_core.models import HookResult + + session = PyAmplifierSession(minimal_config) + session._initialized = True + + # Record the order of operations + call_order = [] + + async def capture_handler(event, data): + call_order.append("session_end_emitted") + return HookResult(action="continue") + + session.coordinator.hooks.on(SESSION_END, capture_handler, name="test-capture") + + # Mock coordinator.cleanup to record when it runs + async def tracking_cleanup(): + call_order.append("coordinator_cleanup") + + session.coordinator.cleanup = tracking_cleanup + + await session.cleanup() + + assert call_order == ["session_end_emitted", "coordinator_cleanup"], ( + f"Expected SESSION_END before coordinator.cleanup(), got: {call_order}" + ) diff --git a/tests/test_session_metadata.py b/tests/test_session_metadata.py new file mode 100644 index 0000000..ba2ccf0 --- /dev/null +++ b/tests/test_session_metadata.py @@ -0,0 +1,276 @@ +""" +Tests for session metadata passthrough on session:start, session:fork, session:resume. + +CP-SM: Kernel reads config.session.metadata and includes it as optional 'metadata' +key in event payloads. Pure passthrough - no interpretation or validation. +""" + +from unittest.mock import AsyncMock, Mock + +import pytest +from amplifier_core.events import SESSION_FORK, SESSION_RESUME, SESSION_START +from amplifier_core.models import HookResult +from amplifier_core.session import AmplifierSession as PyAmplifierSession + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _minimal_config_with_metadata(metadata): + """Config that includes session.metadata.""" + return { + "session": { + "orchestrator": "loop-basic", + "context": "context-simple", + "metadata": metadata, + }, + "providers": [], + "tools": [], + } + + +def _minimal_config_no_metadata(): + """Config without session.metadata.""" + return { + "session": { + "orchestrator": "loop-basic", + "context": "context-simple", + }, + "providers": [], + "tools": [], + } + + +def _setup_mock_loader(session): + """Replace the session loader with a mock that succeeds silently.""" + mock_mount = AsyncMock(return_value=None) + session.loader.load = AsyncMock(return_value=mock_mount) + + +def _make_capture_handler(events_list): + """Return an async hook handler that appends (event, data) to events_list.""" + + async def handler(event, data): + events_list.append((event, dict(data))) + return HookResult(action="continue") + + return handler + + +# --------------------------------------------------------------------------- +# session:start metadata tests +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_session_start_includes_metadata_when_configured(): + """session:start payload includes 'metadata' when config.session.metadata is set.""" + metadata = {"agent_name": "test-agent", "run_id": "abc123"} + config = _minimal_config_with_metadata(metadata) + + session = PyAmplifierSession(config) + session._initialized = True + + # Mount minimal mocks + mock_orchestrator = AsyncMock() + mock_orchestrator.execute = AsyncMock(return_value="ok") + mock_context = Mock() + mock_context.add_message = AsyncMock() + mock_context.get_messages = AsyncMock(return_value=[]) + session.coordinator.mount_points["orchestrator"] = mock_orchestrator + session.coordinator.mount_points["context"] = mock_context + session.coordinator.mount_points["providers"] = {"mock": Mock()} + + emitted = [] + session.coordinator.hooks.on( + SESSION_START, _make_capture_handler(emitted), name="test-capture" + ) + + await session.execute("hello") + + start_events = [d for e, d in emitted if e == SESSION_START] + assert len(start_events) == 1, f"Expected 1 SESSION_START, got {len(start_events)}" + payload = start_events[0] + assert "metadata" in payload, "Expected 'metadata' key in session:start payload" + assert payload["metadata"] == metadata + + +@pytest.mark.asyncio +async def test_session_start_excludes_metadata_when_not_configured(): + """session:start payload does NOT include 'metadata' when config.session.metadata is absent.""" + config = _minimal_config_no_metadata() + + session = PyAmplifierSession(config) + session._initialized = True + + mock_orchestrator = AsyncMock() + mock_orchestrator.execute = AsyncMock(return_value="ok") + mock_context = Mock() + mock_context.add_message = AsyncMock() + mock_context.get_messages = AsyncMock(return_value=[]) + session.coordinator.mount_points["orchestrator"] = mock_orchestrator + session.coordinator.mount_points["context"] = mock_context + session.coordinator.mount_points["providers"] = {"mock": Mock()} + + emitted = [] + session.coordinator.hooks.on( + SESSION_START, _make_capture_handler(emitted), name="test-capture" + ) + + await session.execute("hello") + + start_events = [d for e, d in emitted if e == SESSION_START] + assert len(start_events) == 1 + payload = start_events[0] + assert "metadata" not in payload, ( + "Expected no 'metadata' key in session:start payload when not configured" + ) + + +# --------------------------------------------------------------------------- +# session:resume metadata tests +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_session_resume_includes_metadata_when_configured(): + """session:resume payload includes 'metadata' when config.session.metadata is set.""" + metadata = {"agent_name": "resumed-agent"} + config = _minimal_config_with_metadata(metadata) + + session = PyAmplifierSession(config, is_resumed=True) + session._initialized = True + + mock_orchestrator = AsyncMock() + mock_orchestrator.execute = AsyncMock(return_value="ok") + mock_context = Mock() + session.coordinator.mount_points["orchestrator"] = mock_orchestrator + session.coordinator.mount_points["context"] = mock_context + session.coordinator.mount_points["providers"] = {"mock": Mock()} + + emitted = [] + session.coordinator.hooks.on( + SESSION_RESUME, _make_capture_handler(emitted), name="test-capture" + ) + + await session.execute("hello") + + resume_events = [d for e, d in emitted if e == SESSION_RESUME] + assert len(resume_events) == 1, ( + f"Expected 1 SESSION_RESUME, got {len(resume_events)}" + ) + payload = resume_events[0] + assert "metadata" in payload, "Expected 'metadata' key in session:resume payload" + assert payload["metadata"] == metadata + + +@pytest.mark.asyncio +async def test_session_resume_excludes_metadata_when_not_configured(): + """session:resume payload does NOT include 'metadata' when not set in config.""" + config = _minimal_config_no_metadata() + + session = PyAmplifierSession(config, is_resumed=True) + session._initialized = True + + mock_orchestrator = AsyncMock() + mock_orchestrator.execute = AsyncMock(return_value="ok") + mock_context = Mock() + session.coordinator.mount_points["orchestrator"] = mock_orchestrator + session.coordinator.mount_points["context"] = mock_context + session.coordinator.mount_points["providers"] = {"mock": Mock()} + + emitted = [] + session.coordinator.hooks.on( + SESSION_RESUME, _make_capture_handler(emitted), name="test-capture" + ) + + await session.execute("hello") + + resume_events = [d for e, d in emitted if e == SESSION_RESUME] + assert len(resume_events) == 1 + payload = resume_events[0] + assert "metadata" not in payload, ( + "Expected no 'metadata' key in session:resume payload when not configured" + ) + + +# --------------------------------------------------------------------------- +# session:fork metadata tests +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_session_fork_includes_metadata_when_configured(): + """session:fork payload includes 'metadata' when config.session.metadata is set.""" + metadata = {"agent_name": "child-agent", "depth": 1} + config = _minimal_config_with_metadata(metadata) + + parent_id = "parent-session-id-123" + session = PyAmplifierSession(config, parent_id=parent_id) + + _setup_mock_loader(session) + + emitted = [] + session.coordinator.hooks.on( + SESSION_FORK, _make_capture_handler(emitted), name="test-capture" + ) + + await session.initialize() + + fork_events = [d for e, d in emitted if e == SESSION_FORK] + assert len(fork_events) == 1, f"Expected 1 SESSION_FORK, got {len(fork_events)}" + payload = fork_events[0] + assert "metadata" in payload, "Expected 'metadata' key in session:fork payload" + assert payload["metadata"] == metadata + + +@pytest.mark.asyncio +async def test_session_fork_excludes_metadata_when_not_configured(): + """session:fork payload does NOT include 'metadata' when config.session.metadata is absent.""" + config = _minimal_config_no_metadata() + + parent_id = "parent-session-id-456" + session = PyAmplifierSession(config, parent_id=parent_id) + + _setup_mock_loader(session) + + emitted = [] + session.coordinator.hooks.on( + SESSION_FORK, _make_capture_handler(emitted), name="test-capture" + ) + + await session.initialize() + + fork_events = [d for e, d in emitted if e == SESSION_FORK] + assert len(fork_events) == 1 + payload = fork_events[0] + assert "metadata" not in payload, ( + "Expected no 'metadata' key in session:fork payload when not configured" + ) + + +@pytest.mark.asyncio +async def test_session_fork_still_has_parent_and_session_id(): + """session:fork payload still contains parent and session_id regardless of metadata.""" + metadata = {"tag": "some-tag"} + config = _minimal_config_with_metadata(metadata) + + parent_id = "parent-xyz" + session = PyAmplifierSession(config, parent_id=parent_id) + + _setup_mock_loader(session) + + emitted = [] + session.coordinator.hooks.on( + SESSION_FORK, _make_capture_handler(emitted), name="test-capture" + ) + + await session.initialize() + + fork_events = [d for e, d in emitted if e == SESSION_FORK] + assert len(fork_events) == 1 + payload = fork_events[0] + assert payload["parent"] == parent_id + assert "session_id" in payload