Add fine-grained system prompt customization (customize mode)#816
Add fine-grained system prompt customization (customize mode)#816SteveSandersonMS merged 12 commits intomainfrom
Conversation
Cross-SDK Consistency Review ✅❌Great work adding the "customize" mode feature across all 4 SDKs! The core implementation is well-aligned across languages with proper naming conventions. However, I've identified some documentation and testing gaps that should be addressed for consistency. ✅ What's Consistent
❌ Inconsistencies to Address1. Critical Bug: Wrong Package Name (Node.js README)
2. Documentation Gaps: Python & Go Missing Standalone Examples
Suggestion: Add standalone "Customize Mode" subsections to Python and Go READMEs similar to TypeScript/C#, showing:
3. Testing Gap: Only Node.js Has E2E Test
Suggestion: Add equivalent E2E tests to Python, Go, and .NET test suites to ensure the feature works correctly and consistently across all SDKs. 📋 Recommended Actions
SummaryThe core feature implementation is excellent and consistent. The issues are limited to documentation quality (missing examples) and test coverage gaps. Once these are addressed, this PR will maintain full feature parity across all 4 SDKs! 🚀
|
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #816
✅ Cross-SDK Consistency Review: Excellent Work!This PR demonstrates outstanding cross-SDK consistency across all 4 language implementations. The "customize mode" feature has been implemented with remarkable attention to detail and consistency. Summary of ChangesAdded fine-grained system prompt customization (
Consistency Verification✅ Section Identifiers (All identical across languages)✅ Action Names (All identical)
✅ Mode Name (Consistent)
✅ API Structure (Parallel design respecting language conventions)TypeScript (camelCase): systemMessage: {
mode: "customize",
sections: {
tone: { action: "replace", content: "..." }
}
}Python (snake_case): system_message={
"mode": "customize",
"sections": {
"tone": {"action": "replace", "content": "..."}
}
}Go (exported constants): SystemMessage: &copilot.SystemMessageConfig{
Mode: "customize",
Sections: map[string]copilot.SectionOverride{
copilot.SectionTone: {Action: "replace", Content: "..."}
}
}.NET (PascalCase + enum): SystemMessage = new SystemMessageConfig {
Mode = SystemMessageMode.Customize,
Sections = new Dictionary(string, SectionOverride) {
[SystemPromptSections.Tone] = new() {
Action = SectionOverrideAction.Replace,
Content = "..."
}
}
}Additional Consistency Points✅ Type definitions - All languages export the new types properly
✅ Graceful fallback behavior - Documented consistently across all languages VerdictNo consistency issues found. This PR is a textbook example of how to maintain feature parity across multi-language SDKs. The implementation respects each language's idioms while maintaining semantic consistency. 🎉 Great work @MackinnonBuck!
|
SDK Consistency Review: System Prompt Customization FeatureI've reviewed this PR for cross-SDK consistency. The implementation is excellent overall with proper feature parity across all 4 language implementations. All SDKs correctly implement: ✅ Core types:
|
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #816
| SectionEnvironmentContext = "environment_context" | ||
| SectionCodeChangeRules = "code_change_rules" | ||
| SectionGuidelines = "guidelines" | ||
| SectionSafety = "safety" |
There was a problem hiding this comment.
Cross-SDK consistency: Consider adding a SectionDescriptions map here to match TypeScript's SYSTEM_PROMPT_SECTIONS and Python's SYSTEM_PROMPT_SECTIONS.
All other SDKs expose section descriptions for documentation/tooling:
- TypeScript:
SYSTEM_PROMPT_SECTIONS(Record<SystemPromptSection, { description: string }>) - Python:
SYSTEM_PROMPT_SECTIONS(dict[SystemPromptSection, str]) - .NET: XML doc comments on each
SystemPromptSectionsconstant
Suggested addition:
// SectionDescriptions provides human-readable descriptions for each system prompt section.
var SectionDescriptions = map[string]string{
SectionIdentity: "Agent identity preamble and mode statement",
SectionTone: "Response style, conciseness rules, output formatting preferences",
SectionToolEfficiency: "Tool usage patterns, parallel calling, batching guidelines",
SectionEnvironmentContext: "CWD, OS, git root, directory listing, available tools",
SectionCodeChangeRules: "Coding rules, linting/testing, ecosystem tools, style",
SectionGuidelines: "Tips, behavioral best practices, behavioral guidelines",
SectionSafety: "Environment limitations, prohibited actions, security policies",
SectionToolInstructions: "Per-tool usage instructions",
SectionCustomInstructions: "Repository and organization custom instructions",
SectionLastInstructions: "End-of-prompt instructions: parallel tool calling, persistence, task completion",
}This would make Go's public API equivalent to the other SDKs and improve discoverability for SDK consumers.
28b1bc5 to
0348b8e
Compare
✅ Cross-SDK Consistency Review: EXCELLENTI've completed a thorough review of PR #816 for cross-language SDK consistency. This PR adds the "customize" mode for system prompt customization across all 4 SDK implementations. SummaryThis PR maintains exceptional consistency across all SDKs. The feature has been implemented uniformly with proper attention to language-specific conventions while maintaining semantic parity. ✅ What's Consistent1. Core Type DefinitionsAll 4 SDKs define the same structures with language-appropriate naming:
2. Section IdentifiersAll 10 section identifiers are present in all SDKs with identical string values:
3. ActionsAll 4 actions are consistently available:
4. API Surface
5. E2E TestsEach SDK includes an equivalent test that:
Test coverage: ✅ TypeScript, ✅ Python, ✅ Go, ✅ .NET 6. DocumentationAll 5 documentation files updated with:
🎯 Language Convention AdherenceThe PR properly follows each language's idioms:
📝 Minor Observations
✅ RecommendationThis PR demonstrates excellent cross-SDK consistency. No changes needed from a consistency perspective. The implementation:
Great work on maintaining consistency in this multi-language codebase! 🎉
|
✅ Cross-SDK Consistency ReviewI've reviewed PR #816 for consistency across all four SDK implementations (TypeScript, Python, Go, and .NET). Excellent work! This PR maintains strong feature parity and API consistency. SummaryThe new "customize" mode for system prompt customization is uniformly implemented across all SDKs with:
Language-Specific Conventions Appropriately Applied
No cross-language inconsistencies detected. The implementation properly balances consistency with language-idiomatic design.
|
|
@MackinnonBuck is there a way to view/ retrieve the default/ built in value? Be good to be able to see what the default value is if I perform a "replace", as I might just want to tweak the behavior slightly. |
|
@IeuanWalker are you wanting a way to read sections of the system prompt programmatically? This PR does not provide that facility, but we could address it in a follow-up. |
|
@MackinnonBuck not specifically programmatically, just some way for us to find the current/ default value Even if it's just on a doc somewhere. Atm I might replace one of the values with something else verbose, so be good just too see what the current structure is before replacing it |
Cross-SDK Consistency Review ✅I've reviewed PR #816 for consistency across all four SDK implementations (TypeScript, Python, Go, .NET). Overall, the implementation maintains excellent consistency. Here's what I found: ✅ Consistent Across All SDKs:
|
4102bd1 to
daf9337
Compare
daf9337 to
38376d8
Compare
✅ Cross-SDK Consistency Review: Excellent Feature ParityI've completed a comprehensive review of PR #816 across all four SDK implementations (TypeScript, Python, Go, .NET). This PR adds fine-grained system prompt customization through the new 🎯 Summary: Strong Consistency Across All SDKsThis PR demonstrates excellent cross-language consistency with parallel implementations across all four SDKs. The feature is fully implemented with equivalent APIs, comprehensive E2E tests, and documentation in all languages. ✅ Consistent API SurfaceAll four SDKs expose identical capabilities:
Sections Supported (all SDKs): ✅ Consistent TestingAll four SDKs include equivalent E2E tests using shared snapshot files:
Shared snapshots in
✅ Consistent DocumentationAll four README files include parallel examples demonstrating the customize mode:
Plus comprehensive examples in 📊 Language-Specific Design Choices (Expected)Each SDK appropriately adapts to language idioms:
💡 Notable Implementation Details
🎉 ConclusionThis PR maintains excellent cross-SDK consistency while appropriately adapting to each language's idioms and runtime characteristics. The feature is fully implemented with:
No consistency issues found. The implementation demonstrates best practices for multi-language SDK development. 🚀
|
d3dee9b to
6b7d32c
Compare
🔍 Cross-SDK Consistency ReviewI've completed a comprehensive review of PR #816 to ensure consistency across all four SDK implementations (TypeScript, Python, Go, .NET). ✅ Excellent Consistency - No Blocking IssuesThis PR demonstrates exceptional cross-language consistency: Core Feature Parity ✅All 4 SDKs implement:
API Naming Consistency ✅Naming follows language conventions appropriately:
Implementation Consistency ✅
Testing Parity ✅
📝 Documentation Suggestion: Transform Callbacks Not DocumentedWhile the transform feature is fully implemented and tested across all SDKs, it's not documented in any README or getting-started guide. What's missing: Suggestion: Consider adding transform callback examples to each SDK's README: // TypeScript
sections: {
identity: {
action: (currentContent) => {
return currentContent.replace("GitHub Copilot", "Acme Assistant");
}
}
}# Python (supports both sync and async)
"sections": {
"identity": {
"action": lambda content: content.replace("GitHub Copilot", "Acme Assistant")
}
}// Go
Sections: map[string]copilot.SectionOverride{
copilot.SectionIdentity: {
Transform: func(content string) (string, error) {
return strings.Replace(content, "GitHub Copilot", "Acme Assistant", 1), nil
},
},
}// C#
Sections = new Dictionary(string, SectionOverride)
{
[SystemPromptSections.Identity] = new() {
Transform = async (content) => {
return content.Replace("GitHub Copilot", "Acme Assistant");
}
}
}SummaryNo consistency issues found. This PR maintains excellent feature parity and API design consistency across all four SDKs. The only suggestion is to document the transform callback feature so users can discover this powerful capability. 🎉
|
6b7d32c to
150eb33
Compare
SDK Consistency Review ✅This PR adds the "customize" mode and "transform" action for system prompt customization across all 4 SDK implementations. Great work on maintaining consistency! ✅ Cross-Language ConsistencyThe implementation is highly consistent across all SDKs:
📝 Documentation Gap: Transform Action Not DocumentedWhile the transform action is fully implemented and tested, it's not documented in any README or getting-started guide:
Expected: Documentation should mention all 5 actions and include examples showing how to use transform callbacks for read-then-write mutations, logging/observability, and conditional modifications (as described in the PR description). Suggested fix: Add a subsection to the "Customize Mode" documentation in all 4 READMEs and
This would match the excellent examples already present in the E2E tests and bring the documentation up to the same quality as the implementation. Summary: The cross-SDK consistency for the customize mode implementation is excellent. The only issue is that the transform action needs to be added to the user-facing documentation.
|
Add a new 'customize' mode for systemMessage configuration, enabling SDK consumers to selectively override individual sections of the CLI system prompt while preserving the rest. This sits between the existing 'append' and 'replace' modes. 9 configurable sections: identity, tone, tool_efficiency, environment_context, code_change_rules, guidelines, safety, tool_instructions, custom_instructions. 4 override actions per section: replace, remove, append, prepend. Unknown section IDs are handled gracefully: content-bearing overrides are appended to additional instructions with a warning, and remove on unknown sections is silently ignored. Types and constants added to all 4 SDK languages (TypeScript, Python, Go, .NET). Documentation updated across all READMEs and getting-started guide. Companion runtime PR: github/copilot-agent-runtime#4751 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix incorrect package name in nodejs/README.md (@anthropic-ai/sdk -> @github/copilot-sdk) - Add standalone 'System Message Customization' sections with full code examples to Python and Go READMEs (matching TypeScript/.NET) - Add E2E tests for customize mode to Python, Go, and .NET (matching existing Node.js E2E test coverage) - Fix 'end of the prompt' wording in docs to 'additional instructions' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expose lastInstructions as a customizable section across all 4 SDKs, addressing review feedback about duplicate tool-efficiency blocks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds a new 'transform' action to SectionOverride that enables read-then-write mutation of system prompt sections via callbacks. The SDK intercepts function- valued actions before serialization, stores the callbacks locally, and handles the batched systemMessage.transform JSON-RPC callback from the runtime. Changes across all 4 SDKs (TypeScript, Python, Go, .NET): - Types: SectionTransformFn, SectionOverrideAction (TS/Python), Transform field (Go/.NET), SectionOverrideAction constants (Go) - Client: extractTransformCallbacks helper, transform callback registration, systemMessage.transform RPC handler - Session: transform callback storage and batched dispatch with error handling - E2E tests and shared snapshot YAML files Wire protocol: single batched RPC call with all transform sections, matching the runtime implementation in copilot-agent-runtime PR #5103. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
150eb33 to
a422b3c
Compare
Cross-SDK Consistency Review ✅I've reviewed PR #816 for consistency across all four SDK implementations (TypeScript, Python, Go, .NET). Excellent work! This PR demonstrates exemplary cross-language feature parity for the new "customize mode" system prompt customization feature. Summary of ChangesThis PR adds fine-grained system prompt customization capabilities across all 4 SDKs, enabling users to selectively override individual sections of the CLI system prompt while preserving the rest. The implementation is consistent and complete across all languages. ✅ Consistent Type DefinitionsAll 4 languages define the same 10 configurable sections with identical string identifiers:
✅ Consistent API DesignSection Override Actions - All 4 languages support the same actions with consistent semantics:
Transform Callbacks - All languages implement the same callback pattern:
Each correctly handles both sync and async callbacks where applicable (Python, TypeScript, .NET). ✅ Consistent RPC ImplementationAll 4 SDKs implement the
✅ Consistent DocumentationAll 4 READMEs include:
✅ Consistent E2E TestsAll 4 languages have matching E2E test files in their respective test directories:
All tests use the same shared snapshot files in 🎯 Language Convention ComplianceThe implementation correctly follows each language's naming conventions:
📝 Minor Observations (non-blocking)
ConclusionNo consistency issues found. This PR successfully adds the "customize mode" feature with complete feature parity across all 4 SDK implementations. The API design, type definitions, RPC handling, documentation, and tests are all consistent and follow language-specific conventions appropriately. Great work on maintaining consistency across this multi-language SDK! 🎉
|
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Generate the missing snapshot file that the 'should create a session with customized systemMessage config' test requires across all SDK languages (Node, Python, Go, .NET). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency Review ✅I've completed a comprehensive review of this PR for cross-language SDK consistency. Overall, this PR maintains excellent consistency across all 4 SDK implementations (TypeScript, Python, Go, .NET). Here's my detailed analysis: ✅ Excellent Consistency Achievements
📝 Minor Documentation Inconsistency (Not Blocking)The transform action is fully implemented and tested in all 4 languages, but is not documented in user-facing documentation:
The PR description correctly lists 5 actions and includes a transform example, so this appears to be an oversight in the documentation portions. 📚 RecommendationConsider adding transform documentation/examples to:
The transform feature itself is fully implemented and works correctly across all SDKs — this is purely a documentation gap that could help users discover this powerful capability. 🎯 ConclusionThis PR successfully maintains cross-SDK consistency. The implementation, testing, and API design are all excellent. The documentation gap noted above is minor and doesn't affect the functionality. Great work on ensuring feature parity across all 4 languages! 🚀
|
- Add blank // comment line between doc example and extractTransformCallbacks function doc comment in go/client.go (required by go fmt) - Fix ruff import sorting in python/copilot/__init__.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new systemMessage.mode = "customize" across the TypeScript, Python, Go, and .NET SDKs, enabling section-level system prompt overrides plus a systemMessage.transform JSON-RPC callback so SDK consumers can read/modify rendered prompt sections without replacing the whole prompt.
Changes:
- Introduces “customize” system message config types and section override models (incl. transform callbacks) across all 4 SDKs.
- Implements transform-callback extraction (wire-safe payload + local callback registry) and a
systemMessage.transformRPC handler in each SDK. - Adds cross-language E2E coverage (new tests + shared snapshots) and updates docs/READMEs to describe customize mode.
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
docs/getting-started.md |
Documents systemMessage customize mode usage in the main getting-started guide. |
dotnet/README.md |
Adds .NET customize-mode documentation and examples. |
dotnet/src/Client.cs |
Extracts transform callbacks before serialization; registers RPC handler for systemMessage.transform. |
dotnet/src/SdkProtocolVersion.cs |
Minor refactor to expression-bodied GetVersion. |
dotnet/src/Session.cs |
Stores transform callbacks and applies them in systemMessage.transform handler. |
dotnet/src/Types.cs |
Adds Customize mode, section override types, section constants, and transform RPC response models. |
dotnet/test/SessionTests.cs |
Adds E2E test for customized system message config. |
dotnet/test/SystemMessageTransformTests.cs |
Adds E2E tests validating transform callback invocation and behavior. |
go/README.md |
Adds Go customize-mode documentation and examples. |
go/client.go |
Extracts transform callbacks for wire payload; registers systemMessage.transform handler. |
go/internal/e2e/session_test.go |
Adds E2E test for customized system message config. |
go/internal/e2e/system_message_transform_test.go |
Adds E2E tests for transform callback invocation/behavior. |
go/session.go |
Stores transform callbacks and applies them on systemMessage.transform requests. |
go/types.go |
Adds section constants, override types, and customize-mode fields on SystemMessageConfig. |
nodejs/README.md |
Adds Node customize-mode documentation and examples. |
nodejs/src/client.ts |
Extracts transform callbacks and registers systemMessage.transform request handler. |
nodejs/src/index.ts |
Exports new section metadata/types from the public entrypoint. |
nodejs/src/session.ts |
Stores transform callbacks and applies them per section for transform RPC. |
nodejs/src/types.ts |
Adds customize-mode types: sections, overrides, transform callback shape, and metadata. |
nodejs/test/e2e/session.test.ts |
Adds E2E test for customized system message config. |
nodejs/test/e2e/system_message_transform.test.ts |
Adds E2E tests validating transform callback invocation and behavior. |
python/README.md |
Adds Python customize-mode documentation and examples. |
python/copilot/__init__.py |
Re-exports new system-message customization symbols. |
python/copilot/client.py |
Extracts transform callbacks pre-serialization; registers systemMessage.transform handler. |
python/copilot/session.py |
Stores transform callbacks and applies them in transform RPC handling (sync/async). |
python/copilot/types.py |
Adds customize-mode types, section identifiers, and transform callback typing. |
python/e2e/test_session.py |
Adds Python E2E test for customized system message config. |
python/e2e/test_system_message_transform.py |
Adds Python E2E tests for transform callback invocation and behavior. |
test/snapshots/session/should_create_a_session_with_customized_systemmessage_config.yaml |
Snapshot for customize-mode session creation behavior. |
test/snapshots/system_message_transform/should_apply_transform_modifications_to_section_content.yaml |
Snapshot validating transform modification effects. |
test/snapshots/system_message_transform/should_invoke_transform_callbacks_with_section_content.yaml |
Snapshot validating transform callbacks are invoked with content. |
test/snapshots/system_message_transform/should_work_with_static_overrides_and_transforms_together.yaml |
Snapshot validating static overrides + transforms compose correctly. |
| Each section override supports four actions: | ||
| - **`replace`** — Replace the section content entirely | ||
| - **`remove`** — Remove the section from the prompt | ||
| - **`append`** — Add content after the existing section | ||
| - **`prepend`** — Add content before the existing section | ||
|
|
There was a problem hiding this comment.
Customize mode documentation lists only four actions, but Python also supports per-section transform via function-valued action (sync or async) for read/modify/write of section content. Please document the transform capability here (and mention action can be a callable) so consumers can discover it.
| Each section override supports four actions: | |
| - **`replace`** — Replace the section content entirely | |
| - **`remove`** — Remove the section from the prompt | |
| - **`append`** — Add content after the existing section | |
| - **`prepend`** — Add content before the existing section | |
| Each section override supports these actions: | |
| - **`replace`** — Replace the section content entirely | |
| - **`remove`** — Remove the section from the prompt | |
| - **`append`** — Add content after the existing section | |
| - **`prepend`** — Add content before the existing section | |
| - **`transform`** — Provide a callable `action` (sync or async) that receives the current section content and returns the new content, allowing read/modify/write of the section. | |
| In Python, the `action` value may be either a string (`"replace"`, `"remove"`, `"append"`, `"prepend"`) or a callable used as a per-section transform. When a callable is provided, it is invoked with the existing section text and its return value becomes the updated section content. |
| Each section override supports four actions: | ||
| - **`replace`** — Replace the section content entirely | ||
| - **`remove`** — Remove the section from the prompt | ||
| - **`append`** — Add content after the existing section | ||
| - **`prepend`** — Add content before the existing section |
There was a problem hiding this comment.
This README lists four section override actions, but Go also supports per-section transforms via SectionOverride.Transform (serialized as action "transform"). Please document transform here so users know they can inspect/modify rendered section content at runtime.
| 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. | ||
|
|
There was a problem hiding this comment.
This section documents only Replace/Remove/Append/Prepend, but the C# SDK also supports per-section transforms via SectionOverride.Transform (serialized as action transform). Please document Transform here (and how it interacts with Action) so consumers can use the read/modify/write capability.
| 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. | |
| Each section override supports four built-in `Action` values: `Replace`, `Remove`, `Append`, and `Prepend`. Unknown section IDs are handled gracefully: content is appended to additional instructions, and `Remove` overrides are silently ignored. | |
| For advanced scenarios, `SectionOverride` also exposes an optional `Transform` delegate that lets you read and modify the existing section text. When `Transform` is set, it is used instead of the `Action`/`Content` pair and is serialized as an action of type `transform` in the underlying JSON-RPC payloads. For a given section override you should typically set either `Action`/`Content` or `Transform`, but not both. |
|
|
||
| Available section IDs: `identity`, `tone`, `tool_efficiency`, `environment_context`, `code_change_rules`, `guidelines`, `safety`, `tool_instructions`, `custom_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. |
There was a problem hiding this comment.
This guide says customize-mode overrides support only four actions, but the SDK also supports per-section transform callbacks (read current section content, return modified content). Please add transform to the documented actions and include a brief example so readers can discover and correctly use it.
python/e2e/test_session.py
Outdated
| { | ||
| "system_message": { | ||
| "mode": "customize", | ||
| "sections": { | ||
| "tone": {"action": "replace", "content": custom_tone}, | ||
| "code_change_rules": {"action": "remove"}, | ||
| }, | ||
| "content": appended_content, | ||
| }, | ||
| "on_permission_request": PermissionHandler.approve_all, | ||
| } | ||
| ) | ||
|
|
||
| assistant_message = await session.send_and_wait({"prompt": "Who are you?"}) |
There was a problem hiding this comment.
CopilotClient.create_session is keyword-only (requires on_permission_request= etc.), so passing a single config dict positionally will raise a TypeError. Also, CopilotSession.send_and_wait takes a prompt string, not a { "prompt": ... } dict. Update this test to call create_session with keyword args and pass a string to send_and_wait (or use the correct method that accepts MessageOptions if one exists).
| { | |
| "system_message": { | |
| "mode": "customize", | |
| "sections": { | |
| "tone": {"action": "replace", "content": custom_tone}, | |
| "code_change_rules": {"action": "remove"}, | |
| }, | |
| "content": appended_content, | |
| }, | |
| "on_permission_request": PermissionHandler.approve_all, | |
| } | |
| ) | |
| assistant_message = await session.send_and_wait({"prompt": "Who are you?"}) | |
| on_permission_request=PermissionHandler.approve_all, | |
| system_message={ | |
| "mode": "customize", | |
| "sections": { | |
| "tone": {"action": "replace", "content": custom_tone}, | |
| "code_change_rules": {"action": "remove"}, | |
| }, | |
| "content": appended_content, | |
| }, | |
| ) | |
| assistant_message = await session.send_and_wait("Who are you?") |
| Each section override supports four actions: | ||
| - **`replace`** — Replace the section content entirely | ||
| - **`remove`** — Remove the section from the prompt | ||
| - **`append`** — Add content after the existing section | ||
| - **`prepend`** — Add content before the existing section |
There was a problem hiding this comment.
This section lists only four override actions, but the SDK also supports per-section transform callbacks in customize mode (function-valued action in TS). The README should document transform as a supported action and briefly describe how it works/what it returns so consumers can discover it.
| Each section override supports four actions: | |
| - **`replace`** — Replace the section content entirely | |
| - **`remove`** — Remove the section from the prompt | |
| - **`append`** — Add content after the existing section | |
| - **`prepend`** — Add content before the existing section | |
| Each section override supports five actions: | |
| - **`replace`** — Replace the section content entirely | |
| - **`remove`** — Remove the section from the prompt | |
| - **`append`** — Add content after the existing section | |
| - **`prepend`** — Add content before the existing section | |
| - **`transform`** — Provide a function-valued `action` (customize mode only) that receives the current section (ID and content) and returns either a new string (to replace the content) or a full `SectionOverride`; returning `undefined` leaves the section unchanged. |
Use str() to ensure transform callback result is typed as str, fixing the invalid-assignment error from ty type checker at session.py:689. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The create_session() method was refactored to keyword-only params. Update the customized systemMessage test to use keyword arguments instead of a positional dict, and fix send_and_wait() call to pass prompt as a positional string. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency Review ✅I've reviewed PR #816 for consistency across all four SDK implementations (TypeScript, Python, Go, and .NET). Summary: Excellent Cross-Language ConsistencyThis PR successfully implements the fine-grained system prompt customization feature across all four SDKs with remarkable consistency. The implementation appropriately adapts to each language's idioms while maintaining API parity. ✅ Consistent ImplementationSection Identifiers (10 total)
Override Actions Language-Appropriate Patterns
Both patterns are idiomatic and semantically equivalent. Transform Callbacks
Tests
Documentation 📝 Minor Documentation Gap (Non-Blocking)The transform feature is implemented and tested in all four SDKs but is not documented in any of the language READMEs or While the PR description includes a transform usage example: identity: {
action: (currentContent) => {
return currentContent.replace("GitHub Copilot", "Acme Corp Assistant");
}
}This pattern isn't shown in the SDK documentation files. Since this affects all four SDKs equally, it's a consistent gap rather than a cross-language inconsistency. Suggestion: Consider adding a "Transform Actions" subsection to the README examples in a follow-up PR, showing how users can:
VerdictThis PR maintains excellent cross-SDK consistency. All four language implementations expose the same capabilities with language-appropriate patterns. The minor documentation gap for transform is consistently missing across all SDKs, so there's no inconsistency to address in this PR. Great work on maintaining feature parity across a complex multi-language codebase! 🎉
|
The 'should apply transform modifications' tests previously only verified that the transform callback was invoked, not that the transformed content actually reached the model. Now all 4 SDKs assert that TRANSFORM_MARKER appears in the system message captured from HTTP traffic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency Review: ✅ Excellent with Minor Documentation GapI've reviewed PR #816 for cross-language SDK consistency, and I'm pleased to report that the implementation is exceptionally consistent across all four SDK implementations (TypeScript, Python, Go, and .NET). The feature parity is excellent. ✅ What's Consistent1. Core Types & API Surface
2. Transform Callback Implementation
3. Documentation Examples
|
The systemMessageTransformRequest and systemMessageTransformResponse used anonymous structs without json tags, causing Content to serialize as uppercase 'Content' instead of lowercase 'content'. The CLI expects lowercase, so transform results were silently ignored. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency Review ✅Great work implementing this feature consistently across all 4 SDKs! The implementation demonstrates excellent cross-language consistency: ✅ What's Consistent
|
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #816
| - **`replace`** — Replace the section content entirely | ||
| - **`remove`** — Remove the section from the prompt | ||
| - **`append`** — Add content after the existing section | ||
| - **`prepend`** — Add content before the existing section |
There was a problem hiding this comment.
The README lists "four actions" but the code actually supports five: replace, remove, append, prepend, and transform.
The transform action is a key feature of this PR (mentioned in the PR description) that allows callbacks to read and modify section content dynamically. Consider adding:
Each section override supports five actions:
- **`replace`** — Replace the section content entirely
- **`remove`** — Remove the section from the prompt
- **`append`** — Add content after the existing section
- **`prepend`** — Add content before the existing section
- **Transform callback** — Pass a function `(currentContent: string) => string | Promise(string)` as the `action` to read and modify section content dynamically
Example with transform:
\```typescript
identity: {
action: (content: string) => {
// Log for observability
console.log("Identity prompt:", content);
// Modify and return
return content.replace("GitHub Copilot", "Acme Assistant");
}
}
\```This would help users discover the transform feature without having to read the source code or PR descriptions.
|
|
||
| Available section IDs are defined as constants on `SystemPromptSections`: `Identity`, `Tone`, `ToolEfficiency`, `EnvironmentContext`, `CodeChangeRules`, `Guidelines`, `Safety`, `ToolInstructions`, `CustomInstructions`, `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. |
There was a problem hiding this comment.
The README lists "four actions" but the code supports five: Replace, Remove, Append, Prepend, and transform via the Transform property.
Consider updating to:
Each section override supports five actions: `Replace`, `Remove`, `Append`, `Prepend`, and **transform callbacks via the `Transform` property**.
The `Transform` property accepts a `Func(string, Task(string))` delegate that receives the current section content and returns the modified content:
\```csharp
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary(string, SectionOverride)
{
[SystemPromptSections.Identity] = new SectionOverride
{
Transform = async (content) =>
{
// Log for observability
Console.WriteLine($"Identity: {content}");
// Modify and return
return content.Replace("GitHub Copilot", "Acme Assistant");
}
}
}
}
\```
Unknown section IDs are handled gracefully: content is appended to additional instructions, and `Remove` overrides are silently ignored.| - **`replace`** — Replace the section content entirely | ||
| - **`remove`** — Remove the section from the prompt | ||
| - **`append`** — Add content after the existing section | ||
| - **`prepend`** — Add content before the existing section |
There was a problem hiding this comment.
The README lists "four actions" but the code supports five: replace, remove, append, prepend, and transform callbacks via the Transform field.
Consider updating to:
Each section override supports five actions:
- **`replace`** — Replace the section content entirely
- **`remove`** — Remove the section from the prompt
- **`append`** — Add content after the existing section
- **`prepend`** — Add content before the existing section
- **Transform callback** — Set the `Transform` field to a `SectionTransformFn` that receives current content and returns modified content
Example with transform:
\```go
SystemMessage: &copilot.SystemMessageConfig{
Mode: "customize",
Sections: map[string]copilot.SectionOverride{
copilot.SectionIdentity: {
Transform: func(currentContent string) (string, error) {
// Log for observability
log.Printf("Identity: %s", currentContent)
// Modify and return
modified := strings.ReplaceAll(currentContent, "GitHub Copilot", "Acme Assistant")
return modified, nil
},
},
},
}
\```| - **`replace`** — Replace the section content entirely | ||
| - **`remove`** — Remove the section from the prompt | ||
| - **`append`** — Add content after the existing section | ||
| - **`prepend`** — Add content before the existing section |
There was a problem hiding this comment.
The README lists "four actions" but the code supports five: replace, remove, append, prepend, and transform callbacks.
Consider updating to:
Each section override supports five actions:
- **`replace`** — Replace the section content entirely
- **`remove`** — Remove the section from the prompt
- **`append`** — Add content after the existing section
- **`prepend`** — Add content before the existing section
- **Transform callback** — Pass a callable `(str) -> str | Awaitable[str]` as the `action` to read and modify section content
Example with transform:
\```python
async def customize_identity(content: str) -> str:
# Log for observability
print(f"Identity section: {content}")
# Modify content
return content.replace("GitHub Copilot", "Acme Assistant")
session = await client.create_session(
system_message={
"mode": "customize",
"sections": {
"identity": {"action": customize_identity}
}
}
)
\```Add back SectionTransformFn type, _extract_transform_callbacks helper, _handle_system_message_transform handler, and systemMessage.transform RPC registration that were part of PR github#816 but lost during rebase. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Remove `copilot.types` Along the way, simplify `copilot.__init__` to only export the high-level API. * fix: reorder import statements in test_telemetry.py * fix: ruff format client.py and session.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: update PermissionHandler import path in transform test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fixes after rebase * fix: use keyword params directly in create_session/resume_session bodies Remove cfg dict intermediary and use keyword parameters directly, fixing ty type checker errors where cfg.get() returned Any | None and shadowed the typed parameter variables. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: restore system message transform support lost during rebase Add back SectionTransformFn type, _extract_transform_callbacks helper, _handle_system_message_transform handler, and systemMessage.transform RPC registration that were part of PR #816 but lost during rebase. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: restore missing SystemMessageCustomizeConfig and related types The customize mode types (SystemPromptSection, SYSTEM_PROMPT_SECTIONS, SectionOverride, SystemMessageCustomizeConfig) were dropped when types.py was deleted but not re-added to session.py. This also moves SectionTransformFn and SectionOverrideAction before SectionOverride so the definitions flow in dependency order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Steve Sanderson <SteveSandersonMS@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add fine-grained system prompt customization (customize mode)
What
Adds a new
"customize"mode forsystemMessageconfiguration across all 4 SDK languages (TypeScript, Python, Go, .NET), enabling SDK consumers to selectively override individual sections of the CLI system prompt while preserving the rest.This sits between the existing
"append"(add to the end) and"replace"(replace everything) modes, offering fine-grained control without requiring consumers to maintain entire prompt copies.10 configurable sections with 5 actions each (
replace,remove,append,prepend,transform):identitytonetool_efficiencyenvironment_contextcode_change_rulesguidelinessafetytool_instructionscustom_instructionslast_instructionsGraceful handling of unknown sections: If the runtime removes a section in a future update, content from
replace/append/prependoverrides is appended to additional instructions with a warning;removeandtransformare silently ignored.Transform support
The
transformaction enables read-then-write mutations on prompt sections. Unlike other actions which are "write-only",transformpasses the current rendered section content to a user-defined callback, and uses the callback's return value as the new content.This enables:
The transform is implemented via a
systemMessage.transformJSON-RPC callback from the runtime to the SDK, similar to how hooks are invoked. Per-section callbacks are registered locally on the session and dispatched when the runtime requests a transform. Errors in callbacks leave the original section content unchanged.Why
Addresses #215. SDK consumers need to customize agent behavior (e.g., change identity, adjust tone, remove coding rules for non-coding agents) without replacing the entire system prompt.
Changes
nodejs/src/types.ts,nodejs/src/client.ts,nodejs/src/session.ts):SystemPromptSectiontype,SectionOverride,SectionTransformFn,extractTransformCallbackshelper,systemMessage.transformRPC handlerpython/copilot/types.py,python/copilot/client.py,python/copilot/session.py): Matching types,_extract_transform_callbackshelper, RPC handler (sync+async callback support)go/types.go,go/client.go,go/session.go):SectionTransformFntype,Transformfield onSectionOverride,extractTransformCallbackshelper, RPC handlerdotnet/src/Types.cs,dotnet/src/Client.cs,dotnet/src/Session.cs):Transformdelegate onSectionOverride,ExtractTransformCallbackshelper, RPC handlergenerated_rpc.goMCP type casing mismatch, .NETSession.LogAsyncmissingurlparameterCompanion PRs
Usage example (TypeScript)