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: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -1909,7 +1909,7 @@ const session = await client.createSession({
});
```

Available section IDs: `identity`, `tone`, `tool_efficiency`, `environment_context`, `code_change_rules`, `guidelines`, `safety`, `tool_instructions`, `custom_instructions`, `last_instructions`.
Available section IDs: `identity`, `tone`, `tool_efficiency`, `environment_context`, `code_change_rules`, `guidelines`, `safety`, `tool_instructions`, `custom_instructions`, `runtime_instructions`, `last_instructions`.

Each override supports four actions: `replace`, `remove`, `append`, and `prepend`. Unknown section IDs are handled gracefully—content is appended to additional instructions and a warning is emitted; `remove` on unknown sections is silently ignored.

Expand Down
12 changes: 6 additions & 6 deletions dotnet/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copilot SDK
# Copilot SDK

SDK for programmatic control of GitHub Copilot CLI.

Expand Down Expand Up @@ -627,18 +627,18 @@ var session = await client.CreateSessionAsync(new SessionConfig
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary<string, SectionOverride>
Sections = new Dictionary<SystemMessageSection, SectionOverride>
{
[SystemPromptSections.Tone] = new() { Action = SectionOverrideAction.Replace, Content = "Respond in a warm, professional tone. Be thorough in explanations." },
[SystemPromptSections.CodeChangeRules] = new() { Action = SectionOverrideAction.Remove },
[SystemPromptSections.Guidelines] = new() { Action = SectionOverrideAction.Append, Content = "\n* Always cite data sources" },
[SystemMessageSection.Tone] = new() { Action = SectionOverrideAction.Replace, Content = "Respond in a warm, professional tone. Be thorough in explanations." },
[SystemMessageSection.CodeChangeRules] = new() { Action = SectionOverrideAction.Remove },
[SystemMessageSection.Guidelines] = new() { Action = SectionOverrideAction.Append, Content = "\n* Always cite data sources" },
},
Content = "Focus on financial analysis and reporting."
}
});
```

Available section IDs are defined as constants on `SystemPromptSections`: `Identity`, `Tone`, `ToolEfficiency`, `EnvironmentContext`, `CodeChangeRules`, `Guidelines`, `Safety`, `ToolInstructions`, `CustomInstructions`, `LastInstructions`.
Available section IDs are defined as static properties on the `SystemMessageSection` struct: `Identity`, `Tone`, `ToolEfficiency`, `EnvironmentContext`, `CodeChangeRules`, `Guidelines`, `Safety`, `ToolInstructions`, `CustomInstructions`, `RuntimeInstructions`, `LastInstructions`.

Each section override supports four actions: `Replace`, `Remove`, `Append`, and `Prepend`. Unknown section IDs are handled gracefully: content is appended to additional instructions, and `Remove` overrides are silently ignored.

Expand Down
6 changes: 3 additions & 3 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*---------------------------------------------------------------------------------------------
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

Expand Down Expand Up @@ -464,13 +464,13 @@ private static (SystemMessageConfig? wireConfig, Dictionary<string, Func<string,
}

var callbacks = new Dictionary<string, Func<string, Task<string>>>();
var wireSections = new Dictionary<string, SectionOverride>();
var wireSections = new Dictionary<SystemMessageSection, SectionOverride>();

foreach (var (sectionId, sectionOverride) in systemMessage.Sections)
{
if (sectionOverride.Transform != null)
{
callbacks[sectionId] = sectionOverride.Transform;
callbacks[sectionId.Value] = sectionOverride.Transform;
wireSections[sectionId] = new SectionOverride { Action = SectionOverrideAction.Transform };
}
else
Expand Down
99 changes: 82 additions & 17 deletions dotnet/src/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ public enum SystemMessageMode
}

/// <summary>
/// Specifies the operation to perform on a system prompt section.
/// Specifies the operation to perform on a system message section.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<SectionOverrideAction>))]
public enum SectionOverrideAction
Expand All @@ -1771,7 +1771,7 @@ public enum SectionOverrideAction
}

/// <summary>
/// Override operation for a single system prompt section.
/// Override operation for a single system message section.
/// </summary>
public sealed class SectionOverride
{
Expand All @@ -1797,30 +1797,95 @@ public sealed class SectionOverride
}

/// <summary>
/// Known system prompt section identifiers for the "customize" mode.
/// Identifies a system message section for the "customize" mode.
/// </summary>
public static class SystemPromptSections
[JsonConverter(typeof(SystemMessageSection.Converter))]
public readonly struct SystemMessageSection : IEquatable<SystemMessageSection>
{
/// <summary>Agent identity preamble and mode statement.</summary>
public const string Identity = "identity";
public static SystemMessageSection Identity { get; } = new("identity");
/// <summary>Response style, conciseness rules, output formatting preferences.</summary>
public const string Tone = "tone";
public static SystemMessageSection Tone { get; } = new("tone");
/// <summary>Tool usage patterns, parallel calling, batching guidelines.</summary>
public const string ToolEfficiency = "tool_efficiency";
public static SystemMessageSection ToolEfficiency { get; } = new("tool_efficiency");
/// <summary>CWD, OS, git root, directory listing, available tools.</summary>
public const string EnvironmentContext = "environment_context";
public static SystemMessageSection EnvironmentContext { get; } = new("environment_context");
/// <summary>Coding rules, linting/testing, ecosystem tools, style.</summary>
public const string CodeChangeRules = "code_change_rules";
public static SystemMessageSection CodeChangeRules { get; } = new("code_change_rules");
/// <summary>Tips, behavioral best practices, behavioral guidelines.</summary>
public const string Guidelines = "guidelines";
public static SystemMessageSection Guidelines { get; } = new("guidelines");
/// <summary>Environment limitations, prohibited actions, security policies.</summary>
public const string Safety = "safety";
public static SystemMessageSection Safety { get; } = new("safety");
/// <summary>Per-tool usage instructions.</summary>
public const string ToolInstructions = "tool_instructions";
public static SystemMessageSection ToolInstructions { get; } = new("tool_instructions");
/// <summary>Repository and organization custom instructions.</summary>
public const string CustomInstructions = "custom_instructions";
public static SystemMessageSection CustomInstructions { get; } = new("custom_instructions");
/// <summary>Runtime-provided context and instructions (e.g. system notifications, memories, workspace context, mode-specific instructions, content-exclusion policy).</summary>
public static SystemMessageSection RuntimeInstructions { get; } = new("runtime_instructions");
/// <summary>End-of-prompt instructions: parallel tool calling, persistence, task completion.</summary>
public const string LastInstructions = "last_instructions";
public static SystemMessageSection LastInstructions { get; } = new("last_instructions");

/// <summary>Gets the underlying string value of this <see cref="SystemMessageSection"/>.</summary>
public string Value => _value ?? string.Empty;

private readonly string? _value;

/// <summary>Initializes a new instance of the <see cref="SystemMessageSection"/> struct.</summary>
/// <param name="value">The string value for this section identifier.</param>
[JsonConstructor]
public SystemMessageSection(string value) => _value = value;

/// <inheritdoc/>
public static bool operator ==(SystemMessageSection left, SystemMessageSection right) => left.Equals(right);

/// <inheritdoc/>
public static bool operator !=(SystemMessageSection left, SystemMessageSection right) => !left.Equals(right);

/// <inheritdoc/>
public override bool Equals([NotNullWhen(true)] object? obj) => obj is SystemMessageSection other && Equals(other);

/// <inheritdoc/>
public bool Equals(SystemMessageSection other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);

/// <inheritdoc/>
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);

/// <inheritdoc/>
public override string ToString() => Value;

/// <summary>Provides a <see cref="JsonConverter{SystemMessageSection}"/> for serializing <see cref="SystemMessageSection"/> instances.</summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class Converter : JsonConverter<SystemMessageSection>
{
/// <inheritdoc/>
public override SystemMessageSection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
{
throw new JsonException("Expected string for SystemMessageSection.");
}

var value = reader.GetString();
if (value is null)
{
throw new JsonException("SystemMessageSection value cannot be null.");
}

return new SystemMessageSection(value);
}

/// <inheritdoc/>
public override void Write(Utf8JsonWriter writer, SystemMessageSection value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.Value);

/// <inheritdoc/>
public override SystemMessageSection ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
new(reader.GetString()!);

/// <inheritdoc/>
public override void WriteAsPropertyName(Utf8JsonWriter writer, SystemMessageSection value, JsonSerializerOptions options) =>
writer.WritePropertyName(value.Value);
}
}

/// <summary>
Expand All @@ -1841,9 +1906,9 @@ public sealed class SystemMessageConfig

/// <summary>
/// Section-level overrides for customize mode.
/// Keys are section identifiers (see <see cref="SystemPromptSections"/>).
/// Keys are section identifiers (see <see cref="SystemMessageSection"/>).
/// </summary>
public IDictionary<string, SectionOverride>? Sections { get; set; }
public IDictionary<SystemMessageSection, SectionOverride>? Sections { get; set; }
}

/// <summary>
Expand Down Expand Up @@ -3001,7 +3066,7 @@ public sealed class SetForegroundSessionResponse
}

/// <summary>
/// Content data for a single system prompt section in a transform RPC call.
/// Content data for a single system message section in a transform RPC call.
/// </summary>
public sealed class SystemMessageTransformSection
{
Expand Down
8 changes: 4 additions & 4 deletions dotnet/test/E2E/SessionE2ETests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*---------------------------------------------------------------------------------------------
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

Expand Down Expand Up @@ -101,10 +101,10 @@ public async Task Should_Create_A_Session_With_Customized_SystemMessage_Config()
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary<string, SectionOverride>
Sections = new Dictionary<SystemMessageSection, SectionOverride>
{
[SystemPromptSections.Tone] = new() { Action = SectionOverrideAction.Replace, Content = customTone },
[SystemPromptSections.CodeChangeRules] = new() { Action = SectionOverrideAction.Remove },
[SystemMessageSection.Tone] = new() { Action = SectionOverrideAction.Replace, Content = customTone },
[SystemMessageSection.CodeChangeRules] = new() { Action = SectionOverrideAction.Remove },
},
Content = appendedContent
}
Expand Down
16 changes: 8 additions & 8 deletions dotnet/test/E2E/SystemMessageTransformE2ETests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public async Task Should_Invoke_Transform_Callbacks_With_Section_Content()
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary<string, SectionOverride>
Sections = new Dictionary<SystemMessageSection, SectionOverride>
{
["identity"] = new SectionOverride
[SystemMessageSection.Identity] = new SectionOverride
{
Transform = async (content) =>
{
Expand All @@ -33,7 +33,7 @@ public async Task Should_Invoke_Transform_Callbacks_With_Section_Content()
return content;
}
},
["tone"] = new SectionOverride
[SystemMessageSection.Tone] = new SectionOverride
{
Transform = async (content) =>
{
Expand Down Expand Up @@ -68,9 +68,9 @@ public async Task Should_Apply_Transform_Modifications_To_Section_Content()
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary<string, SectionOverride>
Sections = new Dictionary<SystemMessageSection, SectionOverride>
{
["identity"] = new SectionOverride
[SystemMessageSection.Identity] = new SectionOverride
{
Transform = async (content) =>
{
Expand Down Expand Up @@ -108,13 +108,13 @@ public async Task Should_Work_With_Static_Overrides_And_Transforms_Together()
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary<string, SectionOverride>
Sections = new Dictionary<SystemMessageSection, SectionOverride>
{
["safety"] = new SectionOverride
[SystemMessageSection.Safety] = new SectionOverride
{
Action = SectionOverrideAction.Remove
},
["identity"] = new SectionOverride
[SystemMessageSection.Identity] = new SectionOverride
{
Transform = async (content) =>
{
Expand Down
10 changes: 6 additions & 4 deletions dotnet/test/Unit/PublicDtoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,17 @@ private static bool TryCreateGenericCollection(Type type, HashSet<Type> visited,
.FirstOrDefault(candidate =>
candidate.IsGenericType &&
(candidate.GetGenericTypeDefinition() == typeof(IDictionary<,>) ||
candidate.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)) &&
candidate.GetGenericArguments()[0] == typeof(string));
candidate.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)));

if (dictionaryInterface is not null)
{
var keyType = dictionaryInterface.GetGenericArguments()[0];
var valueType = dictionaryInterface.GetGenericArguments()[1];
TryCreateSampleValue(keyType, visited, out var sampleKey);
TryCreateSampleValue(valueType, visited, out var sampleValue);
var dictionary = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(typeof(string), valueType))!;
dictionary["key"] = sampleValue;
var dictionaryType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
var dictionary = (IDictionary)Activator.CreateInstance(dictionaryType)!;
dictionary[sampleKey!] = sampleValue;
value = dictionary;
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Event types: `SessionLifecycleCreated`, `SessionLifecycleDeleted`, `SessionLifec
- `SystemMessage` (\*SystemMessageConfig): System message configuration. Supports three modes:
- **append** (default): Appends `Content` after the SDK-managed prompt
- **replace**: Replaces the entire prompt with `Content`
- **customize**: Selectively override individual sections via `Sections` map (keys: `SectionIdentity`, `SectionTone`, `SectionToolEfficiency`, `SectionEnvironmentContext`, `SectionCodeChangeRules`, `SectionGuidelines`, `SectionSafety`, `SectionToolInstructions`, `SectionCustomInstructions`, `SectionLastInstructions`; values: `SectionOverride` with `Action` and optional `Content`)
- **customize**: Selectively override individual sections via `Sections` map (keys: `SectionIdentity`, `SectionTone`, `SectionToolEfficiency`, `SectionEnvironmentContext`, `SectionCodeChangeRules`, `SectionGuidelines`, `SectionSafety`, `SectionToolInstructions`, `SectionCustomInstructions`, `SectionRuntimeInstructions`, `SectionLastInstructions`; values: `SectionOverride` with `Action` and optional `Content`)
- `Provider` (\*ProviderConfig): Custom API provider configuration (BYOK). See [Custom Providers](#custom-providers) section.
- `Streaming` (*bool): Enable streaming delta events (nil = runtime default)
- `InfiniteSessions` (\*InfiniteSessionConfig): Automatic context compaction configuration
Expand Down Expand Up @@ -233,7 +233,7 @@ session, err := client.CreateSession(ctx, &copilot.SessionConfig{
})
```

Available section constants: `SectionIdentity`, `SectionTone`, `SectionToolEfficiency`, `SectionEnvironmentContext`, `SectionCodeChangeRules`, `SectionGuidelines`, `SectionSafety`, `SectionToolInstructions`, `SectionCustomInstructions`, `SectionLastInstructions`.
Available section constants: `SectionIdentity`, `SectionTone`, `SectionToolEfficiency`, `SectionEnvironmentContext`, `SectionCodeChangeRules`, `SectionGuidelines`, `SectionSafety`, `SectionToolInstructions`, `SectionCustomInstructions`, `SectionRuntimeInstructions`, `SectionLastInstructions`.

Each section override supports four actions:

Expand Down
Loading
Loading