59 lines
2.7 KiB
TypeScript
59 lines
2.7 KiB
TypeScript
import { type Express } from "express";
|
|
import { z } from "zod";
|
|
import { executeMemoryManager, executeSkillManager } from "../learning/toolManagers.js";
|
|
import { type MemoryStore } from "../memory/store.js";
|
|
import { isTrustedInternalBridgeRequest } from "../product/internal-bridge-auth.js";
|
|
import { getRuntimeSessionContext } from "../runtime/sessionContext.js";
|
|
import { type SkillStore } from "../skills/store.js";
|
|
|
|
const memoryInput = z.object({
|
|
action: z.enum(["add", "list", "replace", "remove"]),
|
|
scope: z.string().max(32),
|
|
reason: z.string().trim().min(1).max(2000).optional(),
|
|
content: z.string().max(20000).optional(),
|
|
target_id: z.string().max(128).optional(),
|
|
}).strict().refine((input) => input.action === "list" || Boolean(input.reason), {
|
|
path: ["reason"], message: "reason is required for writes, updates and removals",
|
|
});
|
|
const skillInput = z.object({
|
|
action: z.enum(["list", "write_skill", "remove_skill", "append_pattern", "remove_pattern", "write_reference", "remove_reference", "write_script", "remove_script"]),
|
|
skill_path: z.string().max(512),
|
|
reason: z.string().trim().min(1).max(2000).optional(),
|
|
content: z.string().max(200000).optional(),
|
|
file_path: z.string().max(512).optional(),
|
|
pattern: z.string().max(20000).optional(),
|
|
target_id: z.string().max(128).optional(),
|
|
}).strict().refine((input) => input.action === "list" || Boolean(input.reason), {
|
|
path: ["reason"], message: "reason is required for writes, updates and removals",
|
|
});
|
|
|
|
export const registerLearningToolBridge = (app: Express, options: {
|
|
internalToken: string;
|
|
memoryStore: MemoryStore;
|
|
skillStore: SkillStore;
|
|
}) => {
|
|
for (const name of ["memory-manager", "skill-manager"] as const) {
|
|
app.post(`/internal/tools/${name}`, async (req, res) => {
|
|
if (!isTrustedInternalBridgeRequest(req, options.internalToken)) {
|
|
res.status(403).json({ message: "forbidden" });
|
|
return;
|
|
}
|
|
const context = typeof req.body?.session_id === "string"
|
|
? getRuntimeSessionContext(req.body.session_id) : null;
|
|
if (!context) {
|
|
res.status(404).json({ message: "session context not found" });
|
|
return;
|
|
}
|
|
if (name === "memory-manager") {
|
|
const input = memoryInput.safeParse(req.body.input);
|
|
if (!input.success) { res.status(400).json({ message: "invalid memory input" }); return; }
|
|
res.json(await executeMemoryManager(options.memoryStore, context, input.data));
|
|
} else {
|
|
const input = skillInput.safeParse(req.body.input);
|
|
if (!input.success) { res.status(400).json({ message: "invalid skill input" }); return; }
|
|
res.json(await executeSkillManager(options.skillStore, context, input.data));
|
|
}
|
|
});
|
|
}
|
|
};
|