Addresses review feedback that channel-host.mts is doing too much.
Two changes, both scoped to the starters:
1. Channel construction moves to a new `channels.mts` beside `agent.ts` —
name resolution, `createChannel`, and the `onMessage` handler. That is
also the file to edit to customise a Channel (commands, reactions,
onMention), which previously meant editing the host.
The per-framework agent import moves with it, so `channel-host.mts` is now
byte-identical in all 15 starters rather than 13 + 2.
2. The host no longer stands up an HTTP server. Its comment claimed the
server was what "keeps the lifecycle-owning process alive"; that is false.
An open undici WebSocket holds the event loop on its own — verified with a
standalone repro where a process with no HTTP server and no timers of its
own stayed up indefinitely on a single WebSocket connection. The server was
therefore serving a second, uncalled copy of the runtime API on port 8300
for no reason.
With the server gone, `createCopilotNodeListener` was the wrong factory —
it builds a request listener purely for its activation side effect. The
host now uses `createCopilotRuntimeHandler` + `ready()`, which is the
documented long-running-host pattern (see fetch-handler.ts). This also
drops `node:http`, `basePath`, and the CHANNEL_PORT env var.
Behaviour is unchanged: same Channel, same agent, same status reporting, and
the same non-zero exit on activation failure.
Verified: 14/14 starters with a `typecheck:channel` script pass; mastra has no
such script by design (166dc94691) and its pre-existing Mastra `Memory` type
error is byte-identical before and after. `npm run channel` exercised on both
failure paths — missing channels.json, and missing INTELLIGENCE_API_KEY with a
name supplied — confirming the new `./channels.mjs` specifier resolves under
tsx as well as tsc. `parity:check` output identical to the pre-change baseline.
Refs #6315
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Same extraction as langgraph-python across the nine starters whose runtime
route builds a generic HttpAgent (adk, agno, claude-sdk-python,
claude-sdk-typescript, crewai-flows, ms-agent-framework-dotnet,
ms-agent-framework-python, pydantic-ai, strands-python). Each starter's
route now imports createDefaultAgent() from a new src/agent.ts instead of
constructing HttpAgent inline; the URL fallback/normalisation logic is
preserved verbatim per starter (identical bodies for four, agno's "/agui"
suffix, claude-sdk-*'s trailing-slash strip, crewai-flows' bare strip,
strands-python's second STRANDS_AGENT_URL fallback).
Each starter also gets channel-host.mts (copied verbatim from
langgraph-python) and its own tsconfig.channel.json, needed because the
starters' shared allowJs:true tsconfig makes tsx's resolver prefer a stray
index.ts the published fast-json-patch package ships without its source,
which otherwise crashes the channel script before it runs. package.json
gains the channel/typecheck:channel scripts and three deps: dotenv,
@copilotkit/channels (pinned to the same 1785633429 canary build as the
other @copilotkit/* packages), and tsx as a devDependency. This canary pin
is a temporary workaround pending a stable release with identifyUser
support, and must move before this path ships to users.
ms-agent-framework-dotnet's postinstall (a .NET SDK probe) fails on
machines without the SDK installed; dependency resolution itself succeeds
and is unaffected. crewai-flows, pydantic-ai, and strands-python each carry
a small number of pre-existing, unrelated tsc --noEmit errors (JSX/recharts
typing clashes and a missing exported type) not touched by this change.