UNPKG

@langgraph-js/sdk

Version:

The UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces

99 lines (98 loc) 3.83 kB
import { atom, effect } from "nanostores"; export * from "./types.js"; import { ToolRenderData } from "../tool/ToolUI.js"; // 创建 artifacts computed store const extractArtifactsFromMessages = (renderMessages, client) => { const files = new Map(); for (const message of renderMessages) { if (message.type === "tool" && message.name === "create_artifacts") { const tool = new ToolRenderData(message, client); const command = tool.getInputRepaired(); if (!command.id) continue; command.tool_id = tool.message.id; command.is_done = tool.state === "done"; files.set(command.id, [...(files.get(command.id) || []), command]); } } const composedFiles = new Map(); // 遍历每个 ID 的命令序列,生成对应的 artifact 版本 for (const [id, commands] of files) { const artifacts = []; let currentContent = ""; let currentFilename = ""; let currentFiletype = ""; let version = 1; // 按命令顺序处理每个操作 for (const command of commands) { switch (command.command) { case "create": // 创建新 artifact,直接使用 content currentContent = command.content; currentFilename = command.title || `artifact-${id}`; currentFiletype = command.type || command.language; break; case "update": // 更新现有内容,使用 old_str 和 new_str 进行替换 if (command.old_str && command.new_str) { currentContent = currentContent.replace(command.old_str, command.new_str); } else if (command.content) { // 如果没有 old_str/new_str,则直接使用 content 覆盖 currentContent = command.content; } break; case "rewrite": currentContent = command.content; break; } // 创建当前版本的 artifact const artifact = { group_id: id, id: command.tool_id, code: currentContent, filename: currentFilename, filetype: currentFiletype, version: version, is_done: command.is_done, }; artifacts.push(artifact); version++; } composedFiles.set(id, artifacts); } return [...composedFiles.values()].map((artifacts) => ({ id: artifacts[0].group_id, filename: artifacts[artifacts.length - 1].filename, filetype: artifacts[artifacts.length - 1].filetype, versions: artifacts, })); }; export const useArtifacts = (renderMessages, client) => { // 创建 artifacts store const showArtifact = atom(false); const currentArtifactId = atom(null); const artifacts = atom([]); effect([renderMessages, client], () => { artifacts.set(extractArtifactsFromMessages(renderMessages.get(), client.get())); }); const debouncedSetCurrentArtifactById = (id, tool_id) => { const current = currentArtifactId.get(); if (current?.[0] === id && current?.[1] === tool_id) { return; } showArtifact.set(true); currentArtifactId.set([id, tool_id]); }; return { data: { artifacts, currentArtifactId, showArtifact, }, mutation: { setCurrentArtifactById: debouncedSetCurrentArtifactById, setShowArtifact: (show) => showArtifact.set(show), }, }; };