mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-06 01:14:36 +08:00
feat: enhance Codex agent connection handling with automatic thread recovery and improved error logging
This commit is contained in:
@@ -10,6 +10,10 @@ export type AgentPendingToolCall = { requestId: string; name: string; input?: {
|
||||
export type AgentThreadSummary = { id: string; preview: string; name?: string | null; cwd?: string; status?: string; source?: unknown; createdAt?: number; updatedAt?: number };
|
||||
export type AgentPanelTab = "chat" | "setup" | "history" | "log";
|
||||
|
||||
const CONNECT_TIMEOUT_MS = 6000;
|
||||
let agentSource: EventSource | null = null;
|
||||
let connectTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
type CanvasAgentStore = {
|
||||
width: number;
|
||||
url: string;
|
||||
@@ -31,13 +35,15 @@ type CanvasAgentStore = {
|
||||
activity: string;
|
||||
connectError: string;
|
||||
pendingTool: AgentPendingToolCall | null;
|
||||
setAgentState: (patch: Partial<Omit<CanvasAgentStore, "setAgentState" | "addMessage" | "addEventLog" | "clearEventLogs">>) => void;
|
||||
setAgentState: (patch: Partial<Omit<CanvasAgentStore, "setAgentState" | "connectAgent" | "disconnectAgent" | "addMessage" | "addEventLog" | "clearEventLogs">>) => void;
|
||||
connectAgent: () => void;
|
||||
disconnectAgent: (patch?: Partial<Omit<CanvasAgentStore, "setAgentState" | "connectAgent" | "disconnectAgent" | "addMessage" | "addEventLog" | "clearEventLogs">>) => void;
|
||||
addMessage: (item: AgentChatItem) => void;
|
||||
addEventLog: (item: AgentEventLog) => void;
|
||||
clearEventLogs: () => void;
|
||||
};
|
||||
|
||||
export const useCanvasAgentStore = create<CanvasAgentStore>((set) => ({
|
||||
export const useCanvasAgentStore = create<CanvasAgentStore>((set, get) => ({
|
||||
width: typeof window === "undefined" ? 440 : Number(localStorage.getItem("canvas-agent-panel-width")) || 440,
|
||||
url: typeof window === "undefined" ? "http://127.0.0.1:17371" : localStorage.getItem("canvas-agent-url") || "http://127.0.0.1:17371",
|
||||
token: typeof window === "undefined" ? "" : localStorage.getItem("canvas-agent-token") || "",
|
||||
@@ -59,6 +65,42 @@ export const useCanvasAgentStore = create<CanvasAgentStore>((set) => ({
|
||||
connectError: "",
|
||||
pendingTool: null,
|
||||
setAgentState: (patch) => set(patch),
|
||||
connectAgent: () => {
|
||||
const endpoint = get().url.trim().replace(/\/$/, "");
|
||||
const token = get().token.trim();
|
||||
if (!endpoint || !token) return set({ connectError: "请填写 Local URL 和 Connect token" });
|
||||
try {
|
||||
const parsed = new URL(endpoint);
|
||||
if (!["http:", "https:"].includes(parsed.protocol)) throw new Error();
|
||||
} catch {
|
||||
return set({ connectError: "Local URL 格式不正确" });
|
||||
}
|
||||
get().disconnectAgent({ url: endpoint, token, enabled: true, activity: "连接中", connectError: "" });
|
||||
localStorage.setItem("canvas-agent-url", endpoint);
|
||||
localStorage.setItem("canvas-agent-token", token);
|
||||
const clientId = typeof crypto === "undefined" ? `${Date.now()}` : crypto.randomUUID();
|
||||
const source = new EventSource(`${endpoint}/events?token=${encodeURIComponent(token)}&clientId=${encodeURIComponent(clientId)}&role=status`);
|
||||
agentSource = source;
|
||||
connectTimer = setTimeout(() => {
|
||||
if (agentSource !== source) return;
|
||||
get().disconnectAgent({ activity: "连接超时", connectError: "连接超时:请确认 Canvas Agent 正在运行,并使用当前启动输出的 Connect token" });
|
||||
}, CONNECT_TIMEOUT_MS);
|
||||
source.addEventListener("hello", () => {
|
||||
if (connectTimer) clearTimeout(connectTimer);
|
||||
connectTimer = null;
|
||||
set({ enabled: true, connected: true, activity: "已连接", connectError: "" });
|
||||
});
|
||||
source.onerror = () => {
|
||||
if (agentSource === source) get().disconnectAgent({ activity: "连接失败", connectError: "连接失败:请检查 Local URL、Connect token 或已绑定的网页 Origin" });
|
||||
};
|
||||
},
|
||||
disconnectAgent: (patch = {}) => {
|
||||
agentSource?.close();
|
||||
agentSource = null;
|
||||
if (connectTimer) clearTimeout(connectTimer);
|
||||
connectTimer = null;
|
||||
set({ enabled: false, connected: false, activity: "离线", ...patch });
|
||||
},
|
||||
addMessage: (item) => set((state) => ({ messages: [...state.messages.slice(-120), item] })),
|
||||
addEventLog: (item) => set((state) => ({ eventLogs: [...state.eventLogs.slice(-160), item] })),
|
||||
clearEventLogs: () => set({ eventLogs: [] }),
|
||||
|
||||
Reference in New Issue
Block a user