feat: 实现 Workspace 对话持久化
This commit is contained in:
parent
c2b10ea5c0
commit
2f7d5b2e39
97
src/extensions/shared/workspace/index.ts
Normal file
97
src/extensions/shared/workspace/index.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { homedir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
|
||||
import type { Extension } from "../../../kernel";
|
||||
import { ExtensionId, Hook } from "../../catalog";
|
||||
|
||||
export type MessageRole = "system" | "user" | "assistant";
|
||||
|
||||
export interface ChatMessage {
|
||||
role: MessageRole;
|
||||
content: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface WorkspaceService {
|
||||
home: string;
|
||||
projectPath: string;
|
||||
workspaceId: string;
|
||||
conversationId: string;
|
||||
messages(): Promise<ChatMessage[]>;
|
||||
append(role: MessageRole, content: string): Promise<ChatMessage>;
|
||||
}
|
||||
|
||||
export interface WorkspaceOptions {
|
||||
home?: string;
|
||||
projectPath?: string;
|
||||
conversationId?: string;
|
||||
}
|
||||
|
||||
export function createWorkspaceExtension(options: WorkspaceOptions = {}): Extension {
|
||||
const home = resolve(
|
||||
options.home ?? process.env.LLM_TO_AGENT_HOME ?? join(homedir(), ".llm-to-agent"),
|
||||
);
|
||||
const projectPath = resolve(options.projectPath ?? process.cwd());
|
||||
const workspaceId = createHash("sha256").update(projectPath).digest("hex").slice(0, 16);
|
||||
const conversationId = options.conversationId ?? "default";
|
||||
const workspaceDirectory = join(home, "workspaces", workspaceId);
|
||||
const conversationDirectory = join(workspaceDirectory, "conversations", conversationId);
|
||||
const messagesFile = join(conversationDirectory, "messages.jsonl");
|
||||
|
||||
const workspace: WorkspaceService = {
|
||||
home,
|
||||
projectPath,
|
||||
workspaceId,
|
||||
conversationId,
|
||||
|
||||
async messages() {
|
||||
try {
|
||||
const content = await readFile(messagesFile, "utf8");
|
||||
return content
|
||||
.split("\n")
|
||||
.filter(Boolean)
|
||||
.map((line) => JSON.parse(line) as ChatMessage);
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") return [];
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
async append(role, content) {
|
||||
const message = {
|
||||
role,
|
||||
content,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
await appendFile(messagesFile, `${JSON.stringify(message)}\n`, "utf8");
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
id: ExtensionId.Workspace,
|
||||
|
||||
async setup(context) {
|
||||
await mkdir(conversationDirectory, { recursive: true });
|
||||
await writeFile(
|
||||
join(workspaceDirectory, "workspace.json"),
|
||||
`${JSON.stringify(
|
||||
{
|
||||
id: workspaceId,
|
||||
kind: "linked",
|
||||
projectPath,
|
||||
activeConversationId: conversationId,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
|
||||
context.add(Hook.Workspace, workspace);
|
||||
},
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user