NeoGraph 0.16.0
A C++20 Graph Agent Engine Library — LangGraph for C++
Loading...
Searching...
No Matches
task_graph_fragment.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <neograph/api.h>
17
18#include <functional>
19#include <asio/awaitable.hpp>
20
21#include <cstdint>
22#include <memory>
23#include <optional>
24#include <string>
25#include <string_view>
26#include <vector>
27
28namespace neograph::program {
29
31struct NEOGRAPH_PROGRAM_API TaskGraphTemplateReceipt {
32 std::string template_id;
33 std::string content_identity;
34 std::string child_binding;
35 std::string executable_identity;
36 std::string kind;
37 std::vector<std::string> capabilities;
38 std::vector<std::string> effects;
39 std::vector<std::string> input_fields;
40 std::vector<TaskGraphArtifactContract> output_artifacts;
41
42 bool operator==(const TaskGraphTemplateReceipt&) const = default;
43};
44
46struct NEOGRAPH_PROGRAM_API CompiledTaskGraphTask {
47 std::string task_id;
48 std::string operation_id;
49 std::string template_id;
50 std::string template_identity;
51 std::string child_binding;
52 std::vector<TaskGraphInputBinding> input_bindings;
53 std::vector<std::string> depends_on;
54 TaskGraphBudget requested_budget;
55 TaskGraphBudget reserved_budget;
56 std::vector<std::string> capabilities;
57 std::vector<std::string> effects;
58 std::vector<std::string> input_fields;
59 std::vector<TaskGraphArtifactContract> output_artifacts;
62 std::vector<TaskGraphInputLiteral> input_literals;
65 std::uint32_t max_attempts = 1;
66
67 bool operator==(const CompiledTaskGraphTask&) const = default;
68};
69
75class NEOGRAPH_PROGRAM_API CompiledTaskGraphFragment final {
76public:
78 static constexpr std::uint32_t SCHEMA_VERSION = 1;
81 static constexpr std::uint32_t SCHEMA_VERSION_2 = 2;
82
84 CompiledTaskGraphFragment& operator=(const CompiledTaskGraphFragment&) = default;
86 CompiledTaskGraphFragment& operator=(CompiledTaskGraphFragment&&) noexcept = default;
88
89 static CompiledTaskGraphFragment parse(std::string_view stored_bytes);
90
91 std::uint32_t schema_version() const noexcept;
92 const std::string& fragment_id() const noexcept;
93 const std::string& owner_scope() const noexcept;
94 const std::string& parent_run_id() const noexcept;
95 const std::string& expansion_operation_id() const noexcept;
96 const std::string& parent_program_version_id() const noexcept;
97 std::uint32_t child_depth() const noexcept;
98 const std::string& proposal_hash() const noexcept;
99 const std::vector<CompiledTaskGraphTask>& tasks() const noexcept;
100 const TaskGraphJoinPolicy& join() const noexcept;
101 const TaskGraphBudget& aggregate_budget() const noexcept;
102 const std::vector<TaskGraphTemplateReceipt>& template_receipts() const noexcept;
103 const std::vector<std::string>& capability_effect_closure() const noexcept;
104 const std::vector<SourceMapEntry>& source_map() const noexcept;
105
107 json to_json() const;
108 const std::string& serialize_canonical() const noexcept;
109 bool operator==(const CompiledTaskGraphFragment& other) const noexcept;
110
111private:
112 struct Impl;
113 explicit CompiledTaskGraphFragment(std::shared_ptr<const Impl> impl);
114 std::shared_ptr<const Impl> impl_;
115
116 friend class TaskGraphFragmentCompiler;
117};
118
120enum class TaskGraphTaskState : std::uint8_t {
121 Pending,
122 Active,
123 Completed,
124 Failed,
125 Cancelled,
126};
127
128NEOGRAPH_PROGRAM_API std::string_view to_string(TaskGraphTaskState state) noexcept;
129NEOGRAPH_PROGRAM_API TaskGraphTaskState task_graph_task_state_from_string(std::string_view value);
130
132struct NEOGRAPH_PROGRAM_API TaskGraphTaskRecord {
133 std::string task_id;
134 std::string operation_id;
135 TaskGraphTaskState state = TaskGraphTaskState::Pending;
136 std::uint32_t attempt = 0;
137 std::optional<json> output;
138 std::optional<json> failure;
140 std::string attempt_identity;
142 std::optional<std::string> child_run_id;
143
144 bool operator==(const TaskGraphTaskRecord&) const = default;
145};
146
147struct NEOGRAPH_PROGRAM_API TaskGraphFragmentRecord {
148 static constexpr std::uint32_t STORAGE_SCHEMA_VERSION = 1;
149
151 std::vector<TaskGraphTaskRecord> tasks;
152 std::uint64_t revision = 0;
153 bool published = false;
154 bool terminal = false;
155
156 static TaskGraphFragmentRecord parse(std::string_view stored_bytes);
157 json to_json() const;
158 std::string serialize_canonical() const;
159
160 bool operator==(const TaskGraphFragmentRecord&) const = default;
161};
162
164enum class TaskGraphPublishResult : std::uint8_t {
165 Published,
166 AlreadyPresent,
167 Conflict,
168 Missing,
169};
170
171NEOGRAPH_PROGRAM_API std::string_view to_string(TaskGraphPublishResult result) noexcept;
172
178class NEOGRAPH_PROGRAM_API TaskGraphFragmentStore {
179public:
180 virtual ~TaskGraphFragmentStore() = default;
181
182 [[nodiscard]] virtual asio::awaitable<TaskGraphPublishResult> publish(const TaskGraphFragmentRecord& record) = 0;
183 [[nodiscard]] virtual asio::awaitable<std::optional<TaskGraphFragmentRecord>> load(
184 std::string_view fragment_id) const = 0;
193 [[nodiscard]] virtual asio::awaitable<std::optional<TaskGraphFragmentRecord>> find_published_lineage(
194 std::string_view owner_scope,
195 std::string_view parent_run_id,
196 std::string_view expansion_operation_id) const {
197 (void)owner_scope;
198 (void)parent_run_id;
199 (void)expansion_operation_id;
200 co_return std::nullopt;
201 }
209 [[nodiscard]] virtual asio::awaitable<std::optional<TaskGraphFragmentRecord>> find_published(
210 std::string_view owner_scope,
211 std::string_view parent_run_id,
212 std::string_view expansion_operation_id,
213 std::string_view proposal_hash) const {
214 (void)owner_scope;
215 (void)parent_run_id;
216 (void)expansion_operation_id;
217 (void)proposal_hash;
218 co_return std::nullopt;
219 }
220 [[nodiscard]] virtual asio::awaitable<TaskGraphPublishResult> compare_update(
221 std::string_view fragment_id,
222 std::uint64_t expected_revision,
223 const TaskGraphFragmentRecord& record) = 0;
224};
225
230class NEOGRAPH_PROGRAM_API SyncTaskGraphFragmentStore : public TaskGraphFragmentStore {
231public:
232 // The synchronous operations. Each has the contract of the awaitable operation of the same name.
233 virtual TaskGraphPublishResult publish_sync(const TaskGraphFragmentRecord& record) = 0;
234 virtual std::optional<TaskGraphFragmentRecord> load_sync(std::string_view fragment_id) const = 0;
235 virtual std::optional<TaskGraphFragmentRecord> find_published_lineage_sync(
236 std::string_view owner_scope,
237 std::string_view parent_run_id,
238 std::string_view expansion_operation_id) const {
239 (void)owner_scope;
240 (void)parent_run_id;
241 (void)expansion_operation_id;
242 return std::nullopt;
243 }
244 virtual std::optional<TaskGraphFragmentRecord> find_published_sync(
245 std::string_view owner_scope,
246 std::string_view parent_run_id,
247 std::string_view expansion_operation_id,
248 std::string_view proposal_hash) const {
249 (void)owner_scope;
250 (void)parent_run_id;
251 (void)expansion_operation_id;
252 (void)proposal_hash;
253 return std::nullopt;
254 }
255 virtual TaskGraphPublishResult compare_update_sync(
256 std::string_view fragment_id,
257 std::uint64_t expected_revision,
258 const TaskGraphFragmentRecord& record) = 0;
259
260 // The awaitable interface, completed by the operations above: at once on the calling thread,
261 // or on a thread of a bounded pool when offloads() is true.
262 [[nodiscard]] asio::awaitable<TaskGraphPublishResult> publish(const TaskGraphFragmentRecord& record) final;
263 [[nodiscard]] asio::awaitable<std::optional<TaskGraphFragmentRecord>> load(
264 std::string_view fragment_id) const final;
265 [[nodiscard]] asio::awaitable<std::optional<TaskGraphFragmentRecord>> find_published_lineage(
266 std::string_view owner_scope,
267 std::string_view parent_run_id,
268 std::string_view expansion_operation_id) const final;
269 [[nodiscard]] asio::awaitable<std::optional<TaskGraphFragmentRecord>> find_published(
270 std::string_view owner_scope,
271 std::string_view parent_run_id,
272 std::string_view expansion_operation_id,
273 std::string_view proposal_hash) const final;
274 [[nodiscard]] asio::awaitable<TaskGraphPublishResult> compare_update(
275 std::string_view fragment_id,
276 std::uint64_t expected_revision,
277 const TaskGraphFragmentRecord& record) final;
278
280 bool completes_at_once() const noexcept { return !offloads(); }
281
282protected:
284 virtual bool offloads() const noexcept { return false; }
285};
286
291class NEOGRAPH_PROGRAM_API BlockingTaskGraphFragmentStore {
292public:
293 BlockingTaskGraphFragmentStore(std::shared_ptr<TaskGraphFragmentStore> store, BlockingStorePolicy policy = {});
296
297 const std::shared_ptr<TaskGraphFragmentStore>& store() const noexcept { return store_; }
298
299 TaskGraphPublishResult publish(const TaskGraphFragmentRecord& record) const;
300 std::optional<TaskGraphFragmentRecord> load(std::string_view fragment_id) const;
301 std::optional<TaskGraphFragmentRecord> find_published_lineage(
302 std::string_view owner_scope,
303 std::string_view parent_run_id,
304 std::string_view expansion_operation_id) const;
305 std::optional<TaskGraphFragmentRecord> find_published(
306 std::string_view owner_scope,
307 std::string_view parent_run_id,
308 std::string_view expansion_operation_id,
309 std::string_view proposal_hash) const;
310 TaskGraphPublishResult compare_update(
311 std::string_view fragment_id,
312 std::uint64_t expected_revision,
313 const TaskGraphFragmentRecord& record) const;
314
315private:
316 std::shared_ptr<TaskGraphFragmentStore> store_;
317 SyncTaskGraphFragmentStore* sync_ = nullptr;
318 BlockingStorePolicy policy_;
319};
320
322struct NEOGRAPH_PROGRAM_API TaskGraphFragmentCompileOptions {
323 std::string owner_scope;
324 std::string parent_run_id;
325 std::string expansion_operation_id;
326 std::string parent_program_version_id;
327 std::uint32_t child_depth = 0;
328 BudgetLimits remaining_budget;
330 std::vector<TaskGraphTemplateContract> template_allowlist;
331 std::vector<std::string> parent_capabilities;
332 std::vector<std::string> parent_effects;
333 std::vector<std::string> host_capabilities;
334 std::vector<std::string> host_effects;
335};
336
338struct NEOGRAPH_PROGRAM_API TaskGraphExpansionPolicy {
340 std::vector<TaskGraphTemplateContract> template_allowlist;
341 std::vector<std::string> host_capabilities;
342 std::vector<std::string> host_effects;
343
344 bool operator==(const TaskGraphExpansionPolicy&) const = default;
345};
346
347using TaskGraphExpansionPolicyResolver =
348 std::function<std::optional<TaskGraphExpansionPolicy>(
349 std::string_view owner_scope,
350 std::string_view parent_program_version_id,
351 std::string_view expansion_operation_id)>;
352
354class NEOGRAPH_PROGRAM_API TaskGraphFragmentCompiler final {
355public:
356 static CompiledTaskGraphFragment compile(
357 const TaskGraphProposal& proposal,
358 const TaskGraphFragmentCompileOptions& options);
359
360 static CompiledTaskGraphFragment compile(
361 const json& proposal,
362 TaskGraphProposalOptions proposal_options,
363 const TaskGraphFragmentCompileOptions& options);
364};
365
367class NEOGRAPH_PROGRAM_API InMemoryTaskGraphFragmentStore final : public SyncTaskGraphFragmentStore {
368public:
375
376 TaskGraphPublishResult publish_sync(const TaskGraphFragmentRecord& record) override;
377 std::optional<TaskGraphFragmentRecord> load_sync(std::string_view fragment_id) const override;
378 std::optional<TaskGraphFragmentRecord> find_published_lineage_sync(
379 std::string_view owner_scope,
380 std::string_view parent_run_id,
381 std::string_view expansion_operation_id) const override;
382 std::optional<TaskGraphFragmentRecord> find_published_sync(
383 std::string_view owner_scope,
384 std::string_view parent_run_id,
385 std::string_view expansion_operation_id,
386 std::string_view proposal_hash) const override;
387 TaskGraphPublishResult compare_update_sync(
388 std::string_view fragment_id, std::uint64_t expected_revision,
389 const TaskGraphFragmentRecord& record) override;
390
391private:
392 struct Impl;
393 std::unique_ptr<Impl> impl_;
394};
395
396} // namespace neograph::program
Immutable Program admission and policy snapshots.
NEOGRAPH_API export/import macro for shared-library builds.
A TaskGraphFragmentStore for a caller that cannot suspend.
BlockingTaskGraphFragmentStore(TaskGraphFragmentStore &store, BlockingStorePolicy policy={})
A view of a store that outlives it.
Small deterministic store used by tests and embedded hosts.
Base of a TaskGraphFragmentStore whose backend is synchronous.
bool completes_at_once() const noexcept
True when every awaitable operation completes at once on the calling thread, not on a pool thread.
asio::awaitable< std::optional< TaskGraphFragmentRecord > > find_published_lineage(std::string_view owner_scope, std::string_view parent_run_id, std::string_view expansion_operation_id) const final
Locate the published expansion for one immutable parent operation.
virtual bool offloads() const noexcept
True for a backend that blocks for long: each operation then runs on a pool thread.
asio::awaitable< std::optional< TaskGraphFragmentRecord > > find_published(std::string_view owner_scope, std::string_view parent_run_id, std::string_view expansion_operation_id, std::string_view proposal_hash) const final
Locate an already published expansion by immutable parent lineage and proposal identity.
Pure compiler from untrusted proposal data to an immutable typed fragment.
Host-owned durable store boundary for compiled fragments and task state.
virtual asio::awaitable< std::optional< TaskGraphFragmentRecord > > find_published_lineage(std::string_view owner_scope, std::string_view parent_run_id, std::string_view expansion_operation_id) const
Locate the published expansion for one immutable parent operation.
virtual asio::awaitable< std::optional< TaskGraphFragmentRecord > > find_published(std::string_view owner_scope, std::string_view parent_run_id, std::string_view expansion_operation_id, std::string_view proposal_hash) const
Locate an already published expansion by immutable parent lineage and proposal identity.
Deeply owned canonical TaskGraphProposal.
How a Program store call is awaited, and how a synchronous caller waits for one (#556).
When a Blocking...Store may wait for a store call that does not complete at once.
Definition store_call.h:39
A stable operation identity and all typed edges for one dynamic task.
std::vector< TaskGraphInputLiteral > input_literals
Schema-2 fragments: JSON values assigned to input fields of each attempt's child input,...
Requested resource budget for one proposed task or a proposal ceiling.
Host-owned policy facts used to admit one dynamic task-graph expansion.
Trusted, host-owned inputs to deterministic proposal lowering.
v1 intentionally supports only all-of joins; additional policies need their own contract.
Finite structural and resource ceilings enforced before a proposal is usable.
Trusted parsing context for one proposal artifact.
Typed task result; artifact values are data, never authority.
std::optional< std::string > child_run_id
Durable child lineage, populated before the child result is joined.
std::string attempt_identity
Stable identity for this bounded dispatch attempt.
Immutable trusted facts for one template selected by a proposal.
TaskGraphPublishResult
Result of a compare-and-publish/update operation.
TaskGraphTaskState
Durable state of one published task.
Immutable, non-executable TaskGraphProposal-v1 values.