NeoGraph 0.16.0
A C++20 Graph Agent Engine Library — LangGraph for C++
Loading...
Searching...
No Matches
server.h
Go to the documentation of this file.
1
48#pragma once
49
50#include <neograph/api.h>
51#include <neograph/acp/types.h>
52#include <neograph/graph/execution.h>
54
55#include <chrono>
56#include <functional>
57#include <iosfwd>
58#include <memory>
59#include <optional>
60#include <stdexcept>
61#include <string>
62#include <string_view>
63#include <vector>
64
65namespace neograph {
66class Tool;
67}
68
69namespace neograph::acp {
70
71class ACPServer;
72struct ACPServerTestAccess;
73
83struct NEOGRAPH_API ACPSessionContext {
84 std::string session_id;
85 std::string cwd;
86 std::vector<std::string> additional_directories;
88 neograph::json mcp_tools = neograph::json::array();
89};
90
97struct NEOGRAPH_API ACPInterrupt {
98 std::string session_id;
99 std::string node;
100 std::string reason;
101 neograph::json payload;
102 std::string checkpoint_id;
103};
104
107struct NEOGRAPH_API ACPInterruptPermission {
108 ToolCallUpdate tool_call;
109 std::vector<PermissionOption> options;
110};
111
123class NEOGRAPH_API ACPGraphAdapter {
124 public:
125 virtual ~ACPGraphAdapter() = default;
126
128 virtual std::string input_channel() const { return "prompt"; }
129
131 virtual std::string output_channel() const { return "response"; }
132
137 virtual std::string extract_user_text(
138 const std::vector<ContentBlock>& blocks) const;
139
146 virtual neograph::json build_initial_state(
147 const std::vector<ContentBlock>& blocks,
148 const std::string& session_id) const;
149
155 virtual neograph::json build_session_state(
156 const std::vector<ContentBlock>& blocks,
157 const ACPSessionContext& session) const;
158
163 virtual std::string extract_agent_text(
164 const neograph::json& output) const;
165
179 virtual std::optional<ACPInterruptPermission> interrupt_permission(
180 const ACPInterrupt& interrupt) const;
181
184 virtual neograph::json interrupt_resume_value(
185 const ACPInterrupt& interrupt, const std::string& option_id) const;
186};
187
198class NEOGRAPH_API ACPClientError : public std::runtime_error {
199public:
201 ACPClientError(std::string method, const neograph::json& error);
202 ~ACPClientError() override;
203
205 [[nodiscard]] const std::string& method() const noexcept { return method_; }
207 [[nodiscard]] int code() const noexcept { return code_; }
209 [[nodiscard]] const std::string& message() const noexcept { return message_; }
211 [[nodiscard]] const neograph::json& data() const noexcept { return data_; }
212
213private:
214 std::string method_;
215 int code_ = -32603;
216 std::string message_;
217 neograph::json data_;
218};
219
231class NEOGRAPH_API ACPClientRefusal final : public ACPClientError, public ToolRequestRefusal {
232public:
233 using ACPClientError::ACPClientError;
234 ~ACPClientRefusal() override;
235 [[nodiscard]] bool retryable() const noexcept override { return false; }
236};
237
268class NEOGRAPH_API ACPClient {
269 public:
273 std::function<std::shared_ptr<ACPServer>(std::string_view session_id)>;
274
280
282 explicit ACPClient(ACPServer* server);
283
289 explicit ACPClient(ServerResolver resolver);
290
292 void bind(ACPServer* server);
293
296 void bind(ServerResolver resolver);
297
300 bool bound() const noexcept;
301
304 void set_timeout(std::chrono::milliseconds t);
305
309 void set_permission_timeout(std::optional<std::chrono::milliseconds> t);
310
314 std::string read_text_file(std::string_view session_id,
315 std::string_view path,
316 std::optional<int> line = {},
317 std::optional<int> limit = {});
318
321 void write_text_file(std::string_view session_id,
322 std::string_view path,
323 std::string_view content);
324
333 RequestPermissionOutcome request_permission(
334 std::string_view session_id,
335 const ToolCallUpdate& tool_call,
336 const std::vector<PermissionOption>& options);
337
344 std::vector<std::shared_ptr<neograph::Tool>> session_tools(
345 std::string_view session_id) const;
346
347 private:
350 ACPServer* target(std::string_view session_id,
351 std::shared_ptr<ACPServer>& keep,
352 const char* caller) const;
353
354 ACPServer* server_ = nullptr;
355 ServerResolver resolver_;
356 std::chrono::milliseconds timeout_{std::chrono::seconds(30)};
357 std::optional<std::chrono::milliseconds> permission_timeout_;
358};
359
375class NEOGRAPH_API ACPServer {
376 public:
380 using NotificationSink = std::function<void(const neograph::json&)>;
381
390 ACPServer(std::shared_ptr<neograph::graph::GraphEngine> engine,
391 neograph::json info,
392 std::shared_ptr<ACPGraphAdapter> adapter = {});
395 neograph::json info,
396 std::shared_ptr<ACPGraphAdapter> adapter = {});
397
398 ~ACPServer();
399
404 const AgentCapabilities& capabilities() const;
405
416 void run(std::istream& in, std::ostream& out);
417
419 void run();
420
425 bool is_running() const;
426
432 neograph::json handle_message(const neograph::json& envelope);
433
442
472 void stop();
476 void set_max_inflight_prompts(std::size_t limit);
477 bool initialized() const;
478
483 void set_pre_armed_cancel(bool enabled);
484
488 void set_eof_grace(std::chrono::milliseconds grace);
489
492 std::vector<std::shared_ptr<neograph::Tool>> session_tools(
493 std::string_view session_id) const;
494
499 std::shared_ptr<ACPClient> client();
500
505 void attach_client(std::shared_ptr<ACPClient> c);
506
518 neograph::json call_client(std::string method,
519 neograph::json params,
520 std::chrono::milliseconds timeout
521 = std::chrono::seconds(30));
522
523 private:
524 friend struct ACPServerTestAccess;
525
526 // Defined only in test builds. Kept private so the deterministic thread
527 // failure seams are not part of the production ACP API.
528 void fail_next_worker_launch_for_testing();
529 void fail_next_handle_message_for_testing();
530
531 struct Impl;
532 std::unique_ptr<Impl> impl_;
533};
534
535} // namespace neograph::acp
Core data types for the Agent Client Protocol (ACP).
NEOGRAPH_API export/import macro for shared-library builds.
What an exception says when the call it ended is known not to have run: the service that hosts the to...
A JSON-RPC error the client answered to a request of the agent.
Definition server.h:198
const std::string & message() const noexcept
The client's error message; empty when it sent none.
Definition server.h:209
const std::string & method() const noexcept
The method the agent called, such as "fs/read_text_file".
Definition server.h:205
ACPClientError(std::string method, const neograph::json &error)
error is the response's error object.
int code() const noexcept
The JSON-RPC error code; -32603 when the client sent none.
Definition server.h:207
const neograph::json & data() const noexcept
The error's data; null when it had none.
Definition server.h:211
An ACPClientError whose code says the request cannot succeed (#500).
Definition server.h:231
bool retryable() const noexcept override
Whether sending the same request again may succeed.
Definition server.h:235
Agent-side handle for issuing requests back to the editor.
Definition server.h:268
std::vector< std::shared_ptr< neograph::Tool > > session_tools(std::string_view session_id) const
The tools of the session's client-supplied MCP servers (session/new mcpServers), in server order....
ACPClient(ACPServer *server)
Construct a client already bound to server.
bool bound() const noexcept
True once bind has been called with a non-null server, or when the client was made with a resolver.
ACPClient(ServerResolver resolver)
Construct a client for a host that serves several connections, each with its own ACPServer (see ACPHt...
void bind(ACPServer *server)
Late-binding hook — set the back-pointer to the server. Idempotent.
void bind(ServerResolver resolver)
Late-binding hook for a host that serves several connections (see ACPHttpServer::attach_client): rout...
std::function< std::shared_ptr< ACPServer >(std::string_view session_id)> ServerResolver
Finds the ACPServer that serves a session, or an empty pointer when none does.
Definition server.h:273
void write_text_file(std::string_view session_id, std::string_view path, std::string_view content)
Write (create or overwrite) a workspace file via the editor. Throws if not yet bound to a server.
ACPClient()
Construct an unbound client. Bind it to a server later via bind or ACPServer::attach_client....
RequestPermissionOutcome request_permission(std::string_view session_id, const ToolCallUpdate &tool_call, const std::vector< PermissionOption > &options)
Ask the editor to surface a permission prompt for an upcoming tool call. Blocks until the user picks ...
Map between ACP ContentBlock[] and the engine's channels.
Definition server.h:123
virtual neograph::json build_initial_state(const std::vector< ContentBlock > &blocks, const std::string &session_id) const
Build the initial graph state for a turn.
virtual std::optional< ACPInterruptPermission > interrupt_permission(const ACPInterrupt &interrupt) const
Present a NodeInterrupt to the user.
virtual std::string extract_user_text(const std::vector< ContentBlock > &blocks) const
Join the text of every block with single spaces: text blocks verbatim, resource_link as [name](uri),...
virtual std::string input_channel() const
Channel name to write the inbound user text into (default "prompt").
Definition server.h:128
virtual neograph::json interrupt_resume_value(const ACPInterrupt &interrupt, const std::string &option_id) const
The resume value for the option the user selected.
virtual neograph::json build_session_state(const std::vector< ContentBlock > &blocks, const ACPSessionContext &session) const
What the server calls to build a turn's initial state.
virtual std::string extract_agent_text(const neograph::json &output) const
Pull the agent's text reply out of the graph's final state.
virtual std::string output_channel() const
Channel name to read the agent's text reply from (default "response").
Definition server.h:131
HTTP-less, stdio-first ACP server hosting a NeoGraph engine.
Definition server.h:375
void set_max_inflight_prompts(std::size_t limit)
Bound concurrently executing sessions; reject excess prompts before any graph node runs (JSON-RPC -32...
std::function< void(const neograph::json &)> NotificationSink
Sink for agent→client notifications (session/update). Receives the fully-formed JSON-RPC envelope rea...
Definition server.h:380
void run()
Convenience overload — uses std::cin / std::cout.
void set_eof_grace(std::chrono::milliseconds grace)
How long run() lets in-flight prompts finish after its input reaches EOF (the client closed the conne...
neograph::json handle_message(const neograph::json &envelope)
Process exactly one parsed JSON-RPC envelope. Returns:
neograph::json call_client(std::string method, neograph::json params, std::chrono::milliseconds timeout=std::chrono::seconds(30))
Issue a JSON-RPC request to the connected client and block until a response arrives....
std::vector< std::shared_ptr< neograph::Tool > > session_tools(std::string_view session_id) const
The tools of a session's client-supplied MCP servers; see ACPClient::session_tools.
bool is_running() const
True while run() is actively reading from its input stream. Set on entry, cleared on exit....
AgentCapabilities & capabilities()
Mutable access to the capabilities advertised in initialize. Defaults: session.resume=true,...
void run(std::istream &in, std::ostream &out)
Drive the server loop reading newline-delimited JSON-RPC envelopes from in and writing them to out....
std::shared_ptr< ACPClient > client()
Handle for issuing agent→client requests (fs/*, etc.). On first call lazily creates a client bound to...
void set_pre_armed_cancel(bool enabled)
Opt in to the pre-armed cancel: a session/cancel received after session/new but before the session's ...
void set_notification_sink(NotificationSink sink)
Where session/update notifications go. Default: dropped on the floor (test-friendly)....
void attach_client(std::shared_ptr< ACPClient > c)
Install a pre-constructed client and bind it to this server. Useful when the engine's nodes captured ...
ACPServer(std::shared_ptr< neograph::graph::GraphEngine > engine, neograph::json info, std::shared_ptr< ACPGraphAdapter > adapter={})
void stop()
Signal a running run() loop to exit at the next message boundary.
ACPServer(neograph::graph::GraphExecution execution, neograph::json info, std::shared_ptr< ACPGraphAdapter > adapter={})
Preferred constructor: restrict the host to graph execution.
Owning, concrete execution capability for protocol hosts.
Definition execution.h:18
The session/request_permission request that asks the user about an interrupt (see ACPGraphAdapter::in...
Definition server.h:107
A NodeInterrupt raised during a prompt turn.
Definition server.h:97
What a prompt turn knows about its session.
Definition server.h:83
Capabilities advertised in InitializeResponse.
Definition types.h:75
Resource-aware, coroutine-safe execution boundary for tools.