pub struct Extension { /* private fields */ }Expand description
The author-facing registration surface for a PXB extension binary.
Implementations§
Source§impl Extension
impl Extension
Sourcepub fn new(name: impl Into<String>, version: impl Into<String>) -> Self
pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self
Constructs a module; call run once everything is
registered.
Examples found in repository?
examples/full.rs (line 6)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("full", "0.1.0");
7
8 m.register_tool(phi::Tool::new(
9 "echo",
10 "Echo the input back",
11 phi::Schema::object()
12 .property("text", phi::Schema::string())
13 .required(["text"]),
14 |args| {
15 let text = String::from_utf8_lossy(args);
16 Ok(phi::ToolResult {
17 content: format!("echo: {text}"),
18 ..Default::default()
19 })
20 },
21 ));
22
23 m.register_command(
24 "ask",
25 phi::Command::new("Ask a yes/no question", |_args, ctx| {
26 let reply = ctx.confirm("Confirm?", "Proceed with /tmp/x?");
27 if reply.ok {
28 ctx.notify("info", "Confirmed!");
29 } else {
30 ctx.notify("warning", "Declined.");
31 }
32 ctx.submit("follow-up from ask");
33 Ok(())
34 }),
35 );
36
37 m.run()
38}More examples
examples/hello.rs (line 6)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn register_tool(&mut self, tool: Tool)
pub fn register_tool(&mut self, tool: Tool)
Adds an LLM-callable tool.
Examples found in repository?
examples/full.rs (lines 8-21)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("full", "0.1.0");
7
8 m.register_tool(phi::Tool::new(
9 "echo",
10 "Echo the input back",
11 phi::Schema::object()
12 .property("text", phi::Schema::string())
13 .required(["text"]),
14 |args| {
15 let text = String::from_utf8_lossy(args);
16 Ok(phi::ToolResult {
17 content: format!("echo: {text}"),
18 ..Default::default()
19 })
20 },
21 ));
22
23 m.register_command(
24 "ask",
25 phi::Command::new("Ask a yes/no question", |_args, ctx| {
26 let reply = ctx.confirm("Confirm?", "Proceed with /tmp/x?");
27 if reply.ok {
28 ctx.notify("info", "Confirmed!");
29 } else {
30 ctx.notify("warning", "Declined.");
31 }
32 ctx.submit("follow-up from ask");
33 Ok(())
34 }),
35 );
36
37 m.run()
38}Sourcepub fn register_command(&mut self, name: impl Into<String>, cmd: Command)
pub fn register_command(&mut self, name: impl Into<String>, cmd: Command)
Adds a slash command (cannot override builtins at host level).
Examples found in repository?
examples/full.rs (lines 23-35)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("full", "0.1.0");
7
8 m.register_tool(phi::Tool::new(
9 "echo",
10 "Echo the input back",
11 phi::Schema::object()
12 .property("text", phi::Schema::string())
13 .required(["text"]),
14 |args| {
15 let text = String::from_utf8_lossy(args);
16 Ok(phi::ToolResult {
17 content: format!("echo: {text}"),
18 ..Default::default()
19 })
20 },
21 ));
22
23 m.register_command(
24 "ask",
25 phi::Command::new("Ask a yes/no question", |_args, ctx| {
26 let reply = ctx.confirm("Confirm?", "Proceed with /tmp/x?");
27 if reply.ok {
28 ctx.notify("info", "Confirmed!");
29 } else {
30 ctx.notify("warning", "Declined.");
31 }
32 ctx.submit("follow-up from ask");
33 Ok(())
34 }),
35 );
36
37 m.run()
38}More examples
examples/hello.rs (lines 8-16)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn on_tool_call(
&mut self,
f: impl FnMut(ToolCallEvent) -> Option<ToolCallResult> + 'static,
)
pub fn on_tool_call( &mut self, f: impl FnMut(ToolCallEvent) -> Option<ToolCallResult> + 'static, )
Registers a pre-gate tool_call intercept.
Examples found in repository?
examples/hello.rs (lines 24-27)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn on_tool_result(
&mut self,
f: impl FnMut(ToolResultEvent) -> Option<ToolResultResult> + 'static,
)
pub fn on_tool_result( &mut self, f: impl FnMut(ToolResultEvent) -> Option<ToolResultResult> + 'static, )
Registers a post-tool tool_result intercept.
Examples found in repository?
examples/hello.rs (lines 29-32)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn on_before_agent_start(
&mut self,
f: impl FnMut(BeforeAgentStartEvent) -> Option<BeforeAgentStartResult> + 'static,
)
pub fn on_before_agent_start( &mut self, f: impl FnMut(BeforeAgentStartEvent) -> Option<BeforeAgentStartResult> + 'static, )
May append system prompt text before the agent loop starts.
Sourcepub fn on_session_before_switch(
&mut self,
f: impl FnMut(SessionBeforeSwitchEvent) -> Option<SessionBeforeSwitchResult> + 'static,
)
pub fn on_session_before_switch( &mut self, f: impl FnMut(SessionBeforeSwitchEvent) -> Option<SessionBeforeSwitchResult> + 'static, )
May cancel a session switch.
Sourcepub fn on_user_input(
&mut self,
f: impl FnMut(UserInputEvent) -> Option<UserInputResult> + 'static,
)
pub fn on_user_input( &mut self, f: impl FnMut(UserInputEvent) -> Option<UserInputResult> + 'static, )
May transform or swallow the user prompt before the agent loop.
Examples found in repository?
examples/hello.rs (lines 18-22)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn on_turn_stopping(
&mut self,
f: impl FnMut(TurnStoppingEvent) -> Option<TurnStoppingResult> + 'static,
)
pub fn on_turn_stopping( &mut self, f: impl FnMut(TurnStoppingEvent) -> Option<TurnStoppingResult> + 'static, )
May steer another agent step when the model stops with no tools.
Examples found in repository?
examples/hello.rs (lines 34-37)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn subscribe(&mut self, event: Event, f: impl FnMut(EventNotify) + 'static)
pub fn subscribe(&mut self, event: Event, f: impl FnMut(EventNotify) + 'static)
Adds a fire-and-forget lifecycle listener; the payload is the wire
EventNotify. Unknown events are ignored.
Examples found in repository?
examples/hello.rs (lines 39-41)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Sourcepub fn run(self) -> Result<(), Error>
pub fn run(self) -> Result<(), Error>
Speaks PXB on stdin/stdout until the host shuts down.
Examples found in repository?
examples/full.rs (line 37)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("full", "0.1.0");
7
8 m.register_tool(phi::Tool::new(
9 "echo",
10 "Echo the input back",
11 phi::Schema::object()
12 .property("text", phi::Schema::string())
13 .required(["text"]),
14 |args| {
15 let text = String::from_utf8_lossy(args);
16 Ok(phi::ToolResult {
17 content: format!("echo: {text}"),
18 ..Default::default()
19 })
20 },
21 ));
22
23 m.register_command(
24 "ask",
25 phi::Command::new("Ask a yes/no question", |_args, ctx| {
26 let reply = ctx.confirm("Confirm?", "Proceed with /tmp/x?");
27 if reply.ok {
28 ctx.notify("info", "Confirmed!");
29 } else {
30 ctx.notify("warning", "Declined.");
31 }
32 ctx.submit("follow-up from ask");
33 Ok(())
34 }),
35 );
36
37 m.run()
38}More examples
examples/hello.rs (line 43)
5fn main() -> Result<(), phi::Error> {
6 let mut m = phi::Extension::new("hello", "0.1.0");
7
8 m.register_command(
9 "hello",
10 phi::Command::new("Say hi", |_args, ctx| {
11 ctx.notify("info", "Hello!");
12 // ctx.submit("follow-up"); // after /hello returns
13 // ctx.send_user_message("…"); // enqueue a turn anytime
14 Ok(())
15 }),
16 );
17
18 m.on_user_input(|_ev| {
19 // return Some(phi::UserInputResult { handled: true, ..Default::default() }) to swallow
20 // return Some(phi::UserInputResult { text: Some("rewritten".into()), ..Default::default() }) to transform
21 None
22 });
23
24 m.on_tool_call(|_ev| {
25 // return Some(phi::ToolCallResult { block: true, reason: "...".into(), ..Default::default() }) to deny
26 None
27 });
28
29 m.on_tool_result(|_ev| {
30 // return Some(phi::ToolResultResult { stop: true, ..Default::default() }) to end the agent loop
31 None
32 });
33
34 m.on_turn_stopping(|_ev| {
35 // return Some(phi::TurnStoppingResult { continue_: true, message: "check X".into(), ..Default::default() }) to steer
36 None
37 });
38
39 m.subscribe(pxb::Event::SessionStart, |ev| {
40 let _ = ev; // Reason, PreviousSessionID, …
41 });
42
43 m.run()
44}Auto Trait Implementations§
impl !RefUnwindSafe for Extension
impl !Send for Extension
impl !Sync for Extension
impl !UnwindSafe for Extension
impl Freeze for Extension
impl Unpin for Extension
impl UnsafeUnpin for Extension
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more