agent-framework-github-copilot 1.0.2__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_framework_github_copilot/_agent.py +178 -15
- {agent_framework_github_copilot-1.0.2.dist-info → agent_framework_github_copilot-2.0.0.dist-info}/METADATA +32 -3
- agent_framework_github_copilot-2.0.0.dist-info/RECORD +7 -0
- agent_framework_github_copilot-1.0.2.dist-info/RECORD +0 -7
- {agent_framework_github_copilot-1.0.2.dist-info → agent_framework_github_copilot-2.0.0.dist-info}/WHEEL +0 -0
- {agent_framework_github_copilot-1.0.2.dist-info → agent_framework_github_copilot-2.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,10 +5,12 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import contextlib
|
|
7
7
|
import inspect
|
|
8
|
+
import json
|
|
8
9
|
import logging
|
|
9
10
|
import sys
|
|
10
11
|
import warnings
|
|
11
12
|
from collections.abc import AsyncIterable, Awaitable, Callable, Mapping, MutableMapping, Sequence
|
|
13
|
+
from pathlib import Path
|
|
12
14
|
from typing import Any, ClassVar, Generic, Literal, TypedDict, cast, overload
|
|
13
15
|
from urllib.parse import urlparse
|
|
14
16
|
|
|
@@ -29,6 +31,7 @@ from agent_framework import (
|
|
|
29
31
|
add_usage_details,
|
|
30
32
|
normalize_messages,
|
|
31
33
|
)
|
|
34
|
+
from agent_framework._mcp import MCPTool
|
|
32
35
|
from agent_framework._settings import load_settings
|
|
33
36
|
from agent_framework._telemetry import mark_feature_used
|
|
34
37
|
from agent_framework._tools import FunctionTool, ToolTypes
|
|
@@ -52,7 +55,12 @@ else:
|
|
|
52
55
|
from typing_extensions import TypeVar # pragma: no cover
|
|
53
56
|
|
|
54
57
|
try:
|
|
55
|
-
from copilot import
|
|
58
|
+
from copilot import (
|
|
59
|
+
CopilotClient,
|
|
60
|
+
CopilotSession,
|
|
61
|
+
RuntimeConnection,
|
|
62
|
+
TelemetryConfig,
|
|
63
|
+
)
|
|
56
64
|
from copilot.generated.rpc import (
|
|
57
65
|
PermissionDecisionApproveForSession,
|
|
58
66
|
PermissionDecisionApproveForSessionApproval,
|
|
@@ -71,6 +79,7 @@ try:
|
|
|
71
79
|
Attachment,
|
|
72
80
|
BlobAttachment,
|
|
73
81
|
MCPServerConfig,
|
|
82
|
+
PermissionInvocation,
|
|
74
83
|
PermissionRequestResult,
|
|
75
84
|
PreToolUseHandler,
|
|
76
85
|
PreToolUseHookOutput,
|
|
@@ -104,14 +113,24 @@ except ImportError as _copilot_import_error:
|
|
|
104
113
|
DEFAULT_TIMEOUT_SECONDS: float = 60.0
|
|
105
114
|
"""Default timeout in seconds for Copilot requests."""
|
|
106
115
|
|
|
116
|
+
_PermissionHandlerContext = Any
|
|
117
|
+
"""Compatibility context accepted by permission handlers across SDK versions."""
|
|
118
|
+
|
|
107
119
|
PermissionHandlerType = Callable[
|
|
108
|
-
[PermissionRequest,
|
|
120
|
+
[PermissionRequest, _PermissionHandlerContext],
|
|
121
|
+
"PermissionRequestResult | Awaitable[PermissionRequestResult]",
|
|
109
122
|
]
|
|
110
123
|
"""Type for permission request handlers. Supports both sync and async callbacks."""
|
|
111
124
|
|
|
112
|
-
AsyncPermissionHandlerType = Callable[
|
|
125
|
+
AsyncPermissionHandlerType = Callable[
|
|
126
|
+
[PermissionRequest, _PermissionHandlerContext], "Awaitable[PermissionRequestResult]"
|
|
127
|
+
]
|
|
113
128
|
"""Type for permission request handlers that are always asynchronous."""
|
|
114
129
|
|
|
130
|
+
_SdkAsyncPermissionHandlerType = Callable[
|
|
131
|
+
[PermissionRequest, PermissionInvocation], "Awaitable[PermissionRequestResult]"
|
|
132
|
+
]
|
|
133
|
+
|
|
115
134
|
|
|
116
135
|
FunctionApprovalCallback = Callable[[Content], "bool | Awaitable[bool]"]
|
|
117
136
|
"""Deprecated approval callback for ``FunctionTool`` instances declared with
|
|
@@ -162,10 +181,26 @@ async def _resolve_function_approval(
|
|
|
162
181
|
|
|
163
182
|
logger = logging.getLogger("agent_framework.github_copilot")
|
|
164
183
|
|
|
184
|
+
_MCP_TOOL_MESSAGE = (
|
|
185
|
+
"MCP server '{name}' cannot be passed to GitHubCopilotAgent as a tool: the Copilot SDK "
|
|
186
|
+
"connects to MCP servers itself, so a framework-managed MCPTool would keep none of its "
|
|
187
|
+
"framework behavior. Configure the server natively instead, for example "
|
|
188
|
+
"default_options={{'mcp_servers': {{'{name}': {{'type': 'stdio', 'command': 'python', "
|
|
189
|
+
"'args': ['server.py'], 'tools': ['*']}}}}}}, or use a ChatAgent, where the framework owns "
|
|
190
|
+
"the connection."
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _reject_mcp_tools(tools: Sequence[Any]) -> None:
|
|
195
|
+
"""Refuse MCP servers handed in as tools, from whichever option carried them."""
|
|
196
|
+
for tool in tools:
|
|
197
|
+
if isinstance(tool, MCPTool):
|
|
198
|
+
raise TypeError(_MCP_TOOL_MESSAGE.format(name=tool.name))
|
|
199
|
+
|
|
165
200
|
|
|
166
201
|
def _deny_all_permissions(
|
|
167
202
|
_request: PermissionRequest,
|
|
168
|
-
_invocation:
|
|
203
|
+
_invocation: _PermissionHandlerContext,
|
|
169
204
|
) -> PermissionRequestResult:
|
|
170
205
|
"""Default permission handler that denies all requests."""
|
|
171
206
|
return PermissionDecisionUserNotAvailable()
|
|
@@ -316,7 +351,7 @@ def _normalize_permission_decision(
|
|
|
316
351
|
return PermissionDecisionApproveForSession(approval=approval)
|
|
317
352
|
|
|
318
353
|
|
|
319
|
-
def _with_normalized_permission_decisions(handler: PermissionHandlerType) ->
|
|
354
|
+
def _with_normalized_permission_decisions(handler: PermissionHandlerType) -> _SdkAsyncPermissionHandlerType:
|
|
320
355
|
"""Wrap a permission handler so its decisions are normalized before reaching the SDK.
|
|
321
356
|
|
|
322
357
|
Exceptions raised by ``handler`` deliberately propagate: the SDK already catches them
|
|
@@ -329,8 +364,10 @@ def _with_normalized_permission_decisions(handler: PermissionHandlerType) -> Asy
|
|
|
329
364
|
An async handler delegating to ``handler`` and normalizing its result.
|
|
330
365
|
"""
|
|
331
366
|
|
|
332
|
-
async def normalized_handler(
|
|
333
|
-
|
|
367
|
+
async def normalized_handler(
|
|
368
|
+
request: PermissionRequest, invocation: PermissionInvocation
|
|
369
|
+
) -> PermissionRequestResult:
|
|
370
|
+
result = handler(request, cast(PermissionInvocation, dict(invocation)))
|
|
334
371
|
if inspect.isawaitable(result):
|
|
335
372
|
result = await result
|
|
336
373
|
return _normalize_permission_decision(result, request)
|
|
@@ -338,6 +375,65 @@ def _with_normalized_permission_decisions(handler: PermissionHandlerType) -> Asy
|
|
|
338
375
|
return normalized_handler
|
|
339
376
|
|
|
340
377
|
|
|
378
|
+
def _parse_telemetry_config(raw: str) -> TelemetryConfig | None:
|
|
379
|
+
# GITHUB_COPILOT_TELEMETRY and matching .env values are read as plain strings while the
|
|
380
|
+
# Copilot SDK expects a mapping, so parse here before the value reaches CopilotClient.
|
|
381
|
+
# Malformed values are logged and ignored so a bad telemetry setting cannot prevent the
|
|
382
|
+
# agent from starting.
|
|
383
|
+
try:
|
|
384
|
+
parsed = json.loads(raw)
|
|
385
|
+
except json.JSONDecodeError:
|
|
386
|
+
logger.warning(
|
|
387
|
+
"Ignoring malformed GITHUB_COPILOT_TELEMETRY value; expected a JSON object with TelemetryConfig keys."
|
|
388
|
+
)
|
|
389
|
+
return None
|
|
390
|
+
if not isinstance(parsed, dict):
|
|
391
|
+
logger.warning(
|
|
392
|
+
"Ignoring invalid GITHUB_COPILOT_TELEMETRY value; expected a JSON object with TelemetryConfig keys."
|
|
393
|
+
)
|
|
394
|
+
return None
|
|
395
|
+
return cast(TelemetryConfig, parsed)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _client_working_directory(client: CopilotClient | None) -> str | None:
|
|
399
|
+
"""Best-effort read of the working directory an injected client configured.
|
|
400
|
+
|
|
401
|
+
A client created with ``CopilotClient(working_directory=...)`` spawns the CLI process
|
|
402
|
+
in that directory, so the CLI resolves ``.github/hooks/`` relative to it rather than to
|
|
403
|
+
this process. The SDK keeps the value on a private options object, so this is read
|
|
404
|
+
defensively: if the attribute ever moves, hook detection falls back to the process
|
|
405
|
+
working directory instead of failing.
|
|
406
|
+
"""
|
|
407
|
+
options = getattr(client, "_options", None)
|
|
408
|
+
working_directory = getattr(options, "working_directory", None)
|
|
409
|
+
return working_directory if isinstance(working_directory, str) else None
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _resolve_effective_working_directory(session_working_directory: str | None, client: CopilotClient | None) -> Path:
|
|
413
|
+
"""Resolve the directory the CLI will treat as the workspace, mirroring the SDK.
|
|
414
|
+
|
|
415
|
+
The SDK resolves in this order: the session's ``working_directory`` when supplied,
|
|
416
|
+
otherwise the CLI process's own directory, which is the injected client's configured
|
|
417
|
+
``working_directory`` when it set one and this process's directory otherwise.
|
|
418
|
+
"""
|
|
419
|
+
if session_working_directory:
|
|
420
|
+
return Path(session_working_directory)
|
|
421
|
+
client_working_directory = _client_working_directory(client)
|
|
422
|
+
if client_working_directory:
|
|
423
|
+
return Path(client_working_directory)
|
|
424
|
+
return Path.cwd()
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def _has_file_hooks(working_directory: Path) -> bool:
|
|
428
|
+
"""Return whether ``.github/hooks/`` holds hook definitions the CLI would otherwise load."""
|
|
429
|
+
try:
|
|
430
|
+
return any((working_directory / ".github" / "hooks").iterdir())
|
|
431
|
+
except OSError:
|
|
432
|
+
# Missing directory, unreadable path, or a file where the directory would be:
|
|
433
|
+
# there is nothing the caller needs to know about.
|
|
434
|
+
return False
|
|
435
|
+
|
|
436
|
+
|
|
341
437
|
class GitHubCopilotSettings(TypedDict, total=False):
|
|
342
438
|
"""GitHub Copilot model settings.
|
|
343
439
|
|
|
@@ -359,6 +455,10 @@ class GitHubCopilotSettings(TypedDict, total=False):
|
|
|
359
455
|
GITHUB_COPILOT_BASE_DIRECTORY. Defaults to ~/.copilot when not set.
|
|
360
456
|
Only applicable when the SDK spawns the CLI process (ignored when
|
|
361
457
|
connecting to an external server via a pre-configured client).
|
|
458
|
+
telemetry: OpenTelemetry configuration for the Copilot CLI process. This is
|
|
459
|
+
passed to the SDK client when it is created by the agent. Values coming
|
|
460
|
+
from GITHUB_COPILOT_TELEMETRY or a .env file arrive as a JSON string and
|
|
461
|
+
are parsed into a mapping before they reach the SDK.
|
|
362
462
|
"""
|
|
363
463
|
|
|
364
464
|
cli_path: str | None
|
|
@@ -366,6 +466,7 @@ class GitHubCopilotSettings(TypedDict, total=False):
|
|
|
366
466
|
timeout: float | None
|
|
367
467
|
log_level: str | None
|
|
368
468
|
base_directory: str | None
|
|
469
|
+
telemetry: dict[str, Any] | str | None
|
|
369
470
|
|
|
370
471
|
|
|
371
472
|
class GitHubCopilotOptions(TypedDict, total=False):
|
|
@@ -437,6 +538,17 @@ class GitHubCopilotOptions(TypedDict, total=False):
|
|
|
437
538
|
base_directory: str
|
|
438
539
|
"""Directory where the CLI stores session state, configuration, and other persistent data."""
|
|
439
540
|
|
|
541
|
+
enable_file_hooks: bool
|
|
542
|
+
"""Whether the CLI loads file hooks from the working directory's ``.github/hooks/``.
|
|
543
|
+
|
|
544
|
+
Defaults to ``False``: hook definitions checked into the working directory are ignored
|
|
545
|
+
unless you opt in, so a session behaves the same way regardless of which checkout it
|
|
546
|
+
runs in. Unrelated to the SDK callback hooks configured through ``on_pre_tool_use``.
|
|
547
|
+
"""
|
|
548
|
+
|
|
549
|
+
telemetry: TelemetryConfig
|
|
550
|
+
"""OpenTelemetry configuration for the Copilot CLI process."""
|
|
551
|
+
|
|
440
552
|
on_pre_tool_use: PreToolUseHandler
|
|
441
553
|
"""Pre-tool-use hook handler for the Copilot SDK.
|
|
442
554
|
|
|
@@ -574,6 +686,7 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
574
686
|
on_pre_tool_use: PreToolUseHandler | None = opts.pop("on_pre_tool_use", None)
|
|
575
687
|
on_function_approval: FunctionApprovalCallback | None = opts.pop("on_function_approval", None)
|
|
576
688
|
base_directory = opts.pop("base_directory", None)
|
|
689
|
+
telemetry = opts.pop("telemetry", None)
|
|
577
690
|
|
|
578
691
|
if on_function_approval is not None and on_pre_tool_use is not None:
|
|
579
692
|
raise ValueError(
|
|
@@ -600,11 +713,13 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
600
713
|
timeout=timeout,
|
|
601
714
|
log_level=log_level,
|
|
602
715
|
base_directory=base_directory,
|
|
716
|
+
telemetry=telemetry,
|
|
603
717
|
env_file_path=env_file_path,
|
|
604
718
|
env_file_encoding=env_file_encoding,
|
|
605
719
|
)
|
|
606
720
|
|
|
607
721
|
self._tools = normalize_tools(tools)
|
|
722
|
+
_reject_mcp_tools(self._tools)
|
|
608
723
|
self._permission_handler = on_permission_request
|
|
609
724
|
self._on_pre_tool_use: PreToolUseHandler | None = on_pre_tool_use
|
|
610
725
|
self._function_approval_handler: FunctionApprovalCallback | None = on_function_approval
|
|
@@ -613,6 +728,7 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
613
728
|
# are forwarded verbatim to the Copilot SDK by _build_session_kwargs.
|
|
614
729
|
self._default_options = opts
|
|
615
730
|
self._started = False
|
|
731
|
+
self._file_hooks_warning_emitted = False
|
|
616
732
|
|
|
617
733
|
async def __aenter__(self) -> Self:
|
|
618
734
|
"""Start the agent when entering async context."""
|
|
@@ -640,6 +756,9 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
640
756
|
cli_path = self._settings.get("cli_path") or None
|
|
641
757
|
log_level = self._settings.get("log_level") or None
|
|
642
758
|
base_directory = self._settings.get("base_directory") or None
|
|
759
|
+
telemetry = self._settings.get("telemetry") or None
|
|
760
|
+
if isinstance(telemetry, str):
|
|
761
|
+
telemetry = _parse_telemetry_config(telemetry)
|
|
643
762
|
|
|
644
763
|
client_kwargs: dict[str, Any] = {}
|
|
645
764
|
if cli_path:
|
|
@@ -648,6 +767,8 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
648
767
|
client_kwargs["log_level"] = log_level
|
|
649
768
|
if base_directory:
|
|
650
769
|
client_kwargs["base_directory"] = base_directory
|
|
770
|
+
if telemetry:
|
|
771
|
+
client_kwargs["telemetry"] = telemetry
|
|
651
772
|
self._client = CopilotClient(**client_kwargs)
|
|
652
773
|
|
|
653
774
|
try:
|
|
@@ -1387,6 +1508,27 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
1387
1508
|
except Exception as ex:
|
|
1388
1509
|
raise AgentException(f"Failed to create GitHub Copilot session: {ex}") from ex
|
|
1389
1510
|
|
|
1511
|
+
def _warn_once_about_unloaded_file_hooks(self, session_working_directory: str | None) -> None:
|
|
1512
|
+
"""Warn once when the effective working directory defines file hooks that will not run.
|
|
1513
|
+
|
|
1514
|
+
Without this the default is silent: hooks simply stop running, with nothing to
|
|
1515
|
+
point at the cause. The warning fires at most once per agent so a long-lived agent
|
|
1516
|
+
does not repeat it on every run.
|
|
1517
|
+
"""
|
|
1518
|
+
if self._file_hooks_warning_emitted:
|
|
1519
|
+
return
|
|
1520
|
+
working_directory = _resolve_effective_working_directory(session_working_directory, self._client)
|
|
1521
|
+
if not _has_file_hooks(working_directory):
|
|
1522
|
+
return
|
|
1523
|
+
self._file_hooks_warning_emitted = True
|
|
1524
|
+
logger.warning(
|
|
1525
|
+
"Not loading the file hooks defined in '%s': GitHubCopilotAgent leaves "
|
|
1526
|
+
"enable_file_hooks off so a session behaves the same way in every working "
|
|
1527
|
+
"directory. Set enable_file_hooks=True in default_options (or in per-run "
|
|
1528
|
+
"options) to run them.",
|
|
1529
|
+
working_directory / ".github" / "hooks",
|
|
1530
|
+
)
|
|
1531
|
+
|
|
1390
1532
|
def _build_session_kwargs(
|
|
1391
1533
|
self,
|
|
1392
1534
|
streaming: bool,
|
|
@@ -1398,11 +1540,12 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
1398
1540
|
``runtime_options`` which override them. Every key is forwarded verbatim to
|
|
1399
1541
|
the Copilot SDK, so any ``create_session`` parameter is supported without a
|
|
1400
1542
|
dedicated mapping here (an unknown name surfaces as a ``TypeError`` from the
|
|
1401
|
-
SDK). A few keys are handled specially because they need a
|
|
1402
|
-
|
|
1403
|
-
under-specified ``approve-for-session`` decisions are scoped to the
|
|
1404
|
-
triggered them
|
|
1405
|
-
converted to SDK tools, and approval callbacks
|
|
1543
|
+
SDK). A few keys are handled specially because they need a specific default or
|
|
1544
|
+
transforming: ``on_permission_request`` defaults to denying all requests and is
|
|
1545
|
+
wrapped so under-specified ``approve-for-session`` decisions are scoped to the
|
|
1546
|
+
request that triggered them, ``enable_file_hooks`` defaults to off, ``tools`` are
|
|
1547
|
+
merged with the agent's tools and converted to SDK tools, and approval callbacks
|
|
1548
|
+
are turned into ``hooks``.
|
|
1406
1549
|
|
|
1407
1550
|
Args:
|
|
1408
1551
|
streaming: Whether to enable streaming for the session.
|
|
@@ -1418,7 +1561,10 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
1418
1561
|
|
|
1419
1562
|
# Merge agent-level tools with any caller-supplied tools (from default_options
|
|
1420
1563
|
# or per-run options, the latter winning) and convert to SDK tools.
|
|
1421
|
-
|
|
1564
|
+
# Normalize the option-supplied tools the way the constructor does: it converts callables
|
|
1565
|
+
# and flattens tool-collection wrappers, which can otherwise hide an MCPTool.
|
|
1566
|
+
all_tools = normalize_tools(list(self._tools or []) + list(kwargs.get("tools") or []))
|
|
1567
|
+
_reject_mcp_tools(all_tools)
|
|
1422
1568
|
kwargs["tools"] = self._prepare_tools(all_tools) if all_tools else None
|
|
1423
1569
|
|
|
1424
1570
|
kwargs["streaming"] = streaming
|
|
@@ -1427,14 +1573,31 @@ class RawGitHubCopilotAgent(BaseAgent, Generic[OptionsT]):
|
|
|
1427
1573
|
if not kwargs.get("model"):
|
|
1428
1574
|
kwargs["model"] = self._settings.get("model") or None
|
|
1429
1575
|
kwargs["on_permission_request"] = _with_normalized_permission_decisions(
|
|
1430
|
-
|
|
1576
|
+
cast(
|
|
1577
|
+
PermissionHandlerType,
|
|
1578
|
+
opts.get("on_permission_request") or self._permission_handler or _deny_all_permissions,
|
|
1579
|
+
)
|
|
1431
1580
|
)
|
|
1581
|
+
# File hooks let the working directory's checked-in configuration influence what the
|
|
1582
|
+
# CLI does on the host, so the agent leaves them off for a consistent session in every
|
|
1583
|
+
# checkout. Callers opt in through ``default_options`` or per-run options.
|
|
1584
|
+
if kwargs.get("enable_file_hooks") is None:
|
|
1585
|
+
kwargs["enable_file_hooks"] = False
|
|
1586
|
+
self._warn_once_about_unloaded_file_hooks(kwargs.get("working_directory"))
|
|
1432
1587
|
kwargs["hooks"] = self._build_session_hooks(all_tools, kwargs)
|
|
1433
1588
|
|
|
1434
1589
|
# Strip agent-internal and client-level keys that are consumed here or in the
|
|
1435
1590
|
# run methods (and settings) but are NOT valid create_session parameters, so
|
|
1436
1591
|
# they don't leak through the passthrough layer and raise TypeError.
|
|
1437
|
-
for key in (
|
|
1592
|
+
for key in (
|
|
1593
|
+
"on_pre_tool_use",
|
|
1594
|
+
"on_function_approval",
|
|
1595
|
+
"timeout",
|
|
1596
|
+
"cli_path",
|
|
1597
|
+
"log_level",
|
|
1598
|
+
"base_directory",
|
|
1599
|
+
"telemetry",
|
|
1600
|
+
):
|
|
1438
1601
|
kwargs.pop(key, None)
|
|
1439
1602
|
|
|
1440
1603
|
return kwargs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-framework-github-copilot
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: GitHub Copilot integration for Microsoft Agent Framework.
|
|
5
5
|
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.14
|
|
16
16
|
Classifier: Typing :: Typed
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: agent-framework-core>=1.
|
|
19
|
-
Requires-Dist: github-copilot-sdk==1.0.
|
|
18
|
+
Requires-Dist: agent-framework-core>=1.15.0,<2
|
|
19
|
+
Requires-Dist: github-copilot-sdk==1.0.11; python_version >= '3.11'
|
|
20
20
|
Project-URL: homepage, https://aka.ms/agent-framework
|
|
21
21
|
Project-URL: issues, https://github.com/microsoft/agent-framework/issues
|
|
22
22
|
Project-URL: release_notes, https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true
|
|
@@ -111,4 +111,33 @@ model described above. When `on_function_approval` is set, it gates `always_requ
|
|
|
111
111
|
the default ask-hook is not installed. It is **mutually exclusive** with `on_pre_tool_use` —
|
|
112
112
|
setting both (whether at construction or per run) raises `ValueError`.
|
|
113
113
|
|
|
114
|
+
## Workspace-driven session options
|
|
115
|
+
|
|
116
|
+
`on_permission_request` and `on_pre_tool_use` gate **tool calls**. They do not cover
|
|
117
|
+
configuration the CLI picks up from the working directory it runs in, which is a separate
|
|
118
|
+
mechanism with its own switches.
|
|
119
|
+
|
|
120
|
+
So that a session behaves the same way in every checkout, `GitHubCopilotAgent` leaves the
|
|
121
|
+
following off by default:
|
|
122
|
+
|
|
123
|
+
| Option | Default | Effect when enabled |
|
|
124
|
+
| --- | --- | --- |
|
|
125
|
+
| `enable_file_hooks` | `False` | The CLI loads file hooks from the working directory's `.github/hooks/` and runs the commands they define, independently of the tool-approval path. |
|
|
126
|
+
|
|
127
|
+
Opt in per agent or per run when your workflow needs the checkout to drive the session:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
agent = GitHubCopilotAgent(
|
|
131
|
+
default_options=GitHubCopilotOptions(enable_file_hooks=True),
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Only enable these for a working directory whose contents you trust to act on the host.
|
|
136
|
+
|
|
137
|
+
To make the default visible rather than silent, the agent logs a warning through the
|
|
138
|
+
`agent_framework.github_copilot` logger the first time it starts a session in a working
|
|
139
|
+
directory that defines hooks it is not loading. See
|
|
140
|
+
[`github_copilot_with_file_hooks.py`](../../samples/02-agents/providers/github_copilot/github_copilot_with_file_hooks.py)
|
|
141
|
+
for a runnable example.
|
|
142
|
+
|
|
114
143
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
agent_framework_github_copilot/__init__.py,sha256=A8xc4tEW9aFASMSwBmiWIn6MWnOU1rXGyN3HMzEOZxw,464
|
|
2
|
+
agent_framework_github_copilot/_agent.py,sha256=aR9nKRDa_1L9QAyfgh74qyvRVm6f-0NgVNYW7MVEOus,75345
|
|
3
|
+
agent_framework_github_copilot/_feature_usage.py,sha256=UfIdQLxq6ppR2zrjHZTo5kptX7PPR4Be_N2Wd7DSV4U,184
|
|
4
|
+
agent_framework_github_copilot-2.0.0.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
|
|
5
|
+
agent_framework_github_copilot-2.0.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
6
|
+
agent_framework_github_copilot-2.0.0.dist-info/METADATA,sha256=JrePbSIdKKpIMChvVH0n7KKh-k7Qp8voz30Mb8IjVWw,6447
|
|
7
|
+
agent_framework_github_copilot-2.0.0.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
agent_framework_github_copilot/__init__.py,sha256=A8xc4tEW9aFASMSwBmiWIn6MWnOU1rXGyN3HMzEOZxw,464
|
|
2
|
-
agent_framework_github_copilot/_agent.py,sha256=M96Xy1whwgDTcvCuUOoyBbpi4hoUepCm3gbgX4iv22M,68004
|
|
3
|
-
agent_framework_github_copilot/_feature_usage.py,sha256=UfIdQLxq6ppR2zrjHZTo5kptX7PPR4Be_N2Wd7DSV4U,184
|
|
4
|
-
agent_framework_github_copilot-1.0.2.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
|
|
5
|
-
agent_framework_github_copilot-1.0.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
6
|
-
agent_framework_github_copilot-1.0.2.dist-info/METADATA,sha256=DIAjemb3jP20Ck5l0y5BlJFrXWSU3cOICZ2o_e3pfP4,5176
|
|
7
|
-
agent_framework_github_copilot-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|