From 135c4aa3464acd5390b8d9123232d0676f749cea Mon Sep 17 00:00:00 2001 From: "Silent Demon SD ( MysterySD )" <105407900+SilentDemonSD@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:32:59 +0530 Subject: [PATCH 1/3] chore: update attachment types to include selection support in typescript and python --- nodejs/src/types.ts | 31 ++++++++--- python/copilot/types.py | 40 +++++++++++++-- python/test_session_events.py | 97 +++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 11 deletions(-) create mode 100644 python/test_session_events.py diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 406fe8d5..cc5e8aa8 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -497,13 +497,30 @@ export interface MessageOptions { prompt: string; /** - * File or directory attachments - */ - attachments?: Array<{ - type: "file" | "directory"; - path: string; - displayName?: string; - }>; + * File, directory, or selection attachments + */ + attachments?: Array< + | { + type: "file"; + path: string; + displayName: string; + } + | { + type: "directory"; + path: string; + displayName: string; + } + | { + type: "selection"; + filePath: string; + displayName: string; + selection?: { + start: { line: number; character: number }; + end: { line: number; character: number }; + }; + text?: string; + } + >; /** * Message delivery mode diff --git a/python/copilot/types.py b/python/copilot/types.py index bb64dd98..724d6081 100644 --- a/python/copilot/types.py +++ b/python/copilot/types.py @@ -24,11 +24,43 @@ LogLevel = Literal["none", "error", "warning", "info", "debug", "all"] -# Attachment type -class Attachment(TypedDict): - type: Literal["file", "directory"] +# Selection range for text attachments +class SelectionRange(TypedDict): + line: int + character: int + + +class Selection(TypedDict): + start: SelectionRange + end: SelectionRange + + +# Attachment types - discriminated union based on 'type' field +class FileAttachment(TypedDict): + """File attachment.""" + type: Literal["file"] path: str - displayName: NotRequired[str] + displayName: str + + +class DirectoryAttachment(TypedDict): + """Directory attachment.""" + type: Literal["directory"] + path: str + displayName: str + + +class SelectionAttachment(TypedDict): + """Selection attachment with text from a file.""" + type: Literal["selection"] + filePath: str + displayName: str + selection: NotRequired[Selection] + text: NotRequired[str] + + +# Attachment type - union of all attachment types +Attachment = Union[FileAttachment, DirectoryAttachment, SelectionAttachment] # Options for creating a CopilotClient diff --git a/python/test_session_events.py b/python/test_session_events.py new file mode 100644 index 00000000..703beb9e --- /dev/null +++ b/python/test_session_events.py @@ -0,0 +1,97 @@ +""" +Unit tests for generated session event types. + +Tests for parsing session events and their data structures from the generated +session_events.py module. +""" + + +from copilot.generated.session_events import ( + Attachment, + AttachmentType, + SessionEventType, +) + + +class TestSessionEventTypes: + """Test session event type enum values.""" + + def test_session_start_event_type(self): + """The session.start event type should be recognized.""" + assert SessionEventType.SESSION_START.value == "session.start" + + def test_session_snapshot_rewind_event_type(self): + """The session.snapshot_rewind event type should be recognized.""" + assert SessionEventType.SESSION_SNAPSHOT_REWIND.value == "session.snapshot_rewind" + + def test_session_usage_info_event_type(self): + """The session.usage_info event type should be recognized.""" + assert SessionEventType.SESSION_USAGE_INFO.value == "session.usage_info" + + +class TestAttachmentTypes: + """Test attachment type parsing from generated session_events module.""" + + def test_file_attachment_parsing(self): + """Test parsing a file attachment.""" + attachment_dict = { + "type": "file", + "path": "/path/to/file.py", + "displayName": "file.py", + } + + attachment = Attachment.from_dict(attachment_dict) + assert attachment.type == AttachmentType.FILE + assert attachment.path == "/path/to/file.py" + assert attachment.display_name == "file.py" + + def test_directory_attachment_parsing(self): + """Test parsing a directory attachment.""" + attachment_dict = { + "type": "directory", + "path": "/path/to/dir", + "displayName": "dir", + } + + attachment = Attachment.from_dict(attachment_dict) + assert attachment.type == AttachmentType.DIRECTORY + assert attachment.path == "/path/to/dir" + assert attachment.display_name == "dir" + + def test_selection_attachment_parsing(self): + """Test parsing a selection attachment with all fields.""" + attachment_dict = { + "type": "selection", + "filePath": "/path/to/file.py", + "displayName": "file.py:10-20", + "selection": { + "start": {"line": 10, "character": 0}, + "end": {"line": 20, "character": 50}, + }, + "text": "selected text content", + } + + attachment = Attachment.from_dict(attachment_dict) + assert attachment.type == AttachmentType.SELECTION + assert attachment.file_path == "/path/to/file.py" + assert attachment.display_name == "file.py:10-20" + assert attachment.selection is not None + assert attachment.selection.start.line == 10 + assert attachment.selection.start.character == 0 + assert attachment.selection.end.line == 20 + assert attachment.selection.end.character == 50 + assert attachment.text == "selected text content" + + def test_selection_attachment_minimal(self): + """Test parsing a selection attachment with only required fields.""" + attachment_dict = { + "type": "selection", + "filePath": "/path/to/file.py", + "displayName": "file.py", + } + + attachment = Attachment.from_dict(attachment_dict) + assert attachment.type == AttachmentType.SELECTION + assert attachment.file_path == "/path/to/file.py" + assert attachment.selection is None + assert attachment.text is None From d6f311adedf4306c874b8e971a949caea9fd7658 Mon Sep 17 00:00:00 2001 From: Mystery SD <105407900+SilentDemonSD@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:52:04 +0530 Subject: [PATCH 2/3] fix(nodejs/src/types.ts): allowed it to be omitted (displayName?: string) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- nodejs/src/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index cc5e8aa8..413c1aaa 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -503,12 +503,12 @@ export interface MessageOptions { | { type: "file"; path: string; - displayName: string; + displayName?: string; } | { type: "directory"; path: string; - displayName: string; + displayName?: string; } | { type: "selection"; From 6a5dfc9292488a9c61530183e46f2886d99951f4 Mon Sep 17 00:00:00 2001 From: Mystery SD <105407900+SilentDemonSD@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:53:10 +0530 Subject: [PATCH 3/3] fix(python/copilot/types.py): keep displayName optional Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- python/copilot/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/copilot/types.py b/python/copilot/types.py index 724d6081..668ffe43 100644 --- a/python/copilot/types.py +++ b/python/copilot/types.py @@ -40,14 +40,14 @@ class FileAttachment(TypedDict): """File attachment.""" type: Literal["file"] path: str - displayName: str + displayName: NotRequired[str] class DirectoryAttachment(TypedDict): """Directory attachment.""" type: Literal["directory"] path: str - displayName: str + displayName: NotRequired[str] class SelectionAttachment(TypedDict):