forked from github/copilot-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_session.py
More file actions
128 lines (107 loc) · 3.62 KB
/
Copy pathtest_session.py
File metadata and controls
128 lines (107 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"""CopilotSession unit tests."""
import asyncio
from datetime import UTC, datetime
from unittest.mock import AsyncMock, Mock
from uuid import uuid4
import pytest
from copilot.session import CopilotSession
from copilot.session_events import (
AssistantMessageData,
ExternalToolCompletedData,
ExternalToolRequestedData,
SessionEvent,
SessionEventType,
SessionIdleData,
SessionMode,
)
from copilot.tools import Tool, ToolResult
def _event(data, event_type: SessionEventType) -> SessionEvent:
return SessionEvent(
data=data,
id=uuid4(),
timestamp=datetime.now(UTC),
type=event_type,
)
@pytest.mark.asyncio
async def test_send_and_wait_skips_autopilot_continuation_idle():
client = Mock()
client.request = AsyncMock(return_value={"messageId": "message-1"})
session = CopilotSession("session-1", client)
pending = asyncio.create_task(session.send_and_wait("keep going"))
await asyncio.sleep(0)
client.request.assert_awaited_once()
session._dispatch_event(
_event(
AssistantMessageData(content="intermediate", message_id="assistant-1"),
SessionEventType.ASSISTANT_MESSAGE,
)
)
session._dispatch_event(
_event(
SessionIdleData(mode=SessionMode.AUTOPILOT),
SessionEventType.SESSION_IDLE,
)
)
assert not pending.done()
session._dispatch_event(
_event(
AssistantMessageData(content="final", message_id="assistant-2"),
SessionEventType.ASSISTANT_MESSAGE,
)
)
session._dispatch_event(
_event(
SessionIdleData(mode=SessionMode.INTERACTIVE),
SessionEventType.SESSION_IDLE,
)
)
result = await asyncio.wait_for(pending, timeout=1)
assert result is not None
assert isinstance(result.data, AssistantMessageData)
assert result.data.content == "final"
@pytest.mark.asyncio
async def test_external_tool_completed_cancels_blocked_handler():
client = Mock()
client.request = AsyncMock()
session = CopilotSession("session-1", client)
started = asyncio.Event()
cancelled = asyncio.Event()
async def blocked_tool(_invocation):
started.set()
try:
await asyncio.Future()
except asyncio.CancelledError:
cancelled.set()
return ToolResult(text_result_for_llm="late result")
session._register_tools([Tool("blocked_tool", "Blocks", blocked_tool)])
session._dispatch_event(
_event(
ExternalToolRequestedData(
request_id="request-1",
session_id="session-1",
tool_call_id="tool-call-1",
tool_name="blocked_tool",
),
SessionEventType.EXTERNAL_TOOL_REQUESTED,
)
)
await asyncio.wait_for(started.wait(), timeout=1)
session._dispatch_event(
_event(
ExternalToolCompletedData(request_id="request-1"),
SessionEventType.EXTERNAL_TOOL_COMPLETED,
)
)
await asyncio.wait_for(cancelled.wait(), timeout=1)
await asyncio.sleep(0)
client.request.assert_not_awaited()
@pytest.mark.asyncio
async def test_disconnect_from_tool_task_does_not_cancel_detach_request():
client = Mock()
client.request = AsyncMock(return_value={"success": True})
session = CopilotSession("session-1", client)
current_task = asyncio.current_task()
assert current_task is not None
session._pending_external_tools["request-1"] = current_task
await session.disconnect()
client.request.assert_awaited_once_with("session.detach", {"sessionId": "session-1"})