githubnext/chopinPublic

Let's compose rich plans together

Run the Planner on HarnessAgent with a Copilot SDK adapter #192

Mergedlavaman131merged 2 commits intofeat/harness-2-toolsfromrefs/pull/192/head
  1. LA

    Part of GitHub stack #202 (#181 harness).

    Part of #181. This is slice 3 of 5 stacked PRs for the pluggable agent harness RFC. It covers RFC phase 3 (the Copilot SDK adapter) and phase 5 (the Planner on `HarnessAgent`). Phase 9, the author's own runtime adapter, is deferred.

    Stacked on #187 (`feat/harness-2-tools`). Review #185, #186 and #187 first; this diff contains only the slice 3 commits.

    ## What changes

    - **Copilot SDK adapter.** `apps/server/src/harness/copilot-sdk/` holds `createCopilotSdk()`, a host-process `HarnessV1` over `@github/copilot-sdk`. It absorbs the hardening from `agent/client.ts` and the runtime generations from `agent/runtime.ts`. - The adapter declares no built-ins and registers only the host tools `HarnessAgent` passes. - It disables Copilot's built-in GitHub MCP. - It implements `output` through an internal result tool. - It resolves per-session credentials from the active owner. - It keeps a live check against the Copilot session's tool metadata. That check fails closed, and it accepts a missing `namespacedName` alias only for the exact, unique set of host tool names with no MCP entries. - **Harness map, agents, sessions.** - `harness/harnesses.ts` holds the name-to-factory map (`copilot-sdk`) and `harnessFor`. - `harness/agents.ts` defines `plannerAgent`. - In `harness/session.ts`, `openPlannerSession` authorizes the owner, loads `githubTools`, and opens an empty just-bash sandbox. A failure destroys the sandbox and returns a named error. - **Chat on `HarnessAgent`.** `chat/service.ts` streams through `plannerAgent.stream()`, and `translate(room, part)` projects AI SDK stream parts into `Chat.*`. The rest of the turn lifecycle: - A tool call outside `activeTools` aborts the turn and logs a boundary failure. - `permissionMode` is `allow-reads`, and approval requests are denied automatically. - `abortSignal` follows the active owner's signal. - `session.destroy()` runs after every turn, and interrupted turns are never replayed. - A turn aborted while the Copilot session is still opening sends nothing (`8835926`). - **Deleted.** `agent/client.ts`, `agent/runtime.ts`, `agent/permissions.ts`, `hasForeignScope`, and the slice 2 Copilot bridge. `agent/planner.ts` is smaller. - **Lint boundary.** `.oxlintrc.json` restricts `@github/copilot-sdk` imports to `apps/server/src/harness/copilot-sdk/`.

    ## Deviations from the RFC

    - **Tool context per turn.** The pinned `HarnessAgent` rejects `toolsContext` at `createSession` unless the session is being resumed. So each turn's `prepareCall` supplies the per-tool contexts. - **Owner pre-authorization failure maps to `Unavailable`.** The RFC's `OpenError` union has no `Unauthorized` member.

    ## Temporary pieces (removed in slice 4)

    `harness/copilot-sdk/workers.ts` keeps the background-worker path on the Copilot runtime until the summary and research workers move to structured output. That path includes `openWorker`, `openPublicResearchWorker`, `terminalGate`, `publicResearchGate`, `PUBLIC_WEB_SEARCH_*`, and a `Tool` re-export for the two jobs. A separate worker runtime keeps public web MCP on until then.

    Commits: - `abf1984` Run Planner through Copilot HarnessAgent - `8835926` Stop Copilot turns aborted during session opening (review round)

    ## Interactive Edge verification

    On a signed-in local build in Microsoft Edge, `@chopin` on the `golden-wind` document streamed a reply through the new harness path. The expanded tool list shows `Read repository file` and `List pull requests`, and the reply cites README "# Chopin" and PR #189 from the channel's repository. The server log listed exactly the 16 Chopin host tools, with no MCP or ambient tools. The top of the chat still shows the end of an earlier message from the same session: the live metadata check refused a turn before the `namespacedName` fix.

    ![Planner turn on HarnessAgent: two host tools, cites README heading and PR #189](https://github.com/user-attachments/assets/a3aebb52-3d0a-4ea7-8e27-1f85a338598c)

    Asked for a pull request in `vercel/ai`, the Planner said it has no access, because its tools are fixed to `githubnext/chopin`, and offered #189 from the channel's repository instead.

    ![Planner refuses a foreign repository and answers from the channel repository](https://github.com/user-attachments/assets/fd31b132-8e7e-4004-bcfb-dd6e0dfa6763)

    ## Workflow note

    The review loop approved this slice. The workflow's final check failed twice for reasons outside the code: - A stage's todo file inside the worktree tripped `dprint`. - The E2E command exited under a shared lock with no output.

    I reran the full checks at `8835926` myself; results are below.

    Assistant-model: GPT-6 Sol, Claude Sonnet 5, GPT-6 Luna, Claude Opus 5.5 Assistant-workflow: harness-stack (runs e1e96553-487c-4e7f-acb9-9298606eb64c, 917fbe31-9412-4829-9c2d-8a0c0821fa9f, 9a5c72fd-7661-4262-8db9-cb80294bb7f8) Assistant-verification: Bun adapter contract unit passed: contract suite against createCopilotSdk() with a stubbed Copilot client, including output through the result tool and abort Assistant-verification: Bun metadata regression passed: the live no-alias shape failed before the fix and passed after; built-in alias and duplicate substitution rejected Assistant-verification: Bun delayed-open abort regression passed: failed before 8835926 with one send, passes after with no send Assistant-verification: oxlint negative probe passed: a type-only @github/copilot-sdk import outside the adapter is rejected Assistant-verification: agent-browser Edge manual scenario passed: signed-in @chopin cited README "# Chopin" and PR #189 with two host tools, refused vercel/ai, and the server log listed 16 Chopin tools Assistant-verification: bun run ci passed: dprint, oxlint, tokens at 8835926 Assistant-verification: bun run types passed: all workspaces and E2E at 8835926 Assistant-verification: bun test passed: 1568 pass, 2 PostgreSQL skips, 0 fail at 8835926 Assistant-verification: bun run e2e passed: CI=1 under flock, 228 passed and 2 flaky that passed on retry (responsive-decisions.e2e.ts:61, responsive-workspace.e2e.ts:186) at 8835926 Co-authored-by: @lavaman131

  2. chopinmentionedlast month on GitHub

  3. chopinsubscribedlast month on GitHub

  4. lavaman131mentionedlast month on GitHub

  5. lavaman131subscribedlast month on GitHub

  6. lavaman131added-to-stacklast month on GitHub

  7. lavaman131referenced this in Move workers to structured output and add harness deployment modes #194last month on GitHub

  8. lavaman131referenced this in Add the Pi harness adapter and E2E harness coverage #195last month on GitHub

  9. lavaman131ready-for-reviewlast month on GitHub

  10. MA

    Tested in Chrome in MacOS and also worked 👍

  11. lavaman131removed-from-stacklast month on GitHub

  12. lavaman131base-ref-force-pushedlast month on GitHub

  13. lavaman131head-ref-force-pushed 7ea0c532404clast month on GitHub

  14. lavaman131added-to-stacklast month on GitHub

  15. lavaman131merged 43d99b795c6blast month on GitHub

  16. lavaman131closedlast month on GitHub

  17. lavaman131head-ref-deletedlast month on GitHub