NeoGraph 0.16.0
A C++20 Graph Agent Engine Library — LangGraph for C++
Loading...
Searching...
No Matches
runtime_interposition_consumer.h
1#pragma once
2
3#include <neograph/provider.h>
5#include <neograph/runtime_interposition_controller.h>
6
7#include <memory>
8#include <stdexcept>
9#include <utility>
10#include <vector>
11
12namespace neograph {
13
15class NEOGRAPH_API RuntimeInterpositionConsumer {
16public:
17 virtual ~RuntimeInterpositionConsumer() = default;
18
19 virtual void set_runtime_interposition(
20 std::shared_ptr<RuntimeInterpositionController> controller) {
21 runtime_interposition_ = std::move(controller);
22 }
23
24protected:
25 asio::awaitable<sp::runtime::Result> invoke_provider(
26 std::shared_ptr<Provider> provider,
27 ProviderRequest request,
28 std::vector<sp::Message> host_instructions = {},
29 std::vector<sp::Message> trusted_supplemental = {},
30 std::shared_ptr<graph::ProviderCallBroker> broker = {},
31 graph::ProviderCallIdentity identity = {}) const {
32 // Both mechanisms claim the full dispatch boundary. Bypassing either
33 // silently would discard a host policy or a durable effect receipt.
34 if (broker && runtime_interposition_) {
35 throw std::logic_error("Provider broker conflicts with Strict Runtime interposition");
36 }
37 if (broker) {
38 if (identity.thread_id.empty() || identity.task_id.empty() ||
39 identity.node_name.empty()) {
40 throw std::invalid_argument("Provider broker requires a Core task identity");
41 }
42 return broker->invoke(std::move(identity), std::move(provider),
43 std::move(request));
44 }
45 if (runtime_interposition_) {
46 return runtime_interposition_->invoke_async(
47 std::move(request), std::move(host_instructions),
48 std::move(trusted_supplemental), std::move(identity));
49 }
50 if (identity.model_token_budget == 0 && !identity.managed_budget_lease) {
51 return provider->invoke_async(std::move(request));
52 }
53 return [](std::shared_ptr<Provider> provider, ProviderRequest request,
55 -> asio::awaitable<sp::runtime::Result> {
56 auto prepared = provider->prepare(std::move(request));
57 if (const auto* error = prepared.error()) {
58 co_return std::make_shared<const sp::Outcome>(sp::Failure{*error, {}});
59 }
60 ProviderBudgetClaim claim;
61 try {
62 claim = reserve_provider_dispatch(prepared,
63 ProviderDispatchBudget{identity.usage, identity.model_token_budget,
64 identity.budget_exhausted, identity.budget_cancel_token,
65 identity.managed_budget_lease, identity.managed_budget_store});
66 } catch (const ProviderFailure& failure) {
67 co_return failure.outcome();
68 }
69 co_await claim.begin_managed_effect(
70 prepared, graph::managed_provider_effect_id(identity));
71 claim.mark_dispatched();
72 sp::runtime::Result outcome;
73 std::exception_ptr dispatch_error;
74 try {
75 outcome = co_await provider->dispatch_async(std::move(prepared));
76 } catch (const ProviderOutcomeError& error) {
77 outcome = error.outcome();
78 dispatch_error = std::current_exception();
79 } catch (const ProviderFailure& error) {
80 outcome = error.outcome();
81 dispatch_error = std::current_exception();
82 }
83 try {
84 co_await claim.settle_managed(outcome, dispatch_error);
85 } catch (const ProviderOutcomeError&) {
86 throw;
87 } catch (...) {
88 if (!outcome) throw;
89 throw ProviderBudgetSettlementError(outcome, std::current_exception(), dispatch_error);
90 }
91 if (dispatch_error) std::rethrow_exception(dispatch_error);
92 co_return outcome;
93 }(std::move(provider), std::move(request), std::move(identity));
94 }
95
96private:
97 std::shared_ptr<RuntimeInterpositionController> runtime_interposition_;
98};
99
100} // namespace neograph
How provider stop reasons reach callers.
Definition types.h:391
Post-dispatch host failure retaining the exact drained provider outcome.
Definition provider.h:204
Additive opt-in for built-in provider-calling runtime components.
Host-owned, invocation-scoped boundary for built-in Core provider calls.
Portable request controls remain the SDK's declared, family-specific fields.
Definition provider.h:190