Skip to content

Commit a7d699e

Browse files
committed
feat(types): close type-surface parity gaps with upstream .NET SDK
Add missing enums, types, and fields to match upstream Types.cs: - SectionOverrideAction enum (5 variants) - SectionOverride struct (action + content) - McpHttpServerConfigOauthGrantType enum (2 variants) - SystemMessageMode::Customize variant - DefaultAgentConfig struct (excludedTools) - SystemMessageConfig.sections field - ProviderConfig: headers, modelId, wireModel, maxPromptTokens, maxOutputTokens - SessionConfig: commands, defaultAgent, agent, modelCapabilities, githubToken - ResumeSessionConfig: commands, defaultAgent, agent, modelCapabilities - MessageOptions: requestHeaders Callback handlers (OnElicitationRequest, OnExitPlanMode, etc.) deferred. Tests: 437/437 passing (8 new parity tests added)
1 parent 8e43019 commit a7d699e

4 files changed

Lines changed: 331 additions & 30 deletions

File tree

‎include/copilot/types.hpp‎

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,25 @@ enum class ConnectionState
5757
enum class SystemMessageMode
5858
{
5959
Append,
60-
Replace
60+
Replace,
61+
Customize
62+
};
63+
64+
/// Section override action for system message customization
65+
enum class SectionOverrideAction
66+
{
67+
Replace,
68+
Remove,
69+
Append,
70+
Prepend,
71+
Transform
72+
};
73+
74+
/// OAuth grant type for an MCP HTTP server
75+
enum class McpHttpServerConfigOauthGrantType
76+
{
77+
AuthorizationCode,
78+
ClientCredentials
6179
};
6280

6381
// JSON enum serialization
@@ -76,6 +94,26 @@ NLOHMANN_JSON_SERIALIZE_ENUM(
7694
{
7795
{SystemMessageMode::Append, "append"},
7896
{SystemMessageMode::Replace, "replace"},
97+
{SystemMessageMode::Customize, "customize"},
98+
}
99+
)
100+
101+
NLOHMANN_JSON_SERIALIZE_ENUM(
102+
SectionOverrideAction,
103+
{
104+
{SectionOverrideAction::Replace, "replace"},
105+
{SectionOverrideAction::Remove, "remove"},
106+
{SectionOverrideAction::Append, "append"},
107+
{SectionOverrideAction::Prepend, "prepend"},
108+
{SectionOverrideAction::Transform, "transform"},
109+
}
110+
)
111+
112+
NLOHMANN_JSON_SERIALIZE_ENUM(
113+
McpHttpServerConfigOauthGrantType,
114+
{
115+
{McpHttpServerConfigOauthGrantType::AuthorizationCode, "authorization_code"},
116+
{McpHttpServerConfigOauthGrantType::ClientCredentials, "client_credentials"},
79117
}
80118
)
81119

@@ -595,11 +633,34 @@ struct SessionHooks
595633
// Configuration Types
596634
// =============================================================================
597635

636+
/// Override operation for a single system prompt section
637+
struct SectionOverride
638+
{
639+
SectionOverrideAction action = SectionOverrideAction::Replace;
640+
std::optional<std::string> content;
641+
};
642+
643+
inline void to_json(json& j, const SectionOverride& c)
644+
{
645+
j = json{{"action", c.action}};
646+
if (c.content)
647+
j["content"] = *c.content;
648+
}
649+
650+
inline void from_json(const json& j, SectionOverride& c)
651+
{
652+
if (j.contains("action"))
653+
c.action = j.at("action").get<SectionOverrideAction>();
654+
if (j.contains("content"))
655+
c.content = j.at("content").get<std::string>();
656+
}
657+
598658
/// System message configuration
599659
struct SystemMessageConfig
600660
{
601661
std::optional<SystemMessageMode> mode;
602662
std::optional<std::string> content;
663+
std::optional<std::map<std::string, SectionOverride>> sections;
603664
};
604665

605666
inline void to_json(json& j, const SystemMessageConfig& c)
@@ -609,6 +670,8 @@ inline void to_json(json& j, const SystemMessageConfig& c)
609670
j["mode"] = *c.mode;
610671
if (c.content)
611672
j["content"] = *c.content;
673+
if (c.sections)
674+
j["sections"] = *c.sections;
612675
}
613676

614677
inline void from_json(const json& j, SystemMessageConfig& c)
@@ -617,6 +680,8 @@ inline void from_json(const json& j, SystemMessageConfig& c)
617680
c.mode = j.at("mode").get<SystemMessageMode>();
618681
if (j.contains("content"))
619682
c.content = j.at("content").get<std::string>();
683+
if (j.contains("sections"))
684+
c.sections = j.at("sections").get<std::map<std::string, SectionOverride>>();
620685
}
621686

622687
/// Azure-specific provider options
@@ -647,6 +712,11 @@ struct ProviderConfig
647712
std::optional<std::string> api_key;
648713
std::optional<std::string> bearer_token;
649714
std::optional<AzureOptions> azure;
715+
std::optional<std::map<std::string, std::string>> headers;
716+
std::optional<std::string> model_id;
717+
std::optional<std::string> wire_model;
718+
std::optional<int> max_input_tokens;
719+
std::optional<int> max_output_tokens;
650720

651721
// ─────────────────────────────────────────────────────────────────────────
652722
// Environment Variable Support
@@ -717,6 +787,16 @@ inline void to_json(json& j, const ProviderConfig& c)
717787
j["bearerToken"] = *c.bearer_token;
718788
if (c.azure)
719789
j["azure"] = *c.azure;
790+
if (c.headers)
791+
j["headers"] = *c.headers;
792+
if (c.model_id)
793+
j["modelId"] = *c.model_id;
794+
if (c.wire_model)
795+
j["wireModel"] = *c.wire_model;
796+
if (c.max_input_tokens)
797+
j["maxPromptTokens"] = *c.max_input_tokens;
798+
if (c.max_output_tokens)
799+
j["maxOutputTokens"] = *c.max_output_tokens;
720800
}
721801

722802
inline void from_json(const json& j, ProviderConfig& c)
@@ -732,6 +812,16 @@ inline void from_json(const json& j, ProviderConfig& c)
732812
c.bearer_token = j.at("bearerToken").get<std::string>();
733813
if (j.contains("azure"))
734814
c.azure = j.at("azure").get<AzureOptions>();
815+
if (j.contains("headers"))
816+
c.headers = j.at("headers").get<std::map<std::string, std::string>>();
817+
if (j.contains("modelId"))
818+
c.model_id = j.at("modelId").get<std::string>();
819+
if (j.contains("wireModel"))
820+
c.wire_model = j.at("wireModel").get<std::string>();
821+
if (j.contains("maxPromptTokens"))
822+
c.max_input_tokens = j.at("maxPromptTokens").get<int>();
823+
if (j.contains("maxOutputTokens"))
824+
c.max_output_tokens = j.at("maxOutputTokens").get<int>();
735825
}
736826

737827
// =============================================================================
@@ -871,6 +961,24 @@ inline void from_json(const json& j, CustomAgentConfig& c)
871961
c.model = j.at("model").get<std::string>();
872962
}
873963

964+
struct DefaultAgentConfig
965+
{
966+
std::optional<std::vector<std::string>> excluded_tools;
967+
};
968+
969+
inline void to_json(json& j, const DefaultAgentConfig& c)
970+
{
971+
j = json::object();
972+
if (c.excluded_tools)
973+
j["excludedTools"] = *c.excluded_tools;
974+
}
975+
976+
inline void from_json(const json& j, DefaultAgentConfig& c)
977+
{
978+
if (j.contains("excludedTools"))
979+
c.excluded_tools = j.at("excludedTools").get<std::vector<std::string>>();
980+
}
981+
874982
// =============================================================================
875983
// Attachment Types (for MessageOptions)
876984
// =============================================================================
@@ -1004,7 +1112,9 @@ struct SessionConfig
10041112
{
10051113
std::optional<std::string> session_id;
10061114
std::optional<std::string> model;
1115+
std::optional<json> model_capabilities;
10071116
std::vector<Tool> tools;
1117+
std::optional<std::vector<json>> commands;
10081118
std::optional<SystemMessageConfig> system_message;
10091119
std::optional<std::vector<std::string>> available_tools;
10101120
std::optional<std::vector<std::string>> excluded_tools;
@@ -1013,6 +1123,8 @@ struct SessionConfig
10131123
bool streaming = false;
10141124
std::optional<std::map<std::string, json>> mcp_servers;
10151125
std::optional<std::vector<CustomAgentConfig>> custom_agents;
1126+
std::optional<DefaultAgentConfig> default_agent;
1127+
std::optional<std::string> agent;
10161128

10171129
/// Directories to load skills from.
10181130
std::optional<std::vector<std::string>> skill_directories;
@@ -1044,6 +1156,9 @@ struct SessionConfig
10441156
/// Working directory for the session.
10451157
std::optional<std::string> working_directory;
10461158

1159+
/// GitHub token for per-session authentication.
1160+
std::optional<std::string> github_token;
1161+
10471162
// ===== v0.1.49 additions =====
10481163

10491164
/// Client identifier reported to the CLI (PR #510).
@@ -1075,6 +1190,8 @@ struct ResumeSessionConfig
10751190
bool streaming = false;
10761191
std::optional<std::map<std::string, json>> mcp_servers;
10771192
std::optional<std::vector<CustomAgentConfig>> custom_agents;
1193+
std::optional<DefaultAgentConfig> default_agent;
1194+
std::optional<std::string> agent;
10781195

10791196
/// Directories to load skills from.
10801197
std::optional<std::vector<std::string>> skill_directories;
@@ -1092,10 +1209,13 @@ struct ResumeSessionConfig
10921209

10931210
/// Model to use for this session. Can change the model when resuming.
10941211
std::optional<std::string> model;
1212+
std::optional<json> model_capabilities;
10951213

10961214
/// Reasoning effort level for models that support it.
10971215
std::optional<ReasoningEffort> reasoning_effort;
10981216

1217+
std::optional<std::vector<json>> commands;
1218+
10991219
/// System message configuration.
11001220
std::optional<SystemMessageConfig> system_message;
11011221

@@ -1136,6 +1256,7 @@ struct MessageOptions
11361256
std::string prompt;
11371257
std::optional<std::vector<UserMessageAttachment>> attachments;
11381258
std::optional<std::string> mode;
1259+
std::optional<std::map<std::string, std::string>> request_headers;
11391260
};
11401261

11411262
inline void to_json(json& j, const MessageOptions& o)
@@ -1145,6 +1266,19 @@ inline void to_json(json& j, const MessageOptions& o)
11451266
j["attachments"] = *o.attachments;
11461267
if (o.mode)
11471268
j["mode"] = *o.mode;
1269+
if (o.request_headers)
1270+
j["requestHeaders"] = *o.request_headers;
1271+
}
1272+
1273+
inline void from_json(const json& j, MessageOptions& o)
1274+
{
1275+
j.at("prompt").get_to(o.prompt);
1276+
if (j.contains("attachments"))
1277+
o.attachments = j.at("attachments").get<std::vector<UserMessageAttachment>>();
1278+
if (j.contains("mode"))
1279+
o.mode = j.at("mode").get<std::string>();
1280+
if (j.contains("requestHeaders"))
1281+
o.request_headers = j.at("requestHeaders").get<std::map<std::string, std::string>>();
11481282
}
11491283

11501284
// =============================================================================

‎src/client.cpp‎

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,12 @@ json build_session_create_request(const SessionConfig& config)
3434

3535
if (config.session_id.has_value())
3636
request["sessionId"] = *config.session_id;
37+
if (config.model_capabilities.has_value())
38+
request["modelCapabilities"] = *config.model_capabilities;
3739
if (config.on_permission_request.has_value())
3840
request["requestPermission"] = true;
3941
if (config.system_message.has_value())
40-
{
41-
json sys_msg;
42-
if (config.system_message->content.has_value())
43-
sys_msg["content"] = *config.system_message->content;
44-
if (config.system_message->mode.has_value())
45-
{
46-
sys_msg["mode"] =
47-
(*config.system_message->mode == SystemMessageMode::Replace) ? "replace" : "append";
48-
}
49-
request["systemMessage"] = sys_msg;
50-
}
42+
request["systemMessage"] = *config.system_message;
5143
// Add custom tool definitions to the request
5244
if (!config.tools.empty())
5345
{
@@ -67,6 +59,8 @@ json build_session_create_request(const SessionConfig& config)
6759
}
6860
request["tools"] = tool_defs;
6961
}
62+
if (config.commands.has_value())
63+
request["commands"] = *config.commands;
7064
if (config.available_tools.has_value())
7165
request["availableTools"] = *config.available_tools;
7266
if (config.excluded_tools.has_value())
@@ -94,6 +88,10 @@ json build_session_create_request(const SessionConfig& config)
9488
agents.push_back(agent);
9589
request["customAgents"] = agents;
9690
}
91+
if (config.default_agent.has_value())
92+
request["defaultAgent"] = *config.default_agent;
93+
if (config.agent.has_value())
94+
request["agent"] = *config.agent;
9795
if (config.skill_directories.has_value())
9896
request["skillDirectories"] = *config.skill_directories;
9997
if (config.disabled_skills.has_value())
@@ -110,6 +108,8 @@ json build_session_create_request(const SessionConfig& config)
110108
request["hooks"] = true;
111109
if (config.working_directory.has_value())
112110
request["workingDirectory"] = *config.working_directory;
111+
if (config.github_token.has_value())
112+
request["githubToken"] = *config.github_token;
113113

114114
// v0.1.49 additions
115115
if (config.client_name.has_value())
@@ -154,6 +154,8 @@ json build_session_resume_request(const std::string& session_id, const ResumeSes
154154
}
155155
request["tools"] = tool_defs;
156156
}
157+
if (config.commands.has_value())
158+
request["commands"] = *config.commands;
157159
if (config.streaming)
158160
request["streaming"] = config.streaming;
159161

@@ -177,6 +179,10 @@ json build_session_resume_request(const std::string& session_id, const ResumeSes
177179
agents.push_back(agent);
178180
request["customAgents"] = agents;
179181
}
182+
if (config.default_agent.has_value())
183+
request["defaultAgent"] = *config.default_agent;
184+
if (config.agent.has_value())
185+
request["agent"] = *config.agent;
180186
if (config.skill_directories.has_value())
181187
request["skillDirectories"] = *config.skill_directories;
182188
if (config.disabled_skills.has_value())
@@ -187,20 +193,12 @@ json build_session_resume_request(const std::string& session_id, const ResumeSes
187193
// New fields for v0.1.23 parity
188194
if (config.model.has_value())
189195
request["model"] = *config.model;
196+
if (config.model_capabilities.has_value())
197+
request["modelCapabilities"] = *config.model_capabilities;
190198
if (config.reasoning_effort.has_value())
191199
request["reasoningEffort"] = *config.reasoning_effort;
192200
if (config.system_message.has_value())
193-
{
194-
json sys_msg;
195-
if (config.system_message->content.has_value())
196-
sys_msg["content"] = *config.system_message->content;
197-
if (config.system_message->mode.has_value())
198-
{
199-
sys_msg["mode"] =
200-
(*config.system_message->mode == SystemMessageMode::Replace) ? "replace" : "append";
201-
}
202-
request["systemMessage"] = sys_msg;
203-
}
201+
request["systemMessage"] = *config.system_message;
204202
if (config.available_tools.has_value())
205203
request["availableTools"] = *config.available_tools;
206204
if (config.excluded_tools.has_value())

‎src/session.cpp‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,8 @@ std::future<std::string> Session::send(MessageOptions options)
3636
std::launch::async,
3737
[this, options = std::move(options)]()
3838
{
39-
json params;
39+
json params = options;
4040
params["sessionId"] = session_id_;
41-
params["prompt"] = options.prompt;
42-
43-
if (options.attachments.has_value())
44-
params["attachments"] = *options.attachments;
45-
if (options.mode.has_value())
46-
params["mode"] = *options.mode;
4741

4842
auto response = client_->rpc_client()->invoke(copilot::rpc::methods::kSessionSend, params).get();
4943
return response["messageId"].get<std::string>();

0 commit comments

Comments
 (0)