Skip to content

Commit 494f04d

Browse files
authored
Update Python copilot harness sample to print messages as JSONL (#40115)
1 parent f48094d commit 494f04d

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

.github/drivers/copilot_sdk_driver_sample_python.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
#!/usr/bin/env python3
22
import asyncio
3+
import json
34
import os
45
import sys
6+
from datetime import datetime, timezone
57

68
from copilot import CopilotClient, RuntimeConnection
79
from copilot.session import PermissionHandler
10+
from copilot.session_events import (
11+
AssistantMessageData,
12+
SessionEventType,
13+
ToolExecutionCompleteData,
14+
ToolExecutionStartData,
15+
)
816

917

1018
def read_required_env(name: str) -> str:
@@ -25,6 +33,16 @@ def extract_assistant_content(message: object) -> str:
2533
return ""
2634

2735

36+
def _format_timestamp(ts: datetime | None = None) -> str:
37+
now = ts or datetime.now(timezone.utc)
38+
return now.isoformat(timespec="milliseconds").replace("+00:00", "Z")
39+
40+
41+
def write_event(event_type: str, data: dict, timestamp: datetime | None = None) -> None:
42+
entry = {"type": event_type, "timestamp": _format_timestamp(timestamp), "data": data}
43+
sys.stderr.write(json.dumps(entry) + "\n")
44+
45+
2846
async def main() -> int:
2947
prompt_path = read_required_env("GH_AW_PROMPT")
3048
sdk_uri = read_required_env("COPILOT_SDK_URI")
@@ -43,6 +61,44 @@ async def main() -> int:
4361
session = None
4462
try:
4563
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=model)
64+
65+
pending_tool_calls: dict[str, dict[str, str]] = {}
66+
67+
def handle_event(event) -> None:
68+
if event.ephemeral:
69+
return
70+
71+
match event.type:
72+
case SessionEventType.USER_MESSAGE:
73+
write_event("user.message", {}, event.timestamp)
74+
75+
case SessionEventType.TOOL_EXECUTION_START:
76+
data = event.data
77+
if isinstance(data, ToolExecutionStartData):
78+
tool_name = data.tool_name or "unknown"
79+
mcp_server_name = data.mcp_server_name or ""
80+
if data.tool_call_id:
81+
pending_tool_calls[data.tool_call_id] = {"toolName": tool_name, "mcpServerName": mcp_server_name}
82+
write_event("tool.execution_start", {"toolName": tool_name, "mcpServerName": mcp_server_name}, event.timestamp)
83+
84+
case SessionEventType.TOOL_EXECUTION_COMPLETE:
85+
data = event.data
86+
if isinstance(data, ToolExecutionCompleteData):
87+
pending = pending_tool_calls.pop(data.tool_call_id, None) if data.tool_call_id else None
88+
tool_name = pending.get("toolName") if pending else None
89+
if not tool_name:
90+
tool_name = data.tool_description.name if data.tool_description else None
91+
tool_name = tool_name or "unknown"
92+
mcp_server_name = pending.get("mcpServerName", "") if pending else ""
93+
write_event("tool.execution_complete", {"toolName": tool_name, "mcpServerName": mcp_server_name, "success": data.success}, event.timestamp)
94+
95+
case SessionEventType.ASSISTANT_MESSAGE:
96+
data = event.data
97+
if isinstance(data, AssistantMessageData):
98+
write_event("assistant.message", {"content": data.content}, event.timestamp)
99+
100+
session.on(handle_event)
101+
46102
response = await session.send_and_wait(prompt)
47103
content = extract_assistant_content(response)
48104
if content:

0 commit comments

Comments
 (0)