Skip to main content

AgentContext

Struct AgentContext 

Source
pub struct AgentContext {
    pub run_id: String,
    pub session_id: String,
    pub step_id: String,
    pub agent_role: String,
    pub lease_token: String,
    pub attempt: u64,
    pub state_version: u64,
    pub pending_patch: State,
}

Fields§

§run_id: String§session_id: String§step_id: String§agent_role: String§lease_token: String§attempt: u64§state_version: u64§pending_patch: State

Implementations§

Source§

impl AgentContext

Source

pub fn write_state(&mut self, key: &str, value: Value)

Examples found in repository?
examples/three_minute_demo.rs (line 89)
20fn main() -> agentledger::Result<()> {
21    let mut runtime = Runtime::new();
22    runtime.register_tool(
23        ToolSpec::new(
24            "ticket.create",
25            Box::new(|args| {
26                Ok(Value::Object(state(&[
27                    ("external_id", "TICKET-1".into()),
28                    ("title", args["title"].clone()),
29                ])))
30            }),
31        )
32        .side_effect("external_write")
33        .idempotency_required(true)
34        .input_schema(Value::Object(state(&[
35            ("type", "object".into()),
36            (
37                "required",
38                Value::Array(vec![Value::String("title".to_string())]),
39            ),
40        ]))),
41    );
42    let (run_id, _) = runtime.create_run(State::new());
43
44    let first_claim = runtime.store.claim_step("worker-before-crash", &run_id, 60.0)?;
45    let first_ctx = AgentContext {
46        run_id: run_id.clone(),
47        session_id: first_claim.session_id.clone(),
48        step_id: first_claim.step_id.clone(),
49        agent_role: "SupportAgent".to_string(),
50        lease_token: first_claim.lease_token.clone(),
51        attempt: first_claim.attempt,
52        state_version: first_claim.state_version,
53        pending_patch: State::new(),
54    };
55    let ticket = runtime.call_tool(
56        &first_ctx,
57        "ticket.create",
58        state(&[
59            ("title", "Investigate failed payment".into()),
60            ("_logical_operation", "open-payment-ticket".into()),
61        ]),
62    )?;
63    runtime.store.mark_retry(
64        &run_id,
65        &first_ctx.step_id,
66        "RetryableAgentError",
67        "after external ticket create, before state commit",
68    );
69
70    let second_claim = runtime.store.claim_step("worker-after-restart", &run_id, 60.0)?;
71    let mut second_ctx = AgentContext {
72        run_id: run_id.clone(),
73        session_id: second_claim.session_id.clone(),
74        step_id: second_claim.step_id.clone(),
75        agent_role: "SupportAgent".to_string(),
76        lease_token: second_claim.lease_token.clone(),
77        attempt: second_claim.attempt,
78        state_version: second_claim.state_version,
79        pending_patch: State::new(),
80    };
81    let replayed_ticket = runtime.call_tool(
82        &second_ctx,
83        "ticket.create",
84        state(&[
85            ("title", "Investigate failed payment".into()),
86            ("_logical_operation", "open-payment-ticket".into()),
87        ]),
88    )?;
89    second_ctx.write_state("ticket", replayed_ticket);
90    second_ctx.write_state("recovered", true.into());
91    runtime.store.commit_state_patch(
92        &run_id,
93        &second_ctx.step_id,
94        &second_ctx.lease_token,
95        second_ctx.state_version,
96        second_ctx.pending_patch,
97    )?;
98
99    let summary = replay(&runtime.store, &run_id)?;
100    let ledger = runtime.store.ledger(&run_id);
101    let final_state = runtime.store.final_state(&run_id)?;
102    println!(
103        "{{\n  \"run_id\": \"{}\",\n  \"first_attempt_ok\": false,\n  \"second_attempt_ok\": true,\n  \"external_ticket_count\": 1,\n  \"actual_tool_executions\": 1,\n  \"tool_ledger_count\": {},\n  \"tool_ledger_status\": \"{}\",\n  \"first_ticket_external_id\": \"{}\",\n  \"final_state_recovered\": {},\n  \"replay\": {{\n    \"safe\": {},\n    \"event_count\": {},\n    \"tool_call_count\": {}\n  }}\n}}",
104        run_id,
105        ledger.len(),
106        ledger.first().map(|row| row.status.as_str()).unwrap_or(""),
107        get_string(&ticket, "external_id"),
108        final_state.get("recovered") == Some(&Value::Bool(true)),
109        summary.replay_safe,
110        summary.event_count,
111        summary.tool_call_count
112    );
113    Ok(())
114}
More examples
Hide additional examples
examples/mcp_governance.rs (line 139)
33fn main() -> agentledger::Result<()> {
34    let mut runtime = Runtime::new();
35    runtime.set_sandbox(Box::new(DemoSandboxExecutor));
36    let mut server = InMemoryMCPToolServer::new();
37    server.add_tool(
38        state(&[
39            ("name", "mcp.github.create_pr".into()),
40            (
41                "inputSchema",
42                Value::Object(state(&[
43                    ("type", "object".into()),
44                    (
45                        "required",
46                        Value::Array(vec![Value::String("title".to_string())]),
47                    ),
48                    (
49                        "properties",
50                        Value::Object(state(&[(
51                            "title",
52                            Value::Object(state(&[
53                                ("type", "string".into()),
54                                ("minLength", 1_i64.into()),
55                            ])),
56                        )])),
57                    ),
58                ])),
59            ),
60            (
61                "annotations",
62                Value::Object(state(&[
63                    ("side_effect", "external_write".into()),
64                    ("risk_level", "high".into()),
65                    ("idempotency_required", true.into()),
66                    ("approval_required", true.into()),
67                    ("sandbox_required", true.into()),
68                    (
69                        "sandbox_policy",
70                        Value::Object(state(&[
71                            ("network", "deny".into()),
72                            ("filesystem", "read-only".into()),
73                        ])),
74                    ),
75                ])),
76            ),
77        ]),
78        create_pr,
79    );
80    let adapter = MCPToolAdapter { client_call: create_pr };
81    for descriptor in server.list_tools() {
82        runtime.register_tool(adapter.tool_spec_from_descriptor(&descriptor));
83    }
84
85    let (run_id, _) = runtime.create_run(State::new());
86    let first_claim = runtime.store.claim_step("worker-before-approval", &run_id, 60.0)?;
87    let first_ctx = AgentContext {
88        run_id: run_id.clone(),
89        session_id: first_claim.session_id.clone(),
90        step_id: first_claim.step_id.clone(),
91        agent_role: "MCPAgent".to_string(),
92        lease_token: first_claim.lease_token.clone(),
93        attempt: first_claim.attempt,
94        state_version: first_claim.state_version,
95        pending_patch: State::new(),
96    };
97    let first = runtime.call_tool(
98        &first_ctx,
99        "mcp.github.create_pr",
100        state(&[
101            ("title", "Update runtime docs".into()),
102            ("_logical_operation", "docs-pr".into()),
103        ]),
104    );
105    let approval_id = first
106        .unwrap_err()
107        .0
108        .trim_start_matches("approval required:")
109        .to_string();
110    runtime.store.mark_waiting_human(
111        &run_id,
112        &first_ctx.step_id,
113        "approval required for tool mcp.github.create_pr",
114        &approval_id,
115    );
116    runtime
117        .store
118        .approve_request(&approval_id, "maintainer", "demo approval")?;
119
120    let second_claim = runtime.store.claim_step("worker-after-approval", &run_id, 60.0)?;
121    let mut second_ctx = AgentContext {
122        run_id: run_id.clone(),
123        session_id: second_claim.session_id.clone(),
124        step_id: second_claim.step_id.clone(),
125        agent_role: "MCPAgent".to_string(),
126        lease_token: second_claim.lease_token.clone(),
127        attempt: second_claim.attempt,
128        state_version: second_claim.state_version,
129        pending_patch: State::new(),
130    };
131    let result = runtime.call_tool(
132        &second_ctx,
133        "mcp.github.create_pr",
134        state(&[
135            ("title", "Update runtime docs".into()),
136            ("_logical_operation", "docs-pr".into()),
137        ]),
138    )?;
139    second_ctx.write_state("pull_request", result);
140    runtime.store.commit_state_patch(
141        &run_id,
142        &second_ctx.step_id,
143        &second_ctx.lease_token,
144        second_ctx.state_version,
145        second_ctx.pending_patch,
146    )?;
147
148    let approvals = runtime.store.approval_requests(&run_id);
149    println!(
150        "{{\n  \"run_id\": \"{}\",\n  \"first_attempt_waited_for_approval\": true,\n  \"second_attempt_ok\": true,\n  \"approval_count\": {},\n  \"approval_status\": \"{}\",\n  \"external_action_count\": 1,\n  \"final_state_has_pull_request\": {}\n}}",
151        run_id,
152        approvals.len(),
153        approvals.first().map(|row| row.status.as_str()).unwrap_or(""),
154        runtime
155            .store
156            .final_state(&run_id)?
157            .contains_key("pull_request")
158    );
159    Ok(())
160}

Trait Implementations§

Source§

impl Clone for AgentContext

Source§

fn clone(&self) -> AgentContext

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AgentContext

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.