Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ add_library(copilot_sdk_cpp
include/copilot/process.hpp
include/copilot/client.hpp
include/copilot/session.hpp
include/copilot/rpc_methods.hpp
include/copilot/rpc_types.hpp
# Sources
src/types.cpp
src/events.cpp
Expand Down
10 changes: 10 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,13 @@ set_target_properties(user_input PROPERTIES FOLDER "Examples")
add_executable(reasoning_effort reasoning_effort.cpp)
target_link_libraries(reasoning_effort PRIVATE copilot_sdk_cpp)
set_target_properties(reasoning_effort PROPERTIES FOLDER "Examples")

# Instruction directories example (v0.1.49 - PR #1190)
add_executable(instruction_directories instruction_directories.cpp)
target_link_libraries(instruction_directories PRIVATE copilot_sdk_cpp)
set_target_properties(instruction_directories PROPERTIES FOLDER "Examples")

# Remote session example (v0.1.49 - PR #1295, Mission Control integration)
add_executable(remote_session remote_session.cpp)
target_link_libraries(remote_session PRIVATE copilot_sdk_cpp)
set_target_properties(remote_session PROPERTIES FOLDER "Examples")
55 changes: 55 additions & 0 deletions examples/instruction_directories.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2025 Elias Bachaalany
// SPDX-License-Identifier: MIT

/// @file instruction_directories.cpp
/// @brief Compile-only demo for the v0.1.49 `instructionDirectories` field on
/// `SessionConfig` and `ResumeSessionConfig`.
///
/// Builds a `SessionConfig` populated with per-session instruction directories
/// and dumps the resulting `session.create` request payload that the SDK would
/// send to the Copilot CLI. No network or CLI is required: this example
/// exercises the public `build_session_create_request` helper so the API is
/// exercised at build time and the JSON envelope is human-inspectable.
///
/// Background: instructionDirectories (upstream nodejs PR #1190) lets a host
/// application supplement the global instruction set with additional
/// directories scoped to a single session — useful for ephemeral or
/// workspace-specific guidance without mutating the user's CLI config.

#include <copilot/copilot.hpp>

#include <iostream>

int main()
{
using namespace copilot;

SessionConfig cfg;
cfg.client_name = "instruction-dirs-demo";
cfg.instruction_directories = std::vector<std::string>{
"/etc/copilot/instructions",
"./workspace/.copilot/instructions",
};
cfg.enable_config_discovery = true;
cfg.streaming = false;

json request = build_session_create_request(cfg);

std::cout << "session.create request payload:\n";
std::cout << request.dump(2) << "\n";

// Sanity-check the fields actually round-tripped through the builder.
if (!request.contains("instructionDirectories") ||
!request["instructionDirectories"].is_array() ||
request["instructionDirectories"].size() != 2)
{
std::cerr << "instructionDirectories field missing or malformed\n";
return 1;
}
if (request.value("clientName", std::string{}) != "instruction-dirs-demo")
{
std::cerr << "clientName missing\n";
return 1;
}
return 0;
}
72 changes: 72 additions & 0 deletions examples/remote_session.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2025 Elias Bachaalany
// SPDX-License-Identifier: MIT

/// @file remote_session.cpp
/// @brief Compile-only demo for the v0.1.49 `remoteSession` field on
/// `SessionConfig` (Mission Control integration, upstream nodejs PR #1295).
///
/// Demonstrates the three `RemoteSessionMode` values and shows how the
/// resulting `session.create` payload differs. No live Copilot CLI is
/// required: the example uses the public `build_session_create_request`
/// helper to render each request payload for inspection.
///
/// Remote-session modes (matches upstream nodejs):
/// * `Off` — explicitly disable remote steering for this session.
/// * `Export` — export this session so it shows up in Mission Control
/// without accepting remote commands.
/// * `On` — enable full remote steering from GitHub web / mobile.

#include <copilot/copilot.hpp>

#include <iostream>
#include <string>
#include <vector>

namespace
{

const char* mode_name(copilot::RemoteSessionMode mode)
{
using copilot::RemoteSessionMode;
switch (mode)
{
case RemoteSessionMode::Off: return "off";
case RemoteSessionMode::Export: return "export";
case RemoteSessionMode::On: return "on";
}
return "?";
}

} // namespace

int main()
{
using namespace copilot;

const std::vector<RemoteSessionMode> modes = {
RemoteSessionMode::Off,
RemoteSessionMode::Export,
RemoteSessionMode::On,
};

for (auto mode : modes)
{
SessionConfig cfg;
cfg.client_name = "remote-session-demo";
cfg.remote_session = mode;
cfg.enable_session_telemetry = (mode != RemoteSessionMode::Off);

json request = build_session_create_request(cfg);

std::cout << "[mode=" << mode_name(mode) << "] session.create payload:\n";
std::cout << request.dump(2) << "\n\n";

if (!request.contains("remoteSession"))
{
std::cerr << "remoteSession field missing for mode " << mode_name(mode) << "\n";
return 1;
}
}

return 0;
}
53 changes: 53 additions & 0 deletions include/copilot/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ json build_session_create_request(const SessionConfig& config);
/// @return JSON object ready to send to server
json build_session_resume_request(const std::string& session_id, const ResumeSessionConfig& config);

/// Build the CLI argument vector that {@link Client} will pass to the spawned
/// Copilot CLI process, given a fully-populated {@link ClientOptions}.
/// Exposed for conformance unit testing of process-launch behavior. Mirrors
/// what `start_cli_server()` emits before command resolution (i.e. no Node /
/// `cmd /c` wrapping is applied).
/// @param options Client options
/// @return Argument list (does not include the executable itself)
std::vector<std::string> build_cli_command_args(const ClientOptions& options);

/// Build the environment-variable map that {@link Client} will use when
/// spawning the Copilot CLI process. The returned map reflects the SDK's
/// additions and removals (COPILOT_HOME, COPILOT_CONNECTION_TOKEN,
/// COPILOT_SDK_AUTH_TOKEN, NODE_DEBUG erase) layered on top of the explicit
/// `options.environment`. Exposed for conformance unit testing.
/// @param options Client options
/// @return Environment map ready for ProcessOptions::environment
std::map<std::string, std::string> build_cli_environment(const ClientOptions& options);

// =============================================================================
// CopilotClient - Main client class
// =============================================================================
Expand Down Expand Up @@ -126,6 +144,17 @@ class Client
/// @return Future that resolves to list of session metadata
std::future<std::vector<SessionMetadata>> list_sessions();

/// List sessions matching a filter (matches upstream nodejs SDK).
/// @param filter Filter criteria (cwd / git_root / repository / branch)
/// @return Future that resolves to list of matching session metadata
std::future<std::vector<SessionMetadata>> list_sessions(SessionListFilter filter);

/// Get metadata for a specific session by ID (O(1) lookup).
/// @param session_id ID of the session
/// @return Future that resolves to metadata, or nullopt if not found
std::future<std::optional<SessionMetadata>>
get_session_metadata(const std::string& session_id);

/// Delete a session
/// @param session_id ID of the session to delete
/// @return Future that completes when deleted
Expand Down Expand Up @@ -157,6 +186,18 @@ class Client
/// @throws Error if not authenticated
std::future<std::vector<ModelInfo>> list_models();

/// Provide a custom handler for listing available models (BYOK mode).
/// When set, Client::list_models() calls this handler instead of querying
/// the CLI server. Results are still cached after the first successful call;
/// pass nullptr to revert to default RPC-based behavior. Matches upstream
/// nodejs CopilotClientOptions.onListModels.
using ListModelsHandler = std::function<std::vector<ModelInfo>()>;
void set_on_list_models(ListModelsHandler handler);

/// Get the negotiated protocol version (set after successful start()).
/// Returns std::nullopt before connection is established.
std::optional<int> negotiated_protocol_version() const;

// =========================================================================
// Lifecycle Events
// =========================================================================
Expand Down Expand Up @@ -217,6 +258,10 @@ class Client
/// Handle incoming user input requests
json handle_user_input_request(const json& params);

json handle_elicitation_request(const json& params);
json handle_exit_plan_mode_request(const json& params);
json handle_auto_mode_switch_request(const json& params);

/// Handle incoming hook invocations
json handle_hooks_invoke(const json& params);

Expand All @@ -241,9 +286,17 @@ class Client
mutable std::mutex models_cache_mutex_;
std::optional<std::vector<ModelInfo>> models_cache_;

// BYOK: optional custom models handler (when set, takes precedence over RPC).
mutable std::mutex on_list_models_mutex_;
ListModelsHandler on_list_models_;

// Lifecycle handlers
mutable std::mutex lifecycle_mutex_;
std::vector<LifecycleHandler> lifecycle_handlers_;

// Protocol version negotiation result (set after verify_protocol_version()).
mutable std::mutex protocol_version_mutex_;
std::optional<int> negotiated_protocol_version_;
};

} // namespace copilot
2 changes: 2 additions & 0 deletions include/copilot/copilot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <copilot/events.hpp>
#include <copilot/jsonrpc.hpp>
#include <copilot/process.hpp>
#include <copilot/rpc_methods.hpp>
#include <copilot/rpc_types.hpp>
#include <copilot/session.hpp>
#include <copilot/tool_builder.hpp>
#include <copilot/transport.hpp>
Expand Down
Loading
Loading