Skip to content

KiteBot on CopilotKit Intelligence — Phases 1 & 2 (channels + Intelligence Gateway + LangGraph deep-research agent) - #6

Merged
jerelvelarde merged 25 commits into
mainfrom
jerel/copilotkit-channels-intelligence-40037b
Jul 16, 2026
Merged

KiteBot on CopilotKit Intelligence — Phases 1 & 2 (channels + Intelligence Gateway + LangGraph deep-research agent)#6
jerelvelarde merged 25 commits into
mainfrom
jerel/copilotkit-channels-intelligence-40037b

Conversation

@jerelvelarde

@jerelvelarde jerelvelarde commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

KiteBot on CopilotKit Intelligence — Phases 1 & 2

Turns OpenTag into KiteBot on the CopilotKit Channels + Intelligence stack, with an optional LangGraph deepagents deep-research brain. Specs + plans under docs/superpowers/.

Phase 1 — Channels migration + Intelligence Gateway

  • @copilotkit/bot*@copilotkit/channels* (pure rename; APIs unchanged). Packages are published, so standalone pnpm install works.
  • KiteBot identity (Slack display name, agent persona, channel kitebot); the project stays "OpenTag".
  • Redis dropped (matches upstream examples/slack).
  • New app/managed.ts — the Intelligence Gateway channel host (pnpm channel), using the published two-process pattern (createBot + startChannelsOverRealtimeGateway). Holds no Slack tokens; Intelligence owns the Slack edge.
  • Docs lead with the Intelligence Gateway deploy; self-hosted (pnpm dev) is the alternative.

Phase 2 — LangGraph deepagents deep-research agent (agent/)

  • New Python service (agent/, Python 3.12 + uv), ported from CopilotKit's examples/showcases/deep-agents: a create_deep_agent planner + virtual filesystem, served over AG-UI via LangGraphAGUIAgent + FastAPI/uvicorn on :8123. KiteBot's channel host points AGENT_URL at it.
  • Tavily is optional — only OPENAI_API_KEY is required; chat + generative-UI rendering work without a key, and web research turns on when TAVILY_API_KEY is set.
  • Optional Notion/Linear MCP internal research sources (env-gated, failure-safe), mirroring runtime.ts.
  • Rendering verified (code-level spike): the channel's forwarded generative-UI tools reach the deepagents model via ag_ui_langgraph state-injection + CopilotKitMiddleware, so KiteBot's rich cards render through the deep agent (confirmed by reading the installed adapter source; the emit-tool-call allowlist that would have suppressed cards + the confirm_write write-gate was removed in review).

Code review

Ran the canonical 7-agent pr-review-toolkit CR over the whole PR — 3 rounds, all findings fixed:

  • R1: real deploy/config bugs — Railway $PORT, CORS allow_credentials, temperature=0.7 vs gpt-5.5 (reasoning models 400), the emit_tool_calls allowlist (would suppress cards + write-gate), a runtime.ts MCP late-success leak, secret-in-argv in start-notion-mcp, and the multi-provider docs contradiction (runtime is OpenAI-only).
  • R2: regressions from R1 fixes + robustness (PORT empty-string/range, message-content log gating, caption reorder).
  • R3: error-handling hardening + test robustness (MCP connect timeout, caption-failure misreport, spawn-error listener, strict parseProjectId, hermetic tests).

Per-round wave reviews + a final integration review all approved. Verification: pnpm check-types clean, 108 TS tests, 9 Python tests, agent boots + /health ok. (Review stopped at round 3 by maintainer decision — code is green with no known unfixed bug; residual whole-file-review edge findings accepted as follow-up. No CI is configured in the repo.)

Still manual (needs live creds)

  • Live smoke test: run agent/ (OPENAI_API_KEY, optional TAVILY_API_KEY) + KiteBot with real INTELLIGENCE_* creds; confirm the dashboard flips Waiting for runtime → live and a card renders in Slack. Confirm the channel-name slug (kitebot) and the dev apiUrl/wsUrl.

Out of scope (Phase 3)

  • Railway one-click template (multi-service: Python agent + channel host). The deep-agents showcase's railway.toml + a Dockerfile are the references.

🤖 Generated with Claude Code

jerelvelarde and others added 25 commits July 15, 2026 11:43
…esign

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hannels-intelligence

channels-discord/-telegram/-whatsapp are only published at 0.0.x; pinned to
their latest published versions. jsxImportSource -> @copilotkit/channels-ui.
Commit the pnpm lockfile now that standalone install resolves.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…dupe rxjs

Global import-specifier rename across app/** (API identifiers unchanged:
createBot, defineBotTool, slack, SanitizingHttpAgent, etc.). The rename made
the slack agent import resolve correctly, exposing a latent duplicate-rxjs
skew (channels@7.8.1 vs channels-slack->core@7.8.2) that broke the
AbstractAgent structural type at app/index.ts. Fixed with a pnpm override
pinning rxjs ^7.8.2 to a single copy. check-types clean; 62 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ltimeGateway)

app/managed.ts runs the same bot over the CopilotKit Intelligence Realtime
Gateway (published @copilotkit/channels-intelligence two-process pattern; the
unified CopilotRuntime({channels}) API is main-only/unpublished). Pure
createKiteBot() factory + unit test; 65 tests green, check-types clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eBot mentions

.env.example gains the INTELLIGENCE_* block for pnpm channel (full gateway
scope). README + setup.md rename bot->channels, add channels-intelligence,
present the managed Intelligence deployment as the recommended default with
self-hosted as the alternative, drop Redis, and note packages now publish to
npm (standalone install works).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…st managed service

Relabel the pnpm channel mode 'Intelligence Gateway' (was 'Intelligence
(managed)') and reserve 'managed service' for the coming-soon hosted waitlist,
resolving the terminology collision.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mands, render-table, components)

- managed.ts: drop bot.name! (local channelName const), guard onThreadStarted,
  extract+test pure helpers (promptFromMessage/buildAgentHeaders/parseProjectId)
- index.ts: log the swallowed error-post, harden shutdown (runShutdown wrapper,
  guarded closeBrowser, exit codes) mirroring managed.ts
- commands: wrap /agent /triage /file-issue-fallback runAgent (runAgentSafely
  helper, log + apology); test /triage-with-text and /preview no-user
- render-table: surface clamp truncation notes to user + agent, align 'Max 99'
  desc, right-align monospace fallback, log the native-post failure
- components: render priority in issue-list meta, cap page-list blocks
- render-chart: add JSON.parse/upload-failure/bytes tests
84 tests pass; check-types clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ntime, config)

- confirm-write-tool: distinguish no-response (timeout/dismissed) from explicit
  decline instead of silently reporting DECLINED
- confirm-write / showcase onClick handlers: guard fire-and-forget update/post
- file-issue: log swallowed apology-post; document the necessary ModalView cast;
  test success-path prompt + sender context
- read-thread: cover the handle fallback branch
- runtime.ts: narrowing instead of (reason as Error); drop the as never[] cast
  (types align); document the AGENT_MODEL cast caveat; platform-neutral framing
  (log prefix [runtime], doc header, SYSTEM_PROMPT) since the backend serves all
  platforms
- .env.example: header includes WhatsApp; setup.md: correct the table-renderer
  row (native Table, not Playwright); tsconfig: type-check scripts/ (+ fix childEnv)
89 tests pass; check-types clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hygiene, coverage

- runtime.ts + index.ts: validate PORT (integer, 1-65535; reject 0 / out-of-range)
- index.ts: guard onThreadStarted (match managed.ts)
- managed.ts: type promptFromMessage (drop cast); instanceof narrowing; +parseProjectId edge tests
- scripts/start-notion-mcp.ts: drop --auth-token CLI arg (secret leaked via ps under shell:true; AUTH_TOKEN env suffices)
- docs: correct OpenAI-only reality (runtime is openaiText-only; Anthropic/Google not wired), AGENT_URL is required (not a code default), document NOTION_MCP_PORT/NOTION_VERSION
- tsconfig: drop stale 'agent' exclude; type-check scripts/
- tests: runAgentSafely error path, confirm-write no-response branch, render-chart DIAGRAM_PNG bytes + comment fix
94 tests pass; check-types clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…/LangGraph design

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…PENAI_API_KEY)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on :8123)

New agent/ service ported from CopilotKit examples/showcases/deep-agents:
create_deep_agent planner + virtual filesystem + Tavily research() tool, served
over AG-UI via LangGraphAGUIAgent + FastAPI/uvicorn. TAVILY_API_KEY is OPTIONAL —
only OPENAI_API_KEY is required; the research tool is gated on TAVILY, and chat +
UI-component generation work without it. Default model gpt-5.5, port 8123.
uv sync resolves cleanly; build (research disabled/enabled) + /health verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root .env.example gains an agent/-scoped block (OPENAI_MODEL distinct from
runtime.ts's AGENT_MODEL; optional TAVILY_API_KEY; AGENT_URL->:8123). Adds the
'agent' pnpm script and a 'Deep research (LangGraph deep agent)' section to
README + setup.md (uv sync + pnpm agent; OPENAI required, Tavily optional).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…_PORT apply

The script previously ran uvicorn main:app directly, bypassing main() — so the
documented SERVER_HOST/SERVER_PORT (and the 0.0.0.0 default) were silently
ignored and it bound 127.0.0.1. Now it uses the code path, matching the docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-required

test_tools: internet_search truncation, missing-key raise, error-swallow.
test_health: /health ok, build_agent works WITHOUT Tavily (optional-Tavily proof),
build_agent requires OPENAI_API_KEY. Adds pytest pythonpath=['.'] for flat imports.
6 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…v-gated)

internal_source_tools() builds langchain-mcp-adapters clients for Linear
(LINEAR_API_KEY) and Notion (NOTION_MCP_AUTH_TOKEN), mirroring runtime.ts's
transports; returns [] when unconfigured and is failure-safe (a down MCP never
breaks startup). Wired into main_tools in both research on/off branches so the
agent can consult team docs/issues even without web research. 8 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… in main.py

delenv LINEAR_API_KEY/NOTION_MCP_AUTH_TOKEN in the two build tests so they never
attempt a real MCP connection regardless of the dev's env; reword main.py module
docstring to reflect optional Tavily web research. 8 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ases, docs

agent/main.py: remove emit_tool_calls allowlist (it filtered the bridge-forwarded
generative-UI + confirm_write HITL tools — cards/write-gate would never surface);
honor Railway $PORT; gate uvicorn reload (default off); CORS allow_credentials=false;
version 0.1.0. agent/agent.py + tools.py: drop temperature=0.7 (gpt-5.5 rejects it);
remove dead @tool internet_search. agent/.env.example: document optional Linear/Notion
MCP source vars. render-chart/diagram: post caption only after upload succeeds (no
orphaned caption); drop unreachable stringified-chartSpec branch. render-table: surface
dropped extra cells. runtime.ts: close late-arriving MCP client (post-timeout leak).
docs: correct pnpm agent command + monorepo/standalone naming.
agent 8 tests + root 97 tests pass; check-types clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regressions from round 1: neutralize render-chart/diagram captions (reorder made
'chart/diagram below' wrong); render-table extra-cell note now compares declared
columns.length (not clamped) so >20-col tables aren't falsely flagged.
Robustness: main.py PORT range/non-numeric validation (fail loud); runtime.ts
empty-string PORT -> default 8200; managed.ts gates message-content logging behind
CHANNEL_DEBUG; start-notion-mcp exits nonzero on signal death + validates
NOTION_MCP_PORT; test_health drops importlib.reload (hermetic vs a present .env).
Edge: drop unvalidatable scatter chart type; monospace center-align; page-list
renders editedBy independently of edited. agent 8 + root 100 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- tools.py: rename inner research tool to internet_search (prompt/name match);
  8s asyncio.wait_for timeout on MCP get_tools (hung server can't block startup)
- render-chart/diagram: caption post moved out of the failure try (upload success
  no longer misreported as render failure), console.error on render failure,
  Message-rooted caption
- render-table: guard the monospace fallback post (returns status string, no throw)
- managed.ts: parseProjectId strict /^\d+$/ (reject hex/exp/binary/float typos)
- start-notion-mcp: child 'error' listener (clean message on spawn failure)
- tests: test_health order/.env-independent + assert research enabled/disabled;
  exact-count footer assertions; agent.py docstring corrected
agent 9 + root 108 tests pass; check-types clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jerelvelarde jerelvelarde changed the title KiteBot on CopilotKit Intelligence — Phase 1 (channels migration + Intelligence Gateway) KiteBot on CopilotKit Intelligence — Phases 1 & 2 (channels + Intelligence Gateway + LangGraph deep-research agent) Jul 16, 2026
@jerelvelarde
jerelvelarde merged commit 1559435 into main Jul 16, 2026
jerelvelarde added a commit that referenced this pull request Jul 27, 2026
`.migration-discovery.md` was a scratch artifact sitting at the repo root,
ungitignored, and contradicted by the PR that carried it: it records the
runtime floor staying at ^1.62.3 and channels-intelligence as a direct dep,
while the shipped branch raises the floor to ^1.63.2 and drops that dep.

Its 571 lines of verified SDK signatures are worth keeping, so move it beside
the design doc and plan under docs/superpowers/specs/ (the convention PRs #6
and #7 established) and head it with a note marking it a point-in-time record
plus the two places the implementation deliberately diverged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant