新增 memory 和 skill 存储,实现 Agent 持续学习,并增加工具支持;增加 LLM progress detail 输出
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import { tool } from "@opencode-ai/plugin";
|
||||
import { MemoryStore } from "../../src/memory/store.js";
|
||||
import { ToolSessionContextStore } from "../../src/session/toolContextStore.js";
|
||||
|
||||
const memoryStore = new MemoryStore();
|
||||
const toolContextStore = new ToolSessionContextStore();
|
||||
const initializePromise = Promise.all([
|
||||
memoryStore.initialize(),
|
||||
toolContextStore.initialize(),
|
||||
]);
|
||||
|
||||
const MEMORY_SIGNAL_TYPES = new Set([
|
||||
"user_preference",
|
||||
"user_constraint",
|
||||
"project_fact",
|
||||
"environment_fact",
|
||||
"agent_correction",
|
||||
]);
|
||||
|
||||
const isSignalAllowedForScope = (scope: string, signalType: string) => {
|
||||
if (!MEMORY_SIGNAL_TYPES.has(signalType)) {
|
||||
return false;
|
||||
}
|
||||
if (scope === "user") {
|
||||
return signalType === "user_preference" || signalType === "user_constraint";
|
||||
}
|
||||
if (scope === "workspace") {
|
||||
return (
|
||||
signalType === "project_fact" ||
|
||||
signalType === "environment_fact" ||
|
||||
signalType === "agent_correction"
|
||||
);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export default tool({
|
||||
description:
|
||||
"将高置信度、长期有效的用户偏好或项目事实写入持久 memory。禁止写入 token、password、secret、system prompt 或一次性上下文。",
|
||||
args: {
|
||||
reason: tool.schema
|
||||
.string()
|
||||
.describe("Why this memory should be persisted for future requests."),
|
||||
scope: tool.schema
|
||||
.string()
|
||||
.describe("Target memory scope: 'user' for user preferences, 'workspace' for project/environment facts."),
|
||||
signal_type: tool.schema
|
||||
.string()
|
||||
.describe("Signal type, e.g. user_preference, user_constraint, project_fact, environment_fact."),
|
||||
confidence: tool.schema
|
||||
.number()
|
||||
.describe("Confidence between 0 and 1. Only high-confidence memories should be persisted."),
|
||||
content: tool.schema
|
||||
.string()
|
||||
.describe("The durable fact or preference to remember, written as one concise sentence."),
|
||||
},
|
||||
async execute(args, context) {
|
||||
await initializePromise;
|
||||
const sessionContext = await toolContextStore.read(context.sessionID);
|
||||
if (!sessionContext) {
|
||||
throw new Error(`session context not found for ${context.sessionID}`);
|
||||
}
|
||||
if (!isSignalAllowedForScope(args.scope, args.signal_type)) {
|
||||
return JSON.stringify({
|
||||
ok: true,
|
||||
kind: "memory",
|
||||
decision: "rejected",
|
||||
detail: `signal_type ${args.signal_type} is not allowed for scope ${args.scope}`,
|
||||
});
|
||||
}
|
||||
if (args.confidence < 0.8) {
|
||||
return JSON.stringify({
|
||||
ok: true,
|
||||
kind: "memory",
|
||||
decision: "rejected",
|
||||
detail: "confidence below memory threshold",
|
||||
});
|
||||
}
|
||||
|
||||
const scope = args.scope === "user" ? "user" : args.scope === "workspace" ? "workspace" : null;
|
||||
if (!scope) {
|
||||
return JSON.stringify({
|
||||
ok: true,
|
||||
kind: "memory",
|
||||
decision: "rejected",
|
||||
detail: `unsupported scope: ${args.scope}`,
|
||||
});
|
||||
}
|
||||
|
||||
const scopeKey = scope === "user" ? sessionContext.actorKey : sessionContext.projectKey;
|
||||
const result = await memoryStore.upsert(scope, scopeKey, {
|
||||
content: args.content,
|
||||
sessionId: context.sessionID,
|
||||
source: "tool",
|
||||
traceId: sessionContext.traceId,
|
||||
});
|
||||
|
||||
if (!result.entry) {
|
||||
return JSON.stringify({
|
||||
ok: true,
|
||||
kind: "memory",
|
||||
decision: "rejected",
|
||||
detail: "content rejected by persistence policy",
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
ok: true,
|
||||
kind: "memory",
|
||||
decision: result.changed ? "accepted" : "deduped",
|
||||
detail: result.changed ? "memory stored" : "memory already existed",
|
||||
target: scope,
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user