Uh oh!
There was an error while loading. Please reload this page.
feat(agent-runtimes): add github copilot sdk runtime - #21
Open
em-jones wants to merge 17 commits into
Open
Conversation
Two-phase plan replacing the custom DAG executor and granular event log with LangGraph (orchestration + checkpointer) and Langfuse (observability), preserving every existing feature. - Phase 1 swaps orchestration to LangGraph; Phase 2 integrates Langfuse. Each phase isolates exactly one breaking cutover (1.3 resume cutover, 2.2 event-log deletion) so a bisect localizes regressions to one phase. - Resolves open decisions: LangGraph SQLite checkpointer for resume (td stays a coarse human mirror), `interrupt` for human override, re-point `ca watch` at the in-process callback stream, custom counter channel for the revision budget. - §9 test disposition triages every affected suite (die / port / keep / audit / net-new), pinning the resume oracle and evidence-gate coverage. - Langfuse self-hosted via podman-compose; dispatch host configurable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace custom DAG executor with LangGraph state machine. Add pipeline-dispatch.ts for routing, update pipeline.ts to use LangGraph engine, add parity tests, and include podman-compose for local Langfuse deployment.
Remove legacy events layer (appender, reducer, schema, errors). Add run-state.ts and readback.ts, restructure tests, and finalize watch renderer/watcher for LangGraph state compatibility.
…ndency This package is imported directly in src/langgraph/checkpointer.ts, src/langgraph/engine.ts and test files; it was previously only a transitive dependency of @langchain/langgraph.
Both the initial spawn and the retry spawn in runImplementPhase were omitting langfuse: config.langfuse, leaving the implement phase without observability coverage. Every other phase (scout, verify, review, close, retrospective) passes the tracer. This restores consistent tracing.
The LangGraph engine's evaluatorNode recomputed revision routing with a naive rubricFailed() (any verdict==='fail' → revise), discarding the hard/soft classification that runReviewPhase already encodes. Reviewer hard-gate failures (principle-compliance, scope-discipline) are golden-principle violations — terminal aborts, not fixable-in-a-cycle revisions — but the engine looped them as soft revisions until the revision budget or an agent crash ended the run (the reviewer treadmill). Mirror runReviewPhase's split: reviewer hard fail → phase failure (routes to retrospective), soft fail → revise, verifier fail → revise. Adds a langgraph-parity regression scenario pinning hard-fail → abort (no revision cycle, no close). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ensureBranch created new task branches with `git checkout -b <name>`, basing them on whatever HEAD happened to be. Launching a task while an unrelated feature branch was checked out made the new branch inherit that branch's entire diff as its baseline, so the reviewer reviewed the inherited delta instead of the task's own work. Add resolveBaseRef(): branch from origin's default HEAD, else local main/master, falling back to HEAD only when no default branch exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add vite.config.ts with fmt, lint, and build blocks matching .oxfmtrc.json settings; includes bun-text-import plugin for .md/.yml/.yaml transforms - Delete dead vitest.config.ts stub (unused since bun:test migration) - Route package.json lint/format/format:check scripts through vp - Add vite-plus ^0.2.1 to devDependencies Scoped adoption: bun runtime, bun:test, bun:sqlite, and build:binary are unchanged. vp check/fmt/lint/build/dev all pass on a clean tree. 46 unit + 9 standalone specs green (bun src/dev/run-tests.ts). tsc --noEmit clean. bun src/index.ts --help boots.
The vitest, agent-SDK/LangChain, and vite-plus refactors left several docs
describing the old internals. Bring them current:
- Add docs/architecture/pipeline.md documenting the LangGraph StateGraph
engine, revision loop, fingerprint short-circuit, crash-resume
checkpointer, and the provider-routing agent runtime (Claude -> Agent SDK,
others -> LangChain, pi deprecated). This was wholly undocumented.
- README: replace "deterministic TypeScript pipeline executor" with the
LangGraph + checkpointer + provider-routing description and link the new
doc; fix `--task <file>` -> `--task <td-id>` (now a td issue handle);
fix storage layout (.todos/ td store, drop legacy .case/active and
tasks/active/*.task.json); fix `bun test` -> `bun run test`; correct the
default model id and model-resolution precedence.
- docs/failure-matrix.md: fix the `bun test` invocation to `bun run test`.
- Remove stale tasks/active/*.{md,task.json} examples that contradicted
tasks/README.md (tasks are td issues, not files); update CLAUDE.md project
structure and the bug-fix template's .task.json reference to match.
Conventions docs (testing.md, commits.md) were already current and are
untouched. No code changed.Add CopilotSdkRuntime, a third agent backend that runs the pipeline on a GitHub Copilot subscription via @github/copilot-sdk. The SDK is agentic — it drives the bundled Copilot CLI, which owns its own file/shell tools and authenticates as the logged-in Copilot user (or GITHUB_TOKEN), the same subscription/resource win the Claude Agent SDK runtime exists for — so it sits beside ClaudeAgentSdkRuntime rather than under LangChain. Routing is by explicit provider `copilot`, matched before isClaudeModel: Copilot fronts both GPT and Claude model ids, so a name heuristic would collide with the other backends. Read-only/mutable tool policy is enforced through the SDK onPermissionRequest callback (read-only roles reject `write` requests; shell stays allowed for exploration), keeping toolPolicyFor the single source of truth across all runtimes. CASE_AGENT_RUNTIME=copilot forces the backend for debugging. - src/agent/adapters/copilot-sdk-adapter.ts: new runtime, maps Copilot session events to the shared Langfuse span + tool-activity callbacks - provider-routing-runtime.ts: lazy getCopilot(), copilot-first select() - config.ts: isCopilotProvider classifier - copilot-sdk-adapter.spec.ts: event-mapping, permission seam, auth fail-fast, and routing contract (8 tests) - docs/architecture/pipeline.md: runtime-routing table + override Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Too many files changed for review. ( |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
CopilotSdkRuntime— a third agent execution backend that lets the pipeline run on a GitHub Copilot subscription via the official@github/copilot-sdk(GA).The Copilot SDK is agentic: it drives the bundled Copilot CLI, which owns its own file/shell tools and authenticates as the logged-in Copilot user (or
GITHUB_TOKEN/GH_TOKEN). That's the same subscription/resource win the Claude Agent SDK runtime exists for — so the new runtime sits besideClaudeAgentSdkRuntime, not under LangChain.Routing
copilotCopilotSdkRuntime(new)ClaudeAgentSdkRuntimeLangChainRuntimecopilot, checked beforeisClaudeModel— Copilot fronts both GPT and Claude model ids, so a name heuristic would collide with the other backends.onPermissionRequestcallback: read-only roles (scout/verifier/reviewer/closer) rejectwriterequests; shell stays allowed forrg/find/git status.toolPolicyForremains the single source of truth across all runtimes.CASE_AGENT_RUNTIME=copilotforces the backend for debugging (joinspi|sdk|langchain).spawn-sharedhelpers), so a phase behaves identically regardless of backend.getAuthStatus()is checked before the first message, returning an actionable error instead of an opaque mid-stream throw.Changes
src/agent/adapters/copilot-sdk-adapter.ts— new runtimesrc/agent/adapters/provider-routing-runtime.ts— lazygetCopilot(), copilot-firstselect()src/agent/config.ts—isCopilotProviderclassifiersrc/__tests__/copilot-sdk-adapter.spec.ts— new contract testdocs/architecture/pipeline.md— routing table + override docpackage.json/bun.lock— add@github/copilot-sdkTesting
bun run test— 669 passed, 2 skipped (8 new tests; no regressions)write, allowread/shell), mutable-role write approval, not-authenticated fail-fast, and the provider-router dispatch (provider:'copilot'+ force-env).bun run typecheckclean ·bun run lint0/0 ·bun run format:checkcleanFollow-ups
@github/copilot-sdk@1.0.3types (event names, permission/auth shapes verified against the installed.d.ts). Worth a live smoke test against a real Copilot subscription before relying on it in production runs.assistant.usageevent; fields are best-effort (SDK marks several as optional).