Skip to content

Python: forward GitHubCopilotOptions verbatim to create_session#7155

Open
giles17 wants to merge 2 commits into
microsoft:mainfrom
giles17:ghcp-options-passthrough
Open

Python: forward GitHubCopilotOptions verbatim to create_session#7155
giles17 wants to merge 2 commits into
microsoft:mainfrom
giles17:ghcp-options-passthrough

Conversation

@giles17

@giles17 giles17 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Motivation & Context

The agent-framework-github-copilot package exposes GitHubCopilotOptions, a
TypedDict whose keys are hand-mapped onto the Copilot SDK's create_session.
That SDK accepts ~70 keyword parameters, but the agent only forwarded a fixed
subset (~8). Every time a user needed another option (e.g. reasoning_effort,
context_tier, enable_citations), it required a four-touch code change
(TypedDict key + __init__ pop + two duplicated session-builder mappings), and
any key the agent didn't recognize was silently dropped — the root cause of
recurring "my option isn't being applied" reports.

This change removes that maintenance treadmill and the silent-drop footgun so
the package can move toward a stable release without a stream of additive
option changes. It aligns the package with the sibling ClaudeAgent, which
already forwards its options dict verbatim to its underlying agent SDK.

Description & Review Guide

  • What are the major changes?

    • _create_session / _resume_session now forward the entire merged
      options dict to the Copilot SDK instead of enumerating a fixed subset. Any
      create_session parameter works without further code changes.
    • Introduced a single _build_session_kwargs helper that replaces the two
      near-identical session-builder bodies. It layers agent default_options
      then per-run options, and special-cases only what needs it: tools
      (merge + convert), model, on_permission_request (secure default), and
      hooks.
    • Dropped the dedicated per-key attributes (_mcp_servers, _provider,
      _instruction_directories, _skill_directories, _disabled_skills) and
      their pops; these now ride through default_options.
    • GitHubCopilotOptions remains the curated, typed, documented surface — its
      docstring now clarifies it is a common-case subset and that any other SDK
      create_session parameter is forwarded verbatim (unknown names raise
      TypeError rather than being silently ignored).
    • Updated tests that asserted the old internals (dedicated attributes, None
      passed for unset keys) to assert the new passthrough behavior.
  • What is the impact of these changes?

    • All ~70 create_session parameters are usable immediately; no per-option
      plumbing going forward.
    • Typos/unknown options now surface as a TypeError from the SDK instead of
      being silently dropped.
    • Net ~40 lines removed; behavior for existing curated keys is unchanged.
    • Because it turns previously-ignored keys into either applied options or a
      TypeError, landing it before the stable release keeps it additive; the
      common, documented usage remains backward compatible.
  • What do you want reviewers to focus on?

    • Whether the special-cased keys in _build_session_kwargs (tools, model,
      on_permission_request, hooks, streaming) are the correct minimal set,
      and that precedence (per-run options > agent default_options > settings)
      is preserved.

New usage

Agent-wide defaults — curated keys and previously-unsupported passthrough keys
now work side by side:

from agent_framework_github_copilot import GitHubCopilotAgent

agent = GitHubCopilotAgent(
    instructions="You are a helpful assistant.",
    default_options={
        # curated, typed keys
        "model": "gpt-5",
        "provider": {"type": "azure", "base_url": "https://...", "bearer_token": "..."},
        # passthrough keys that previously did NOT take effect — now forwarded:
        "reasoning_effort": "high",
        "context_tier": "large",
        "enable_citations": True,
        "excluded_tools": ["shell"],
    },
)

async with agent:
    response = await agent.run("Explain quantum tunneling.")

Per-run overrides via options= (take precedence over agent defaults):

async with agent:
    response = await agent.run(
        "Quick summary please.",
        options={"reasoning_effort": "low"},
    )

Unknown/misspelled keys now fail fast instead of being silently dropped:

agent = GitHubCopilotAgent(default_options={"reasoning_efort": "high"})  # typo
async with agent:
    await agent.run("hi")
# -> AgentException wrapping TypeError:
#    create_session() got an unexpected keyword argument 'reasoning_efort'

Related Issue

Fixes #7154

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Refactor the GitHub Copilot agent to forward the full options dict to the
Copilot SDK's create_session/resume_session instead of hand-mapping a fixed
subset. GitHubCopilotOptions stays as the curated, typed surface, but any
other create_session parameter (reasoning_effort, context_tier,
enable_citations, ...) is now passed through verbatim. Unknown keys surface
as TypeError from the SDK instead of being silently dropped.

De-duplicates the near-identical _create_session/_resume_session bodies into
a shared _build_session_kwargs helper.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f9d016d5-4d8c-43f0-a8fb-f3cf3d1ad7eb
Copilot AI review requested due to automatic review settings July 16, 2026 15:18
@giles17 giles17 added the python Usage: [Issues, PRs], Target: Python label Jul 16, 2026
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/github_copilot/agent_framework_github_copilot
   _agent.py4032194%61–62, 104, 113–115, 119, 540, 555–556, 635, 645, 779, 783, 935–936, 975, 978, 1115, 1186, 1204
TOTAL44440523688% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
8987 33 💤 0 ❌ 0 🔥 2m 4s ⏱️

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Python agent-framework-github-copilot agent to forward GitHubCopilotOptions (and any additional Copilot SDK create_session kwargs) through to the underlying Copilot SDK, eliminating the previous “fixed subset + silent drop” behavior and reducing ongoing maintenance for newly supported SDK options.

Changes:

  • Forward merged default_options + per-run options verbatim into create_session / resume_session, so any supported SDK kwarg works without new plumbing.
  • Introduce _build_session_kwargs to centralize session kwarg construction and replace duplicated logic in _create_session / _resume_session.
  • Update tests to assert omission of unset passthrough keys (rather than passing explicit None) and to reflect removal of per-key internal attributes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
python/packages/github_copilot/agent_framework_github_copilot/_agent.py Adds _build_session_kwargs and switches session creation/resumption to passthrough-style kwarg forwarding with a few special-cases.
python/packages/github_copilot/tests/test_github_copilot_agent.py Updates tests to validate new passthrough behavior and the updated internal storage model for defaults.

Comment thread python/packages/github_copilot/agent_framework_github_copilot/_agent.py Outdated
Comment thread python/packages/github_copilot/agent_framework_github_copilot/_agent.py Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 5 | Confidence: 87%

✓ Correctness

The refactoring correctly simplifies the session-kwargs construction, but _build_session_kwargs forwards all keys from runtime_options (per-run options=) to the SDK without stripping agent-internal keys that are not create_session parameters. Specifically, on_pre_tool_use (which existing tests pass per-run, e.g. line 2971) and timeout (consumed at _run_impl line 616) survive the merge and will cause a TypeError from the real SDK because they are not valid create_session keyword arguments. The old code was immune because it only explicitly extracted known SDK keys from runtime_options.

✓ Security Reliability

The refactoring correctly maintains the secure default for on_permission_request (deny-all) and properly overides hooks, tools, model, and streaming. However, on_pre_tool_use from runtime options is consumed by _build_session_hooks (placed inside the hooks dict) but also remains in kwargs from the passthrough spread at line 1138. This means create_session would receive it as both a top-level kwarg AND inside hooks, risking either a TypeError from the SDK (if it's not a valid top-level param) or conflicting configuration (if it is). The same pattern applies to timeout which the run method consumes locally but does not remove before forwarding.

✓ Test Coverage

The PR refactors session option handling to forward all options verbatim to the Copilot SDK. Existing tests were correctly updated to match the new behavior (omitting unset keys rather than passing None). However, the core new capability — forwarding arbitrary non-curated keys (e.g. reasoning_effort, context_tier) to create_session — lacks a dedicated test proving that an arbitrary key supplied in default_options or runtime options actually arrives in the SDK call. Similarly, the per-run override of such arbitrary keys is untested.

✓ Failure Modes

The new _build_session_kwargs method forwards runtime_options verbatim to the SDK via {**self._default_options, **opts}. However, _run_impl passes its entire opts dict (including agent-internal keys like timeout and on_pre_tool_use that are NOT create_session parameters) as runtime_options. In the old code these were harmlessly ignored because only an explicit set of keys was forwarded. Now they leak into create_session(**kwargs), likely causing TypeError in production. Tests don't catch this because the mock accepts any kwargs.

✗ Design Approach

I found one blocking design regression. The new verbatim session-kwargs merge now forwards adapter-consumed runtime options directly into the Copilot SDK session factory, so previously supported code paths like per-run timeout and on_pre_tool_use now raise TypeError against the real CopilotClient signature.

Flagged Issues

  • _build_session_kwargs at line 1138 splats the full runtime opts dict into create_session/resume_session, but CopilotClient.create_session does not accept adapter-local keys like timeout, on_pre_tool_use, or on_function_approval. This breaks documented/tested runtime options such as options={"timeout": 30} and options={"on_pre_tool_use": hook}, which will raise TypeError in production.

Automated review by giles17's agents

Comment thread python/packages/github_copilot/agent_framework_github_copilot/_agent.py Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Flagged issue

_build_session_kwargs at line 1138 splats the full runtime opts dict into create_session/resume_session, but CopilotClient.create_session does not accept adapter-local keys like timeout, on_pre_tool_use, or on_function_approval. This breaks documented/tested runtime options such as options={"timeout": 30} and options={"on_pre_tool_use": hook}, which will raise TypeError in production.


Source: automated DevFlow PR review

- Strip agent-internal/client-level keys (on_pre_tool_use, on_function_approval,
  timeout, cli_path, log_level, base_directory) from the forwarded kwargs so they
  cannot leak into create_session/resume_session and raise TypeError.
- Source caller tools from the merged options layer so tools supplied via
  default_options are honored instead of silently dropped.
- Honor a caller-supplied native 'hooks' dict in _build_session_hooks (composing
  with the on_pre_tool_use shortcut) instead of unconditionally overwriting it.
- Validate mock create_session/resume_session calls against the real SDK
  signatures in tests so invalid kwargs surface as TypeError, and add regression
  tests for the passthrough contract.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f9d016d5-4d8c-43f0-a8fb-f3cf3d1ad7eb
@giles17
giles17 marked this pull request as ready for review July 16, 2026 17:03

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 5 | Confidence: 90% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Failure Modes, Design Approach


Automated review by giles17's agents

@eavanvalkenburg eavanvalkenburg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small note

kwargs["tools"] = self._prepare_tools(all_tools) if all_tools else None

kwargs["streaming"] = streaming
kwargs["model"] = opts.get("model") or self._settings.get("model") or None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will already be set to opts['model'] so this is doing double work, we can check if model is present in kwargs, and if so skip, otherwise set to self._settings....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Investigate extending GHCP Options

3 participants