Skip to main content

cpex_core/cmf/
mod.rs

1// Location: ./crates/cpex-core/src/cmf/mod.rs
2// Copyright 2025
3// SPDX-License-Identifier: Apache-2.0
4// Authors: Teryl Taylor
5//
6// ContextForge Message Format (CMF).
7//
8// Canonical message representation for interactions between users,
9// agents, tools, and language models. All models mirror the Python
10// CMF in cpex/framework/cmf/message.py.
11//
12// Extensions are NOT part of the Message — they are passed separately
13// to handlers via the framework's Extensions type in hooks/payload.rs.
14// This allows extensions to be shared across payload types and avoids
15// copying the message when extensions change.
16//
17// # Hook Registration Patterns
18//
19// CMF supports two registration patterns for plugins:
20//
21// ## Pattern 1: One handler, multiple hook names (recommended)
22//
23// Use `CmfHook` as the hook type and register under multiple names.
24// The plugin writes one handler that covers all CMF hooks. The host
25// invokes via `invoke_by_name("cmf.tool_pre_invoke", ...)`.
26//
27// ```rust,ignore
28// // Plugin implements one handler:
29// impl HookHandler<CmfHook> for MyPlugin {
30//     fn handle(&self, payload: &MessagePayload, ext: &Extensions, ctx: &mut PluginContext)
31//         -> PluginResult<MessagePayload> { ... }
32// }
33//
34// // Factory registers under multiple names:
35// PluginInstance {
36//     plugin: plugin.clone(),
37//     handlers: vec![
38//         ("cmf.tool_pre_invoke", Arc::new(TypedHandlerAdapter::<CmfHook, _>::new(plugin.clone()))),
39//         ("cmf.tool_post_invoke", Arc::new(TypedHandlerAdapter::<CmfHook, _>::new(plugin))),
40//     ],
41// }
42//
43// // Host invokes via invoke_named — compile-time payload type safety
44// // plus runtime hook name routing:
45// mgr.invoke_named::<CmfHook>(
46//     "cmf.tool_pre_invoke", payload, ext, None,
47// ).await;
48// ```
49//
50// `invoke_named::<CmfHook>(hook_name, ...)` gives you both:
51// - **Compile-time**: payload must be `MessagePayload` (from `CmfHook::Payload`)
52// - **Runtime**: dispatches to plugins registered under the specific hook name
53//
54// This is the recommended approach for CMF hooks. Alternatively, use
55// `invoke_by_name(hook_name, boxed_payload, ...)` for fully dynamic
56// dispatch (no compile-time payload check).
57//
58// ## Pattern 2: Individual hook types (optional)
59//
60// For hosts that want per-hook marker types, define separate hook
61// types. Each maps to one hook name. The plugin must implement a
62// handler per type (more boilerplate).
63//
64// ```rust,ignore
65// define_hook! {
66//     CmfToolPreInvoke, "cmf.tool_pre_invoke" => {
67//         payload: MessagePayload,
68//         result: PluginResult<MessagePayload>,
69//     }
70// }
71//
72// // Plugin implements per-hook handlers:
73// impl HookHandler<CmfToolPreInvoke> for MyPlugin { ... }
74// impl HookHandler<CmfToolPostInvoke> for MyPlugin { ... }
75//
76// // Host uses typed invoke:
77// mgr.invoke::<CmfToolPreInvoke>(payload, ext, None).await;
78// ```
79//
80// Both patterns use the same executor, registry, and capabilities.
81// Pattern 1 with `invoke_named` is recommended — one handler impl,
82// compile-time payload safety, and explicit hook name routing.
83//
84// Available CMF hook names (defined in hooks/types.rs):
85//   cmf.tool_pre_invoke, cmf.tool_post_invoke,
86//   cmf.llm_input, cmf.llm_output,
87//   cmf.prompt_pre_fetch, cmf.prompt_post_fetch,
88//   cmf.resource_pre_fetch, cmf.resource_post_fetch
89
90pub mod constants;
91pub mod content;
92pub mod enums;
93pub mod message;
94pub mod view;
95
96// Re-export key types at the cmf module level
97pub use content::*;
98pub use enums::*;
99pub use message::{CmfHook, Message, MessagePayload};
100pub use view::{MessageView, ViewAction, ViewKind};