新增调用前端分区渲染功能,节点通过 ref 文件传输,并增加简单认证

This commit is contained in:
2026-05-18 16:21:23 +08:00
parent 3e3deaa724
commit 69a90de9a1
4 changed files with 89 additions and 4 deletions
+16
View File
@@ -0,0 +1,16 @@
import { tool } from "@opencode-ai/plugin";
export default tool({
description: "在前端地图上对 junctions 图层应用分区渲染。",
args: {
reason: tool.schema
.string()
.describe("Why this junction rendering action is needed for the user request."),
render_ref: tool.schema
.string()
.describe("Reference to a stored junction rendering payload resolved by the Agent service."),
},
async execute() {
return "已在地图上应用节点分区渲染。";
},
});
+25 -3
View File
@@ -45,6 +45,7 @@ export type StoreResultInput = {
export type RetrievalContext = {
actorKey: string;
clientSessionId?: string;
maxItems?: number;
projectId?: string;
};
@@ -105,18 +106,33 @@ export class ResultReferenceStore {
return record;
}
async getAuthorized(resultRef: string, context: RetrievalContext) {
async getAuthorized(resultRef: string, context: RetrievalContext) {
const record = await this.readAuthorizedRecord(resultRef, context);
if (!record) {
return null;
}
const data = projectData(record.data, context.maxItems ?? config.RESULT_REF_MAX_RETRIEVAL_ITEMS);
return {
ok: true,
result_ref: record.resultRef,
result_size_bytes: record.sizeBytes,
stored_at: record.createdAt,
data,
preview: record.preview,
};
}
async getFullAuthorized(resultRef: string, context: RetrievalContext) {
const record = await this.readAuthorizedRecord(resultRef, context);
if (!record) {
return null;
}
const data = projectData(record.data, context.maxItems ?? config.RESULT_REF_MAX_RETRIEVAL_ITEMS);
return {
ok: true,
result_ref: record.resultRef,
result_size_bytes: record.sizeBytes,
stored_at: record.createdAt,
data,
data: record.data,
preview: record.preview,
};
}
@@ -173,6 +189,12 @@ export class ResultReferenceStore {
if ((record.projectId ?? "") !== (context.projectId ?? "")) {
return null;
}
if (
context.clientSessionId &&
record.clientSessionId !== context.clientSessionId
) {
return null;
}
return record;
}
}
+41
View File
@@ -5,9 +5,11 @@ import { z } from "zod";
import { type LearningOrchestrator } from "../learning/orchestrator.js";
import { logger } from "../logger.js";
import { MemoryStore } from "../memory/store.js";
import { type ResultReferenceStore } from "../results/store.js";
import { type OpencodeRuntimeAdapter } from "../runtime/opencode.js";
import { type ChatSessionBridge } from "../chat/sessionBridge.js";
import { writeLlmRequestAuditLog } from "../audit/llmRequestAudit.js";
import { toActorKey } from "../utils/fileStore.js";
const supportedModels = [
"deepseek/deepseek-v4-flash",
@@ -36,9 +38,47 @@ export const buildChatRouter = (
runtime: OpencodeRuntimeAdapter,
memoryStore: MemoryStore,
learningOrchestrator: LearningOrchestrator,
resultReferenceStore: ResultReferenceStore,
) => {
const chatRouter = Router();
chatRouter.get("/render-ref/:renderRef", async (req, res) => {
const renderRef = req.params.renderRef?.trim();
const userId = req.header("x-user-id")?.trim();
const projectId = req.header("x-project-id") ?? undefined;
const clientSessionId =
typeof req.query.session_id === "string"
? req.query.session_id.trim()
: undefined;
if (!userId) {
res.status(400).json({
message: "x-user-id is required",
});
return;
}
if (!renderRef) {
res.status(400).json({
message: "render_ref is required",
});
return;
}
const result = await resultReferenceStore.getFullAuthorized(renderRef, {
actorKey: toActorKey(userId),
clientSessionId,
projectId,
});
if (!result) {
res.status(404).json({ message: "render_ref not found" });
return;
}
res.json(result);
});
chatRouter.post("/abort", async (req, res) => {
const parsed = abortPayloadSchema.safeParse(req.body);
if (!parsed.success) {
@@ -1037,6 +1077,7 @@ const toolLabels: Record<string, string> = {
view_history: "历史数据面板",
view_scada: "SCADA 面板",
show_chart: "图表渲染",
render_junctions: "节点渲染",
};
const buildPromptWithLearningContext = async (
+7 -1
View File
@@ -172,7 +172,13 @@ app.post("/internal/tools/session-search", async (req, res) => {
app.use(
"/api/v1/agent/chat",
buildChatRouter(sessionBridge, opencodeRuntime, memoryStore, learningOrchestrator),
buildChatRouter(
sessionBridge,
opencodeRuntime,
memoryStore,
learningOrchestrator,
resultReferenceStore,
),
);
const bootstrap = async () => {