LLM-driven 设计,添加学习审计和会话历史存储至目录的功能
This commit is contained in:
+33
-4
@@ -2,6 +2,7 @@ import type { Event as OpencodeEvent, Part } from "@opencode-ai/sdk/v2";
|
||||
import { Router } from "express";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type LearningOrchestrator } from "../learning/orchestrator.js";
|
||||
import { logger } from "../logger.js";
|
||||
import { MemoryStore } from "../memory/store.js";
|
||||
import { type OpencodeRuntimeAdapter } from "../runtime/opencode.js";
|
||||
@@ -34,6 +35,7 @@ export const buildChatRouter = (
|
||||
sessionBridge: ChatSessionBridge,
|
||||
runtime: OpencodeRuntimeAdapter,
|
||||
memoryStore: MemoryStore,
|
||||
learningOrchestrator: LearningOrchestrator,
|
||||
) => {
|
||||
const chatRouter = Router();
|
||||
|
||||
@@ -229,6 +231,11 @@ export const buildChatRouter = (
|
||||
});
|
||||
|
||||
if (!streamResult.aborted && !streamResult.failed) {
|
||||
const messages = await runtime.messages(binding.sessionId, 60);
|
||||
const assistantMessage = [...messages]
|
||||
.reverse()
|
||||
.find((message) => message.info.role === "assistant");
|
||||
const assistantText = collectTextContent(assistantMessage?.parts ?? []);
|
||||
const existingSessionTitle = sessionBridge.getSessionTitle(binding.sessionId);
|
||||
let sessionTitle = existingSessionTitle;
|
||||
const shouldGenerateTitle =
|
||||
@@ -251,6 +258,21 @@ export const buildChatRouter = (
|
||||
);
|
||||
}
|
||||
}
|
||||
if (assistantText) {
|
||||
void learningOrchestrator.onTurnCompleted({
|
||||
assistantMessage: assistantText,
|
||||
model: parsed.data.model,
|
||||
requestContext,
|
||||
sessionId: binding.sessionId,
|
||||
toolCallCount: streamResult.toolCallCount,
|
||||
userMessage: parsed.data.message,
|
||||
}).catch((error) => {
|
||||
logger.warn(
|
||||
{ err: error, sessionId: binding.sessionId },
|
||||
"post-turn learning failed",
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
streamClosed = true;
|
||||
@@ -385,7 +407,11 @@ const streamPromptResponse = async ({
|
||||
projectId,
|
||||
signal,
|
||||
write,
|
||||
}: StreamPromptOptions): Promise<{ aborted: boolean; failed: boolean }> => {
|
||||
}: StreamPromptOptions): Promise<{
|
||||
aborted: boolean;
|
||||
failed: boolean;
|
||||
toolCallCount: number;
|
||||
}> => {
|
||||
const eventStream = await runtime.subscribeEvents();
|
||||
const iterator = eventStream[Symbol.asyncIterator]();
|
||||
const requestStartedAt = Date.now();
|
||||
@@ -396,6 +422,7 @@ const streamPromptResponse = async ({
|
||||
const pendingPartTextDeltas = new Map<string, string[]>();
|
||||
const reasoningDeltas = new Map<string, string[]>();
|
||||
let emittedText = false;
|
||||
let toolCallCount = 0;
|
||||
let done = false;
|
||||
let promptSettled = false;
|
||||
let aborted = signal?.aborted ?? false;
|
||||
@@ -624,6 +651,7 @@ const streamPromptResponse = async ({
|
||||
(hasToolParams(toolParams) || isToolFinalState)
|
||||
) {
|
||||
emittedToolParts.add(part.id);
|
||||
toolCallCount += 1;
|
||||
if (!reason) {
|
||||
logger.warn(
|
||||
{
|
||||
@@ -704,11 +732,11 @@ const streamPromptResponse = async ({
|
||||
await runtime.abortSession(opencodeSessionId).catch((error) => {
|
||||
logger.warn({ sessionId: opencodeSessionId, err: error }, "failed to abort opencode session");
|
||||
});
|
||||
return { aborted: true, failed: false };
|
||||
return { aborted: true, failed: false, toolCallCount };
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
return { aborted: false, failed: true };
|
||||
return { aborted: false, failed: true, toolCallCount };
|
||||
}
|
||||
|
||||
await promptPromise;
|
||||
@@ -735,7 +763,7 @@ const streamPromptResponse = async ({
|
||||
session_id: clientSessionId,
|
||||
total_duration_ms: Math.max(0, Date.now() - requestStartedAt),
|
||||
});
|
||||
return { aborted: false, failed: false };
|
||||
return { aborted: false, failed: false, toolCallCount };
|
||||
} finally {
|
||||
await iterator.return?.(undefined);
|
||||
if (!promptSettled) {
|
||||
@@ -1003,6 +1031,7 @@ const toolLabels: Record<string, string> = {
|
||||
dynamic_http_call: "后端数据查询",
|
||||
fetch_result_ref: "结果引用回读",
|
||||
memory_manager: "记忆写入",
|
||||
session_search: "历史会话检索",
|
||||
skill_manager: "流程沉淀",
|
||||
locate_features: "地图定位",
|
||||
view_history: "历史数据面板",
|
||||
|
||||
Reference in New Issue
Block a user