chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:58:18 +08:00
commit 6d5d58c1a9
18293 changed files with 3502153 additions and 0 deletions
@@ -0,0 +1,169 @@
import { NextRequest, NextResponse } from "next/server";
import {
CopilotRuntime,
ExperimentalEmptyAdapter,
copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
import { LangGraphAgent } from "@copilotkit/runtime/langgraph";
import crypto from "node:crypto";
// Emit a structured server-side error log with a correlation id so the
// 500 we return to the client carries no stack/message details (which
// can leak internal config, prompts, or upstream URLs) while operators
// can still grep logs for the same `errorId` to find the full failure.
function logRouteError(err: unknown): string {
const error = err instanceof Error ? err : new Error(String(err));
const errorId = crypto.randomUUID();
console.error(
JSON.stringify({
at: new Date().toISOString(),
level: "error",
phase: "setup",
errorId,
message: error.message,
stack: error.stack,
}),
);
return errorId;
}
const AGENT_URL = process.env.AGENT_URL || "http://localhost:8123";
console.log("[copilotkit/route] Initializing CopilotKit runtime");
console.log(`[copilotkit/route] AGENT_URL: ${AGENT_URL}`);
// Per-request request/response logging is gated behind this flag (default off).
// Under d6 probe fan-out, unconditional per-request logs flooded Railway's
// 500-logs/sec cap and killed the replica ("Messages dropped" → container stop).
// Set SHOWCASE_ROUTE_DEBUG=1 to re-enable verbose per-request tracing locally.
const ROUTE_DEBUG =
process.env.SHOWCASE_ROUTE_DEBUG === "1" ||
process.env.SHOWCASE_ROUTE_DEBUG === "true";
function createAgent(graphId: string = "sample_agent") {
return new LangGraphAgent({
deploymentUrl: `${AGENT_URL}/`,
graphId,
});
}
const agentNames = [
"agentic_chat",
"human_in_the_loop",
"gen-ui-tool-based",
"gen-ui-agent",
"shared-state-read",
"shared-state-write",
"shared-state-streaming",
"prebuilt-sidebar",
"prebuilt-popup",
"chat-slots",
"chat-customization-css",
"headless-simple",
];
const agents: Record<string, LangGraphAgent> = {};
for (const name of agentNames) {
agents[name] = createAgent();
}
// Dedicated-graph agents for tool-rendering + reasoning demos.
agents["tool-rendering"] = createAgent("tool_rendering");
agents["tool-rendering-default-catchall"] = createAgent("tool_rendering");
agents["tool-rendering-custom-catchall"] = createAgent("tool_rendering");
agents["tool-rendering-reasoning-chain"] = createAgent(
"tool_rendering_reasoning_chain",
);
agents["agentic-chat-reasoning"] = createAgent("reasoning_agent");
agents["reasoning-default-render"] = createAgent("reasoning_agent");
// Interrupt variants — share the dedicated `interrupt_agent` graph that uses
// langgraph's `interrupt()` primitive inside `schedule_meeting`.
agents["gen-ui-interrupt"] = createAgent("interrupt_agent");
agents["interrupt-headless"] = createAgent("interrupt_agent");
// Dedicated-graph agents — each cell has its own LangGraph graph with a
// tailored system prompt (tools=[], CopilotKitMiddleware attached).
agents["frontend_tools"] = createAgent("frontend_tools");
agents["frontend-tools-async"] = createAgent("frontend_tools_async");
agents["hitl-in-app"] = createAgent("hitl_in_app");
// In-Chat HITL via the high-level `useHumanInTheLoop` hook — backend
// agent has zero tools; the frontend-registered `book_call` tool is
// injected into the LLM's tool list by `CopilotKitMiddleware`. Both
// the canonical `hitl-in-chat` demo and the `hitl-in-chat-booking`
// alias share the same backend graph.
agents["hitl-in-chat"] = createAgent("hitl_in_chat");
agents["hitl-in-chat-booking"] = createAgent("hitl_in_chat");
// HITL step-selection: dedicated graph with tools=[] + CopilotKitMiddleware.
// The `human_in_the_loop` alias in the neutral-assistant loop above maps to
// `sample_agent` which has 7+ backend tools and a custom AgentState — the
// frontend-only `generate_task_steps` tool (from useHumanInTheLoop) is the
// ONLY tool this demo needs, so a minimal graph avoids state/tool contention.
agents["human_in_the_loop"] = createAgent("hitl_steps");
agents["readonly-state-agent-context"] = createAgent(
"readonly_state_agent_context",
);
// Shared State (Read + Write) — bidirectional shared state between UI and
// agent. UI writes `preferences` via agent.setState; middleware reads them
// into the system prompt; agent writes `notes` back via the `set_notes` tool.
agents["shared-state-read-write"] = createAgent("shared_state_read_write");
// Sub-Agents — supervisor delegates to research_agent / writing_agent /
// critique_agent (each a full create_agent under the hood). Every delegation
// is appended to `state.delegations` for live UI rendering.
agents["subagents"] = createAgent("subagents");
agents["default"] = createAgent();
console.log(
`[copilotkit/route] Registered ${Object.keys(agents).length} agent names: ${Object.keys(agents).join(", ")}`,
);
export const POST = async (req: NextRequest) => {
try {
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
endpoint: "/api/copilotkit",
serviceAdapter: new ExperimentalEmptyAdapter(),
runtime: new CopilotRuntime({
// @ts-ignore
agents,
}),
});
const response = await handleRequest(req);
if (!response.ok) {
console.log(`[copilotkit/route] Response status: ${response.status}`);
} else if (ROUTE_DEBUG) {
console.log(`[copilotkit/route] Response status: ${response.status}`);
}
return response;
} catch (error: unknown) {
// Log full message + stack server-side under a correlation id; return
// only the id to the client so we don't leak internal details (upstream
// URLs, env-driven config, prompts, etc.) into HTTP responses.
const errorId = logRouteError(error);
return NextResponse.json(
{ error: "internal runtime error", errorId },
{ status: 500 },
);
}
};
export const GET = async () => {
let agentStatus = "unknown";
try {
const res = await fetch(`${AGENT_URL}/ok`, {
signal: AbortSignal.timeout(3000),
});
agentStatus = res.ok ? "reachable" : `error (${res.status})`;
} catch (e: unknown) {
agentStatus = `unreachable (${(e as Error).message})`;
}
return NextResponse.json({
status: "ok",
agent_url: AGENT_URL,
agent_status: agentStatus,
});
};