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
9 changes: 7 additions & 2 deletions dotnet/test/SessionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public async Task Should_Pass_Streaming_Option_To_Session_Creation()
}

[Fact]
public async Task Should_SessionEvt_Subscribed()
public async Task Should_Receive_Session_Events()
{
var session = await Client.CreateSessionAsync();
var receivedEvents = new List<SessionEvent>();
Expand All @@ -303,7 +303,7 @@ public async Task Should_SessionEvt_Subscribed()
});

// Send a message to trigger events
await session.SendAsync(new MessageOptions { Prompt = "Hello!" });
await session.SendAsync(new MessageOptions { Prompt = "What is 100+200?" });

// Wait for session to become idle (indicating message processing is complete)
var completed = await Task.WhenAny(idleReceived.Task, Task.Delay(TimeSpan.FromSeconds(60)));
Expand All @@ -315,6 +315,11 @@ public async Task Should_SessionEvt_Subscribed()
Assert.Contains(receivedEvents, evt => evt is AssistantMessageEvent);
Assert.Contains(receivedEvents, evt => evt is SessionIdleEvent);

// Verify the assistant response contains the expected answer
var assistantMessage = await TestHelper.GetFinalAssistantMessageAsync(session);
Assert.NotNull(assistantMessage);
Assert.Contains("300", assistantMessage!.Data.Content);

await session.DisposeAsync();
}
}
73 changes: 73 additions & 0 deletions go/e2e/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,79 @@ func TestSession(t *testing.T) {
t.Errorf("Expected assistant message to contain '2', got %v", assistantMessage.Data.Content)
}
})

t.Run("should receive session events", func(t *testing.T) {
ctx.ConfigureForTest(t)

session, err := client.CreateSession(nil)
if err != nil {
t.Fatalf("Failed to create session: %v", err)
}

var receivedEvents []copilot.SessionEvent
idle := make(chan bool)

session.On(func(event copilot.SessionEvent) {
receivedEvents = append(receivedEvents, event)
if event.Type == "session.idle" {
select {
case idle <- true:
default:
}
}
})

// Send a message to trigger events
_, err = session.Send(copilot.MessageOptions{Prompt: "What is 100+200?"})
if err != nil {
t.Fatalf("Failed to send message: %v", err)
}

// Wait for session to become idle
select {
case <-idle:
case <-time.After(60 * time.Second):
t.Fatal("Timed out waiting for session.idle")
}

// Should have received multiple events
if len(receivedEvents) == 0 {
t.Error("Expected to receive events, got none")
}

hasUserMessage := false
hasAssistantMessage := false
hasSessionIdle := false
for _, evt := range receivedEvents {
switch evt.Type {
case "user.message":
hasUserMessage = true
case "assistant.message":
hasAssistantMessage = true
case "session.idle":
hasSessionIdle = true
}
}

if !hasUserMessage {
t.Error("Expected to receive user.message event")
}
if !hasAssistantMessage {
t.Error("Expected to receive assistant.message event")
}
if !hasSessionIdle {
t.Error("Expected to receive session.idle event")
}

// Verify the assistant response contains the expected answer
assistantMessage, err := testharness.GetFinalAssistantMessage(session, 60*time.Second)
if err != nil {
t.Fatalf("Failed to get assistant message: %v", err)
}
if assistantMessage.Data.Content == nil || !strings.Contains(*assistantMessage.Data.Content, "300") {
t.Errorf("Expected assistant message to contain '300', got %v", assistantMessage.Data.Content)
}
})
}

func getSystemMessage(exchange testharness.ParsedHttpExchange) string {
Expand Down
35 changes: 35 additions & 0 deletions nodejs/test/e2e/session.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,41 @@ describe("Sessions", async () => {
const assistantMessage = await getFinalAssistantMessage(session);
expect(assistantMessage.data.content).toContain("2");
});

it("should receive session events", async () => {
const session = await client.createSession();
const receivedEvents: Array<{ type: string }> = [];
let idleResolve: () => void;
const idlePromise = new Promise<void>((resolve) => {
idleResolve = resolve;
});

session.on((event) => {
receivedEvents.push(event);
if (event.type === "session.idle") {
idleResolve();
}
});

// Send a message to trigger events
await session.send({ prompt: "What is 100+200?" });

// Wait for session to become idle
await Promise.race([
idlePromise,
new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), 60000)),
]);

// Should have received multiple events
expect(receivedEvents.length).toBeGreaterThan(0);
expect(receivedEvents.some((e) => e.type === "user.message")).toBe(true);
expect(receivedEvents.some((e) => e.type === "assistant.message")).toBe(true);
expect(receivedEvents.some((e) => e.type === "session.idle")).toBe(true);

// Verify the assistant response contains the expected answer
const assistantMessage = await getFinalAssistantMessage(session);
expect(assistantMessage.data.content).toContain("300");
});
});

function getSystemMessage(exchange: ParsedHttpExchange): string | undefined {
Expand Down
34 changes: 34 additions & 0 deletions python/e2e/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,40 @@ async def test_should_pass_streaming_option_to_session_creation(self, ctx: E2ETe
assistant_message = await get_final_assistant_message(session)
assert "2" in assistant_message.data.content

async def test_should_receive_session_events(self, ctx: E2ETestContext):
import asyncio

session = await ctx.client.create_session()
received_events = []
idle_event = asyncio.Event()

def on_event(event):
received_events.append(event)
if event.type.value == "session.idle":
idle_event.set()

session.on(on_event)

# Send a message to trigger events
await session.send({"prompt": "What is 100+200?"})

# Wait for session to become idle
try:
await asyncio.wait_for(idle_event.wait(), timeout=60)
except asyncio.TimeoutError:
pytest.fail("Timed out waiting for session.idle")

# Should have received multiple events
assert len(received_events) > 0
event_types = [e.type.value for e in received_events]
assert "user.message" in event_types
assert "assistant.message" in event_types
assert "session.idle" in event_types

# Verify the assistant response contains the expected answer
assistant_message = await get_final_assistant_message(session)
assert "300" in assistant_message.data.content


def _get_system_message(exchange: dict) -> str:
messages = exchange.get("request", {}).get("messages", [])
Expand Down
10 changes: 10 additions & 0 deletions test/snapshots/session/should_receive_session_events.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
models:
- claude-sonnet-4.5
conversations:
- messages:
- role: system
content: ${system}
- role: user
content: What is 100+200?
- role: assistant
content: 100 + 200 = 300
Loading