Skip to content

Add fine-grained system prompt customization (customize mode)#816

Draft
MackinnonBuck wants to merge 3 commits intomainfrom
mackinnonbuck/prompt-customization
Draft

Add fine-grained system prompt customization (customize mode)#816
MackinnonBuck wants to merge 3 commits intomainfrom
mackinnonbuck/prompt-customization

Conversation

@MackinnonBuck
Copy link
Collaborator

Add fine-grained system prompt customization (customize mode)

What

Adds a new "customize" mode for systemMessage configuration 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.

9 configurable sections with 4 actions each (replace, remove, append, prepend):

Section ID What it controls
identity Agent identity preamble and mode statement
tone Response style, conciseness rules, output formatting
tool_efficiency Tool usage patterns, parallel calling, batching
environment_context CWD, OS, git root, directory listing, available tools
code_change_rules Coding rules, linting/testing, ecosystem tools, style
guidelines Tips, behavioral best practices, conditional instructions
safety Environment limitations, prohibited actions, security policies
tool_instructions Per-tool usage instructions
custom_instructions Repository and organization custom instructions

Graceful handling of unknown sections: If the runtime removes a section in a future update, content from replace/append/prepend overrides is appended to additional instructions with a warning; remove is silently ignored.

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

  • TypeScript (nodejs/src/types.ts, nodejs/src/index.ts): SystemPromptSection type, SYSTEM_PROMPT_SECTIONS catalog, SectionOverride, SystemMessageCustomizeConfig
  • Python (python/copilot/types.py, python/copilot/__init__.py): Matching types and exports
  • Go (go/types.go): Section constants, SectionOverride struct, SystemMessageConfig fields
  • .NET (dotnet/src/Types.cs, dotnet/src/Client.cs): SystemPromptSections constants, SectionOverride, SectionOverrideAction enum
  • Docs: All 5 documentation files updated (nodejs/README.md, python/README.md, go/README.md, dotnet/README.md, docs/getting-started.md)
  • E2E test (nodejs/test/e2e/session.test.ts): Integration test for customize mode

Companion PR

Runtime changes: https://github.com/github/copilot-agent-runtime/pull/4751

Usage example (TypeScript)

const session = await client.createSession({
  systemMessage: {
    mode: "customize",
    sections: {
      identity: {
        action: "replace",
        content: "You are Finance Bot, a financial analysis assistant.\n"
      },
      tone: {
        action: "replace",
        content: "Respond in a warm, professional tone. Be thorough."
      },
      code_change_rules: { action: "remove" }
    }
  }
});

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>
@github-actions
Copy link
Contributor

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

  1. API Design - All SDKs correctly implement:

    • 9 section IDs with identical string values (identity, tone, tool_efficiency, etc.)
    • 4 action types: replace, remove, append, prepend
    • Proper naming conventions (camelCase for TS/Python, PascalCase for Go constants/.NET, snake_case for Python dict keys)
    • Graceful handling of unknown sections
  2. Type Definitions - Well-structured with language-appropriate patterns:

    • TypeScript: Union types with discriminated modes
    • Python: TypedDict with Required/NotRequired
    • Go: Unified struct with omitempty
    • .NET: Enums + Dictionary<string, SectionOverride>
  3. Export Surface - All SDKs properly export the new types (SectionOverride, SystemPromptSection/constants, SYSTEM_PROMPT_SECTIONS)


Inconsistencies to Address

1. Critical Bug: Wrong Package Name (Node.js README)

  • File: nodejs/README.md:453
  • Issue: Example shows import { ... } from "@anthropic-ai/sdk" instead of "@github/copilot-sdk"
  • Impact: Users will get import errors if they copy-paste this example
  • See inline comment for the fix

2. Documentation Gaps: Python & Go Missing Standalone Examples

  • TypeScript (nodejs/README.md): ✅ Has dedicated "Customize Mode" section with full code example
  • .NET (dotnet/README.md): ✅ Has dedicated "Customize Mode" section with full code example
  • Python (python/README.md): ❌ Only has brief inline description in parameter list (line 122-125)
  • Go (go/README.md): ❌ Only has brief inline description in parameter list (line 151-154)

Suggestion: Add standalone "Customize Mode" subsections to Python and Go READMEs similar to TypeScript/C#, showing:

  • How to import the necessary types/constants
  • A complete working example with 2-3 section overrides
  • List of available section IDs and actions

3. Testing Gap: Only Node.js Has E2E Test

  • Node.js: ✅ Has E2E test in nodejs/test/e2e/session.test.ts (validates system message contains custom tone, doesn't contain removed section)
  • Python: ❌ No E2E test for customize mode
  • Go: ❌ No E2E test for customize mode
  • .NET: ❌ No E2E test for customize mode

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

  1. Fix the import statement in nodejs/README.md (see inline comment)
  2. Add Python README example - Create a "Customize Mode" subsection with a code example showing:
    from copilot import CopilotClient, SectionOverride, SYSTEM_PROMPT_SECTIONS
    
    session = await client.create_session({
        "system_message": {
            "mode": "customize",
            "sections": {
                "tone": {"action": "replace", "content": "..."},
                "code_change_rules": {"action": "remove"},
            }
        }
    })
  3. Add Go README example - Similar subsection with Go syntax
  4. Add E2E tests for Python, Go, and .NET to match the Node.js test coverage

Summary

The 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! 🚀

Generated by SDK Consistency Review Agent for issue #816 ·

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by SDK Consistency Review Agent for issue #816

MackinnonBuck and others added 2 commits March 13, 2026 09:18
- 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>
…customization

# Conflicts:
#	nodejs/src/index.ts
#	python/copilot/__init__.py
#	python/copilot/types.py
@github-actions
Copy link
Contributor

✅ 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 Changes

Added fine-grained system prompt customization (mode: "customize") across all 4 SDK languages:

  • TypeScript (Node.js)
  • Python
  • Go
  • .NET (C#)

Consistency Verification

Section Identifiers (All identical across languages)

"identity"
"tone"
"tool_efficiency"
"environment_context"
"code_change_rules"
"guidelines"
"safety"
"tool_instructions"
"custom_instructions"

Action Names (All identical)

  • "replace" — Replace section content
  • "remove" — Remove section from prompt
  • "append" — Add content after existing section
  • "prepend" — Add content before existing section

Mode Name (Consistent)

  • "customize" across all languages

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
Documentation - All 5 docs files updated consistently (nodejs/, python/, go/, dotnet/, docs/)
E2E tests - Identical test scenarios across all 4 languages
Section constants - Exported/available for consumers in all languages:

  • TypeScript: SYSTEM_PROMPT_SECTIONS (exported)
  • Python: SYSTEM_PROMPT_SECTIONS (exported)
  • Go: Section* constants (e.g., SectionTone, SectionIdentity)
  • .NET: SystemPromptSections static class with constants

Graceful fallback behavior - Documented consistently across all languages

Verdict

No 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!

Generated by SDK Consistency Review Agent for issue #816 ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant