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
43 changes: 43 additions & 0 deletions dotnet/test/E2E/SystemMessageSectionsE2ETests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

using GitHub.Copilot.Rpc;
using GitHub.Copilot.Test.Harness;
using Xunit;
using Xunit.Abstractions;

namespace GitHub.Copilot.Test.E2E;

public class SystemMessageSectionsE2ETests(E2ETestFixture fixture, ITestOutputHelper output) : E2ETestBase(fixture, "system_message_sections", output)
{
[Fact]
public async Task Should_Use_Replaced_Identity_Section_In_Response()
{
var session = await CreateSessionAsync(new SessionConfig
{
OnPermissionRequest = PermissionHandler.ApproveAll,
SystemMessage = new SystemMessageConfig
{
Mode = SystemMessageMode.Customize,
Sections = new Dictionary<SystemMessageSection, SectionOverride>
{
[SystemMessageSection.Identity] = new SectionOverride
{
Action = SectionOverrideAction.Replace,
Content = "You are a helpful gardening assistant called Botanica. You only answer questions about plants and gardening."
}
}
}
});

await session.SendAsync(new MessageOptions { Prompt = "Who are you?" });
var response = await TestHelper.GetFinalAssistantMessageAsync(session);

Assert.NotNull(response);
var content = response.Data.Content.ToLowerInvariant();
Assert.True(
content.Contains("botanica") || content.Contains("garden") || content.Contains("plant"),
$"Expected response to reflect the replaced identity section, but got: {response.Data.Content}");
}
}
57 changes: 57 additions & 0 deletions go/internal/e2e/system_message_sections_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package e2e

import (
"strings"
"testing"

copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/internal/e2e/testharness"
)

func TestSystemMessageSectionsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })

t.Run("should_use_replaced_identity_section_in_response", func(t *testing.T) {
ctx.ConfigureForTest(t)

session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
SystemMessage: &copilot.SystemMessageConfig{
Mode: "customize",
Sections: map[string]copilot.SectionOverride{
"identity": {
Action: copilot.SectionActionReplace,
Content: "You are a helpful gardening assistant called Botanica. You only answer questions about plants and gardening.",
},
},
},
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
}

response, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "Who are you?",
})
if err != nil {
t.Fatalf("Failed to send message: %v", err)
}
if response == nil {
t.Fatal("Expected a response from the assistant")
}

ad, ok := response.Data.(*copilot.AssistantMessageData)
if !ok {
t.Fatalf("Expected AssistantMessageData, got %T", response.Data)
}
content := strings.ToLower(ad.Content)
if !strings.Contains(content, "botanica") && !strings.Contains(content, "garden") && !strings.Contains(content, "plant") {
t.Errorf("Expected response to reflect the replaced identity section, but got: %s", ad.Content)
}
})
}
38 changes: 38 additions & 0 deletions nodejs/test/e2e/system_message_sections.e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

import { describe, expect, it } from "vitest";
import { approveAll } from "../../src/index.js";
import { createSdkTestContext } from "./harness/sdkTestContext.js";

describe("System message sections", async () => {
const { copilotClient: client } = await createSdkTestContext();

it("should_use_replaced_identity_section_in_response", async () => {
const session = await client.createSession({
onPermissionRequest: approveAll,
systemMessage: {
mode: "customize",
sections: {
identity: {
action: "replace",
content:
"You are a helpful gardening assistant called Botanica. You only answer questions about plants and gardening.",
},
},
},
});

const response = await session.sendAndWait({ prompt: "Who are you?" });

expect(response).not.toBeNull();
const content = response!.data.content.toLowerCase();
expect(
content.includes("botanica") || content.includes("garden") || content.includes("plant"),
`Expected response to reflect the replaced identity section, but got: ${response!.data.content}`
).toBe(true);

await session.disconnect();
});
});
44 changes: 44 additions & 0 deletions python/e2e/test_system_message_sections_e2e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
Copyright (c) Microsoft Corporation.

Tests for system message sections functionality
"""

import pytest

from copilot.session import PermissionHandler

from .testharness import E2ETestContext

pytestmark = pytest.mark.asyncio(loop_scope="module")


class TestSystemMessageSections:
async def test_should_use_replaced_identity_section_in_response(self, ctx: E2ETestContext):
"""Test that replacing the identity section causes the assistant to adopt a new persona"""
session = await ctx.client.create_session(
system_message={
"mode": "customize",
"sections": {
"identity": {
"action": "replace",
"content": (
"You are a helpful gardening assistant called Botanica."
" You only answer questions about plants and gardening."
),
},
},
},
on_permission_request=PermissionHandler.approve_all,
)

response = await session.send_and_wait("Who are you?")

assert response is not None, "Expected a response from the assistant"
content = response.data.content.lower()
assert "botanica" in content or "garden" in content or "plant" in content, (
f"Expected response to reflect the replaced identity section,"
f" but got: {response.data.content}"
)

await session.disconnect()
2 changes: 2 additions & 0 deletions rust/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ mod subagent_hooks;
mod support;
#[path = "e2e/suspend.rs"]
mod suspend;
#[path = "e2e/system_message_sections.rs"]
mod system_message_sections;
#[path = "e2e/system_message_transform.rs"]
mod system_message_transform;
#[path = "e2e/telemetry.rs"]
Expand Down
59 changes: 59 additions & 0 deletions rust/tests/e2e/system_message_sections.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::collections::HashMap;

use github_copilot_sdk::{SectionOverride, SystemMessageConfig};

use super::support::{assistant_message_content, with_e2e_context};

#[tokio::test]
async fn should_use_replaced_identity_section_in_response() {
with_e2e_context(
"system_message_sections",
"should_use_replaced_identity_section_in_response",
|ctx| {
Box::pin(async move {
ctx.set_default_copilot_user();
let mut sections = HashMap::new();
sections.insert(
"identity".to_string(),
SectionOverride {
action: Some("replace".to_string()),
content: Some(
"You are a helpful gardening assistant called Botanica. \
You only answer questions about plants and gardening."
.to_string(),
),
},
);
let client = ctx.start_client().await;
let session = client
.create_session(
ctx.approve_all_session_config().with_system_message(
SystemMessageConfig::new()
.with_mode("customize")
.with_sections(sections),
),
)
.await
.expect("create session");

let answer = session
.send_and_wait("Who are you?")
.await
.expect("send")
.expect("assistant message");
let content = assistant_message_content(&answer).to_lowercase();
assert!(
content.contains("botanica")
|| content.contains("garden")
|| content.contains("plant"),
"Expected response to reflect the replaced identity section, but got: {}",
assistant_message_content(&answer)
);

session.disconnect().await.expect("disconnect session");
client.stop().await.expect("stop client");
})
},
)
.await;
}
Loading