Skip to content

Cross-SDK backend abstraction with copilot_sdk adapter#225

Open
anticomputer wants to merge 28 commits into
mainfrom
anticomputer/copilot-sdk-support
Open

Cross-SDK backend abstraction with copilot_sdk adapter#225
anticomputer wants to merge 28 commits into
mainfrom
anticomputer/copilot-sdk-support

Conversation

@anticomputer
Copy link
Copy Markdown
Contributor

@anticomputer anticomputer commented Apr 21, 2026

Cross-SDK backend abstraction with copilot_sdk adapter

Problem

The runner was hard-wired to the openai-agents SDK. We want to keep the YAML grammar as the source of truth and run the same taskflows against the GitHub Copilot Python SDK as well, without forking the engine or silently changing semantics between SDKs.

What changed

New sdk/ package (src/seclab_taskflow_agent/sdk/):

  • base.py defines AgentSpec (a backend-neutral description of an agent), MCPServerSpec, the neutral stream events TextDelta / ToolEnd, and the AgentBackend protocol every adapter implements (validate, build, run_streamed, aclose).
  • errors.py defines a neutral exception hierarchy (BackendCapabilityError, BackendBadRequestError, BackendRateLimitError, BackendTimeoutError, BackendMaxTurnsError, BackendUnexpectedError) that adapters translate native SDK errors into.
  • openai_agents/backend.py wraps openai-agents (default).
  • copilot_sdk/backend.py wraps the GitHub Copilot Python SDK (pip install seclab-taskflow-agent[copilot]).

Capability gating. Each adapter's validate() rejects spec fields it cannot honour. copilot_sdk rejects handoffs, temperature, and parallel_tool_calls; openai_agents accepts everything the YAML grammar exposes. Taskflows that use unsupported fields fail at load time with a BackendCapabilityError naming the offending field, so behaviour never drifts silently across SDKs.

Backend selection precedence:

  1. backend: field in the model config document.
  2. SECLAB_TASKFLOW_BACKEND environment variable.
  3. Endpoint auto-default (api.githubcopilot.com selects copilot_sdk, anything else selects openai_agents).

Runner refactor. runner.py now drives the backend through the neutral protocol. The per-task event loop, the rate-limit / retry backoff, and the Copilot ToolEnd-to-on_tool_end bridge live in _stream.py so the runner stays focused on orchestration. The JSON-envelope contract that repeat_prompt depends on (json.dumps({"text": ...}) matching openai-agents' MCP TextContent serialisation) is documented in one place.

Defensive hardening for both backends.

  • Per-phase httpx.Timeout(connect=10s, read=300s, write=300s, pool=60s) on the AsyncOpenAI client so dead TCP connections surface as APITimeoutError instead of hanging the run.
  • TaskAgent.close() releases the httpx connection pool; the openai-agents adapter calls it from aclose() to drop CLOSE_WAIT sockets that would otherwise spin the event loop.
  • Stream idle timeout in _stream.drive_backend_stream: each event is fetched under asyncio.wait_for(STREAM_IDLE_TIMEOUT) and translates to BackendTimeoutError so the existing retry loop handles it uniformly for both backends.
  • The openai-agents adapter cancels the underlying RunResultStreaming in its finally, preventing the _run_impl_task leak that occurred when the consumer aborted the iterator.
  • The copilot adapter aborts the session on early stream exit so the SDK's background event task can drain.
  • Process watchdog (_watchdog.py): a daemon thread force-exits the process if no event-loop activity is reported for WATCHDOG_IDLE_TIMEOUT seconds (default 35 min, env-overridable). Pinged from the stream driver, the runner's tool hooks, and the cleanup paths.
  • The runner cancels a still-running MCP session task in its finally so a dangling task can't keep the loop alive past run_main.
  • The CLI calls os._exit after asyncio.run to bypass the interpreter shutdown spin we observed with the Responses API + MCP combination. Tests that import run_main directly are unaffected.

These are the same fixes that landed in #212, layered into the abstraction so they apply to both backends rather than only to openai-agents. #212 can be closed in favour of this PR.

Copilot session pinning. create_session is called with enable_config_discovery=False, custom_agents=None, agent=None, and skill_directories=[] so on-disk Copilot CLI configuration cannot silently override what the YAML asked for. The adapter also refuses empty model strings, which the SDK would otherwise replace with its built-in default and invalidate any reproducibility guarantee a taskflow makes about the model under test.

What did not change

The YAML grammar is unchanged. Existing taskflows run on openai_agents without modification. No public API was removed.

Testing

236 unit tests pass; ruff clean. Real-taskflow matrix exercised against both backends (AI_API_TOKEN from passage show github/capi-token):

taskflow openai_agents copilot_sdk
echo ok ok
example ok rejected (handoffs)
example_repeat_prompt ok ok
example_repeat_prompt_async ok ok
example_repeat_prompt_dictionary ok ok
example_inputs ok ok
example_globals ok ok
example_responses_api ok ok
comprehensive_test ok rejected (handoffs)
edge_case_test ok ok
example_triage_taskflow ok rejected (handoffs)

Pre-existing on main and not a regression: echo_responses_api on openai_agents fails with invalid_request_body (Responses + MCP combination is broken upstream). Listed here so reviewers don't chase it.

Introduces seclab_taskflow_agent.sdk with neutral dataclasses
(AgentSpec, MCPServerSpec, ToolSpec, StreamEvent, RunResult,
BackendCapabilities) and a tiny registry + resolver for picking
an adapter. Purely additive; no existing module consumes it yet.

resolve_backend_name precedence: explicit arg > SECLAB_TASKFLOW_BACKEND
env > auto-default for api.githubcopilot.com > openai_agents.
Mirror the existing agent.TaskRunHooks/TaskAgentHooks shape but with
backend-neutral callback signatures: HookContext + plain tool_name /
source_name strings instead of the openai-agents RunContextWrapper/
Agent/Tool types. Adapters will translate between these and their
native SDK's hook protocol.
Defines the AgentBackend Protocol (build / run_streamed / aclose) that
adapters implement, plus register_backend() / get_backend() for
runtime lookup. register_backend() also records the adapter's
capabilities so resolve_backend_name() stays cheap to import.
sdk/openai_agents/ wraps TaskAgent behind the AgentBackend protocol:
build() translates AgentSpec to TaskAgent kwargs (model_settings is
materialised to agents.agent.ModelSettings here rather than in the
runner), run_streamed() yields sdk.TextDelta events translated from
openai-agents' raw stream, and run_streamed() maps the OpenAI/agents
exceptions to sdk.errors (BackendTimeout/RateLimit/BadRequest/
MaxTurns/Unexpected) so the runner can drop its direct openai and
agents imports.

Importing the package registers the adapter. MCP servers are still
passed as opaque native objects inside MCPServerSpec.params['_native']
and the runner keeps owning the MCP lifecycle; neutral MCP
materialisation is the next step.
Lets YAML select the SDK adapter explicitly (openai_agents or
copilot_sdk). Defaults to None so the runner keeps deriving the
backend from env or endpoint. Unknown values are rejected at parse
time by the Literal.
Extra installs the github-copilot-sdk public-preview package so the
copilot_sdk backend can be selected. Pinned to 0.2.x because the SDK
is under active development and may break between minor releases.
Requires Python >= 3.11 (the SDK's floor); users on 3.10 simply skip
the extra.
deploy_task_agents now resolves a backend via sdk.resolve_backend_name
(threading the new ModelConfigDocument.backend field), builds the
primary and any handoff agents from neutral AgentSpec values, drains
sdk.TextDelta events from backend.run_streamed, and catches the
neutral BackendError hierarchy in both the inner retry loop and the
outer task-retry loop. ModelSettings, prompt_with_handoff_instructions,
ResponseTextDeltaEvent and the OpenAI/agents exception classes are no
longer referenced at runtime; the openai-agents Agent/Tool types
remain only as TYPE_CHECKING annotations on the existing hook
callbacks.

The openai_agents adapter applies prompt_with_handoff_instructions
when AgentSpec.in_handoff_graph is set, preserving the previous
behaviour of wrapping every participant of a multi-personality
taskflow (including the handoff targets themselves).

sdk.get_backend and resolve_backend_name auto-import the adapter
module on demand, so adding the copilot_sdk backend later won't
require touching the runner. The backend's aclose() is now invoked
in the deploy_task_agents finally block.
assert_supported() runs once per task right after backend resolution
and raises BackendCapabilityError with the offending field+backend if
the YAML asks for something the backend cannot honour: handoffs on a
single-agent backend, api_type='responses' on copilot, explicit
temperature on a backend that ignores it, reasoning_effort on a
backend without it, and exclude_from_context on a backend that has
no per-tool exclude. The runner also stops auto-injecting default
temperature / parallel_tool_calls when the backend doesn't support
them, so a copilot run no longer silently sends ignored settings.
Wires the github-copilot-sdk into the AgentBackend abstraction:
permission handler driven by blocked_tools/headless, MCP stdio/SSE/HTTP
config materialiser, and an event-driven run_streamed that drains
SessionEvent into neutral TextDelta/ToolStart/ToolEnd. Runner now
forwards raw MCP params alongside the openai-agents native handle so
the new adapter has the data it needs.
README now lists the openai_agents and copilot_sdk capability matrices,
the install extra, and the backend resolution precedence. New
parametrised tests assert capability/registry consistency across every
registered backend. Make CopilotSDKBackend.aclose tolerate a None
handle so failures during build leave nothing to clean up.
Skipped by default; run them by setting SECLAB_TASKFLOW_LIVE_OPENAI_TOKEN
or SECLAB_TASKFLOW_LIVE_COPILOT_TOKEN to a valid token. Each test runs
a single trivial prompt through build/run_streamed/aclose to confirm
the full path stays wired against the real APIs.
Drop unused capability matrix, registry autoload, hooks module, and
ToolSpec/RunResult/AgentHandle/Tool* event types. Each adapter now
exposes a small Protocol and validates its own spec.

Fix the copilot_sdk path: strip provider/ prefix from model names and
read assistant text from delta_content. Verified by running
examples.taskflows.echo against both backends.
Resolve bare MCP commands via PATH and default subprocess cwd to the
runner's cwd; the SDK spawns MCP servers without inheriting the venv
or working directory, which broke stdio toolboxes (e.g. memcache).

Add a ToolEnd stream event so the runner can capture MCP tool output
from the copilot adapter, which is what repeat_prompt iterates over.

Drop the headless-gated denied-no-approval-rule branch in the
permission handler; taskflow policy is blocked_tools, matching the
openai_agents path.
gpt-5.1 is no longer available via the CAPI list-models endpoint;
gpt-5-mini is the gpt-5 family member that the Responses API actually
serves with this token.
Mirror openai-agents' ToolsToFinalOutputFunction by aborting the
Copilot session after the first successful tool call when the agent
spec asks for it. The tool result still surfaces via the ToolEnd
event, but the model never gets to see it fed back as context.
Disable on-disk config discovery and clear custom_agents / agent /
skill_directories on session.create so user-level config files cannot
silently substitute the model, agent persona, or available skills the
taskflow YAML asks for.

Reject an empty model in _normalize_model; the SDK would otherwise
fall back to its built-in default.

Refresh the permissions module docstring to match the simplified
blocked_tools-only policy. Document why the copilot adapter rejects
handoffs rather than implementing them via custom_agents.
Move the per-task event loop and the Copilot ToolEnd bridge into
_stream.py so the runner stops growing and the JSON-envelope
contract between the bridge and _build_prompts_to_run lives in
one documented place. Pure refactor, no behaviour change.
exclude_from_context is supported on copilot_sdk; remove it from
the list of unsupported fields. Add BackendSdk to the package
__all__ so callers can type-hint the new ModelConfigDocument
field without importing from .models.
Add per-phase httpx.Timeout to AsyncOpenAI so dead TCP connections
surface as APITimeoutError instead of hanging the run. Expose
TaskAgent.close() and have the openai-agents adapter call it from
aclose() to drain the connection pool.

Cancel the underlying RunResultStreaming in the adapter's
run_streamed finally so the openai-agents background task does
not leak when the consumer aborts the iterator. Mirror the same
pattern in the copilot adapter by aborting the session on early
exit.
Wrap each backend event in asyncio.wait_for with a 30 min idle
timeout; translate timeouts into BackendTimeoutError so the
existing retry loop handles them uniformly for both backends.

Add a daemon-thread watchdog that force-exits if no activity is
reported for a configurable window (35 min default). Ping it
from the stream driver, the runner's tool hooks, and the
cleanup paths. Cancel the MCP session task in the runner's
finally so a dangling task can't keep the loop alive.
Python's interpreter shutdown can spin on dangling asyncio tasks
or half-open sockets after asyncio.run completes (notably with
Responses API + MCP), blocking the process from returning. Skip
the soft-shutdown path with os._exit at the CLI entry point.
Tests that import run_main directly are unaffected.
Copilot AI review requested due to automatic review settings April 21, 2026 20:02
Comment thread src/seclab_taskflow_agent/sdk/__init__.py Fixed
Comment thread src/seclab_taskflow_agent/sdk/openai_agents/backend.py Dismissed
Comment thread src/seclab_taskflow_agent/_watchdog.py Dismissed
Comment thread src/seclab_taskflow_agent/sdk/base.py Fixed
Comment thread src/seclab_taskflow_agent/sdk/base.py Fixed
Comment thread src/seclab_taskflow_agent/sdk/base.py Fixed
Comment thread src/seclab_taskflow_agent/sdk/base.py Fixed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 introduces a backend-neutral runner interface so the same taskflow YAML can be executed via either the existing openai-agents integration or a new GitHub Copilot Python SDK adapter, while explicitly gating unsupported features to avoid silent semantic drift.

Changes:

  • Added sdk/ abstraction layer (neutral specs, events, error types) plus openai_agents and copilot_sdk backend adapters.
  • Refactored runner.py to drive agents through the backend protocol, extracting streaming/retry logic into _stream.py and adding a process watchdog _watchdog.py.
  • Updated configuration/docs/tests to support backend selection, optional Copilot dependency, and new hardening behaviors.
Show a summary per file
File Description
tests/test_watchdog.py Unit coverage for watchdog ping/idempotence/force-exit behavior.
tests/test_stream.py Unit coverage for stream driving, retries/backoff, idle timeout, and Copilot ToolEnd hook bridging.
tests/test_sdk_openai_adapter.py Adapter contract tests for openai-agents (events, error translation, cancellation, build/close).
tests/test_sdk_live_smoke.py Opt-in live smoke tests for both backends (env-gated).
tests/test_sdk_copilot_permissions.py Tests for Copilot permission callback behavior and signature.
tests/test_sdk_copilot_mcp.py Tests for translating MCPServerSpec → Copilot SDK MCP config.
tests/test_sdk_copilot_adapter.py Adapter contract tests for Copilot backend (validate, streamed events, abort semantics, helpers).
tests/test_sdk_base.py Tests for backend factory and backend-name resolution precedence.
tests/test_runner.py Adjusted runner tests for _resolve_model_config returning backend.
tests/test_models.py Tests for ModelConfigDocument.backend parsing/validation.
src/seclab_taskflow_agent/sdk/openai_agents/backend.py New openai-agents backend adapter implementing the neutral protocol.
src/seclab_taskflow_agent/sdk/openai_agents/init.py Package export for the OpenAI backend adapter.
src/seclab_taskflow_agent/sdk/errors.py Neutral backend exception hierarchy for consistent runner retry policy.
src/seclab_taskflow_agent/sdk/copilot_sdk/permissions.py Copilot SDK permission handler implementation (blocked_tools gating).
src/seclab_taskflow_agent/sdk/copilot_sdk/mcp.py Translation layer for MCP specs into Copilot SDK session configs.
src/seclab_taskflow_agent/sdk/copilot_sdk/backend.py Copilot SDK backend adapter implementation (build/run_streamed/aclose).
src/seclab_taskflow_agent/sdk/copilot_sdk/init.py Package export for the Copilot backend adapter.
src/seclab_taskflow_agent/sdk/base.py Neutral AgentSpec/MCPServerSpec, stream events, and backend protocol definition.
src/seclab_taskflow_agent/sdk/init.py Backend factory + backend name resolution logic.
src/seclab_taskflow_agent/runner.py Runner refactor to backend protocol + watchdog pings + improved cleanup.
src/seclab_taskflow_agent/models.py Adds backend field to model config schema (validated literal values).
src/seclab_taskflow_agent/cli.py CLI hardening: force-exit after run to avoid shutdown hangs.
src/seclab_taskflow_agent/agent.py Adds httpx timeouts to AsyncOpenAI client and exposes TaskAgent.close().
src/seclab_taskflow_agent/_watchdog.py New process-level watchdog to force-exit on prolonged event-loop inactivity.
src/seclab_taskflow_agent/_stream.py New extracted streaming driver (idle timeout, retry/backoff, tool hook bridging).
src/seclab_taskflow_agent/init.py Re-exports BackendSdk from models.
pyproject.toml Adds optional dependency group for Copilot SDK (seclab-taskflow-agent[copilot]).
examples/model_configs/responses_api.yaml Updates example model ID used for responses-api config.
README.md Documents backends, capability gating, and backend selection precedence.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

src/seclab_taskflow_agent/runner.py:337

  • MCP servers are built/connected unconditionally, but the Copilot backend does not consume the runner-managed entries (it uses create_session(mcp_servers=...) based on transport params). When backend_name == "copilot_sdk" this will start and connect MCP servers that are never used, potentially spawning duplicate subprocesses / consuming resources and introducing avoidable cleanup/hang risk. Consider skipping build_mcp_servers + mcp_session_task for the Copilot backend and instead constructing mcp_specs directly from mcp_client_params(...) (no _native handles) so only the active backend owns MCP lifecycle.
    # Build MCP servers and collect server prompts
    entries = build_mcp_servers(available_tools, toolboxes, blocked_tools, headless)
    mcp_params = mcp_client_params(available_tools, toolboxes)
    server_prompts = [sp for _, (_, _, sp, _) in mcp_params.items()]

    # Wrap each built MCP server in a neutral spec. The openai
    # adapter unwraps ``params["_native"]``; the Copilot adapter reads
    # ``kind`` plus the raw transport keys.
    mcp_specs: list[MCPServerSpec] = []
    for entry in entries:
        raw_params, *_ = mcp_params.get(entry.server.name, ({}, [], "", 0.0))
        mcp_specs.append(
            MCPServerSpec(
                name=entry.server.name,
                kind=raw_params.get("kind", "stdio"),
                params={**raw_params, "_native": entry.server},
            )
        )

    # Connect MCP servers
    servers_connected = asyncio.Event()
    start_cleanup = asyncio.Event()
    mcp_sessions = asyncio.create_task(mcp_session_task(entries, servers_connected, start_cleanup))
  • Files reviewed: 29/29 changed files
  • Comments generated: 3

Comment thread src/seclab_taskflow_agent/sdk/__init__.py Outdated
Comment thread src/seclab_taskflow_agent/models.py Outdated
Comment thread src/seclab_taskflow_agent/sdk/copilot_sdk/backend.py Outdated
- tests: split compound asserts (PT018), use pytest.raises (PT017),
  rename unused lambda params with _ prefix (ARG005).
- sdk/base.py: drop redundant '...' from Protocol method bodies.
- sdk/__init__.py: annotate substring URL match as intentional dispatch
  hint (endpoint is trusted operator config, not attacker input).
shutil.which() requires a PATHEXT-listed extension on Windows, so the
shebang-script fixture used by test_stdio_resolves_bare_command_via_path
isn't found. Skip the test on win32; the underlying code path is
exercised by the macOS and Linux runners.
Copilot AI review requested due to automatic review settings April 21, 2026 21:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 29/29 changed files
  • Comments generated: 2

Comment thread src/seclab_taskflow_agent/runner.py
Comment thread src/seclab_taskflow_agent/cli.py
anticomputer and others added 2 commits May 7, 2026 11:22
Address PR review feedback:

1. Remove endpoint-based auto-selection of copilot_sdk backend.
   Backend selection is now fully deterministic:
   explicit (model config 'backend:' field) > SECLAB_TASKFLOW_BACKEND
   env var > openai_agents. No implicit switching based on endpoint
   URL substring matching. This also resolves the CodeQL incomplete
   URL substring sanitization finding.

2. Fix _resolve_token() fallback returning env var NAME as literal
   token when the env var is unset. Now returns None instead of
   sending e.g. 'AI_API_TOKEN' as a bearer token, which would
   produce confusing auth failures.

3. Add logging.shutdown() before os._exit() in cli.py so log file
   handlers (RotatingFileHandler) flush buffered messages before
   the process force-exits.

4. Fix BackendName reference in models.py docstring (sdk.base.BackendName
   does not exist; the canonical source is sdk._KNOWN).
Copilot AI review requested due to automatic review settings May 8, 2026 00:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 29/29 changed files
  • Comments generated: 2

Comment thread src/seclab_taskflow_agent/sdk/__init__.py
Comment thread src/seclab_taskflow_agent/sdk/copilot_sdk/permissions.py Outdated
@anticomputer
Copy link
Copy Markdown
Contributor Author

Addressing review feedback:

CodeQL findings:

  • Incomplete URL substring sanitization (sdk/init.py): Intentional — URL check is a backend selection heuristic, not a security boundary.
  • Unnecessary delete statement (openai_agents/backend.py): Defensive del spec prevents accidental use after validation. Harmless.
  • Unused global _started (_watchdog.py): False positive — _started is used via global _started (checked and set to prevent double-init).
  • Statement has no effect x4 (base.py): False positives — these are class/method docstrings.

Copilot suggestions — already addressed in current code:

  • resolve_backend_name() endpoint auto-detection: Intentionally removed. Backend selection is now deterministic (explicit config or env var only). Docstring documents this: "no auto-detection based on endpoint URL."
  • _resolve_token() fallback: Fixed — returns os.getenv(token_env) or None, never the literal env var name. Docstring explicitly states this.
  • deploy_task_agents() None endpoint: Matches the deterministic design — endpoint is not used for backend selection.
  • os._exit() without logging.shutdown(): Valid suggestion. Will add logging.shutdown() before the hard exit.
  • BackendName reference in models.py: Will update comment.
  • blocked_tools canonicalization docstring: Will clarify that matching is exact, not canonicalized.

- Add logging.shutdown() before os._exit() to flush log handlers
- Fix blocked_tools docstring: exact string match, not canonicalized

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@anticomputer anticomputer marked this pull request as ready for review May 11, 2026 14:54
Copilot AI review requested due to automatic review settings May 11, 2026 14:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

Comments suppressed due to low confidence (1)

README.md:107

  • The selection-precedence list documents an endpoint auto-default to copilot_sdk, but the shipped resolve_backend_name() implementation does not perform endpoint-based selection. Please align this documentation with the actual behavior, or implement the endpoint-based auto-default in code so users aren’t misled.
Selection precedence:

1. `backend:` field in the model config document.
2. `SECLAB_TASKFLOW_BACKEND` environment variable.
3. Endpoint auto-default (`api.githubcopilot.com` prefers `copilot_sdk`
   when the optional dependency is installed).
4. `openai_agents`.
  • Files reviewed: 29/29 changed files
  • Comments generated: 4

Comment thread src/seclab_taskflow_agent/sdk/__init__.py
Comment thread README.md
Comment thread src/seclab_taskflow_agent/_stream.py
Comment thread src/seclab_taskflow_agent/cli.py Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@anticomputer
Copy link
Copy Markdown
Contributor Author

Addressing latest round of feedback:

  • Duplicate logging.shutdown(): Fixed in 3f8a732 — removed the duplicate.

  • resolve_backend_name endpoint auto-default: This is intentional and already documented in the docstring: "Backend selection is always deterministic — there is no auto-detection based on endpoint URL. Use backend: copilot_sdk in model config or set SECLAB_TASKFLOW_BACKEND=copilot_sdk to opt in." The README has been updated to match.

  • README Python version (>=3.10 vs copilot SDK >=3.11): The base package works on 3.10+. The [copilot] extra requires 3.11+ as noted in pyproject.toml comments. pip handles this — if you're on 3.10, pip install seclab-taskflow-agent[copilot] will fail with a clear version error from the copilot SDK itself.

  • bridge_copilot_tool_event context=None/agent=None: Documented tradeoff. The current hooks only access tool.name, not context.* or agent.*. The Copilot adapter path doesn't have a real agent object to pass. A SimpleNamespace(name=...) placeholder is used for the tool. If hooks are extended to access agent/context, this will need revisiting.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants