Compare commits
3 Commits
feat/Knowl
...
394faa4328
| Author | SHA1 | Date | |
|---|---|---|---|
| 394faa4328 | |||
| 4e06d08106 | |||
| 3b0dca6467 |
@ -42,9 +42,9 @@ const ENV_CONFIG: Record<Environment, IccoderConfig> = {
|
|||||||
},
|
},
|
||||||
/** 测试服务器环境 - 通过 Gateway 路由 */
|
/** 测试服务器环境 - 通过 Gateway 路由 */
|
||||||
test: {
|
test: {
|
||||||
backendUrl: "http://192.168.1.108:2029/iccoder",
|
backendUrl: "http://192.168.1.134:2233",
|
||||||
backendUrlStrongeLoop: "http://192.168.1.108:2029",
|
backendUrlStrongeLoop: "http://192.168.1.134:2233",
|
||||||
loginUrl: "http://192.168.1.108:2005/login",
|
loginUrl: "http://192.168.1.134/login",
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
userId: "default-user",
|
userId: "default-user",
|
||||||
serviceTier: "max",
|
serviceTier: "max",
|
||||||
|
|||||||
@ -90,21 +90,12 @@ export async function selectConversation(
|
|||||||
|
|
||||||
panel.webview.postMessage({ command: "clearChat" });
|
panel.webview.postMessage({ command: "clearChat" });
|
||||||
|
|
||||||
const segments: any[] = [];
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
while (i < taskSession.messages.length) {
|
while (i < taskSession.messages.length) {
|
||||||
const message = taskSession.messages[i];
|
const message = taskSession.messages[i];
|
||||||
|
|
||||||
if (message.type === MessageType.USER) {
|
if (message.type === MessageType.USER) {
|
||||||
if (segments.length > 0) {
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "receiveSegments",
|
|
||||||
segments: [...segments],
|
|
||||||
});
|
|
||||||
segments.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const textContent = message.contents?.find((c) => c.type === "TEXT");
|
const textContent = message.contents?.find((c) => c.type === "TEXT");
|
||||||
if (textContent && "text" in textContent) {
|
if (textContent && "text" in textContent) {
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
@ -115,12 +106,15 @@ export async function selectConversation(
|
|||||||
i++;
|
i++;
|
||||||
} else if (message.type === MessageType.AI) {
|
} else if (message.type === MessageType.AI) {
|
||||||
if (message.segments && message.segments.length > 0) {
|
if (message.segments && message.segments.length > 0) {
|
||||||
|
// 直接发送 segments
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
command: "receiveSegments",
|
command: "receiveSegments",
|
||||||
segments: message.segments,
|
segments: message.segments,
|
||||||
});
|
});
|
||||||
i++;
|
|
||||||
} else {
|
} else {
|
||||||
|
// 构建当前 AI 消息的 segments 并发送
|
||||||
|
const segments: any[] = [];
|
||||||
|
|
||||||
if (message.text) {
|
if (message.text) {
|
||||||
segments.push({ type: "text", content: message.text });
|
segments.push({ type: "text", content: message.text });
|
||||||
}
|
}
|
||||||
@ -138,7 +132,7 @@ export async function selectConversation(
|
|||||||
nextMsg.id === toolReq.id
|
nextMsg.id === toolReq.id
|
||||||
) {
|
) {
|
||||||
toolResult = nextMsg.text;
|
toolResult = nextMsg.text;
|
||||||
i++;
|
i++; // 跳过工具执行结果消息
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,64 +145,26 @@ export async function selectConversation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
if (segments.length > 0) {
|
||||||
|
panel.webview.postMessage({
|
||||||
while (i < taskSession.messages.length) {
|
command: "receiveSegments",
|
||||||
const nextMsg = taskSession.messages[i];
|
segments: segments,
|
||||||
if (nextMsg.type === MessageType.USER) {
|
});
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (nextMsg.type === MessageType.AI) {
|
|
||||||
if (nextMsg.segments && nextMsg.segments.length > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (nextMsg.text) {
|
|
||||||
segments.push({ type: "text", content: nextMsg.text });
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
nextMsg.toolExecutionRequests &&
|
|
||||||
nextMsg.toolExecutionRequests.length > 0
|
|
||||||
) {
|
|
||||||
for (const toolReq of nextMsg.toolExecutionRequests) {
|
|
||||||
let toolResult = "";
|
|
||||||
if (i + 1 < taskSession.messages.length) {
|
|
||||||
const resultMsg = taskSession.messages[i + 1];
|
|
||||||
if (
|
|
||||||
resultMsg.type === MessageType.TOOL_EXECUTION_RESULT &&
|
|
||||||
resultMsg.id === toolReq.id
|
|
||||||
) {
|
|
||||||
toolResult = resultMsg.text;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
segments.push({
|
|
||||||
type: "tool",
|
|
||||||
toolName: toolReq.name,
|
|
||||||
askId: toolReq.id,
|
|
||||||
toolResult: toolResult,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} else if (nextMsg.type === MessageType.TOOL_EXECUTION_RESULT) {
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
i++;
|
i++;
|
||||||
|
} else {
|
||||||
|
// 处理其他类型的消息(如 SYSTEM, TOOL_EXECUTION_RESULT 等)
|
||||||
|
if (message.type === MessageType.TOOL_EXECUTION_RESULT) {
|
||||||
|
// 工具执行结果已经在上面的 AI 消息处理中被处理了,这里跳过
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
// 其他类型消息,如 SYSTEM
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segments.length > 0) {
|
|
||||||
panel.webview.postMessage({
|
|
||||||
command: "receiveSegments",
|
|
||||||
segments: segments,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送任务完成消息(历史记录)
|
// 发送任务完成消息(历史记录)
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
command: "taskCompleteHistory",
|
command: "taskCompleteHistory",
|
||||||
|
|||||||
@ -45,6 +45,8 @@ export interface MessageSegment {
|
|||||||
toolDescription?: string;
|
toolDescription?: string;
|
||||||
askId?: string;
|
askId?: string;
|
||||||
questions?: import("../types/api").QuestionItem[];
|
questions?: import("../types/api").QuestionItem[];
|
||||||
|
answered?: boolean;
|
||||||
|
answers?: { [questionIndex: string]: string[] };
|
||||||
// 智能体相关字段
|
// 智能体相关字段
|
||||||
agentId?: string;
|
agentId?: string;
|
||||||
agentName?: string;
|
agentName?: string;
|
||||||
@ -125,6 +127,7 @@ export class DialogSession {
|
|||||||
private toolContext: ToolExecutorContext;
|
private toolContext: ToolExecutorContext;
|
||||||
private accumulatedText = "";
|
private accumulatedText = "";
|
||||||
private isActive = false;
|
private isActive = false;
|
||||||
|
private wasAbortedByUser = false;
|
||||||
private hasCompleted = false; // 标记是否已收到 complete 事件
|
private hasCompleted = false; // 标记是否已收到 complete 事件
|
||||||
private segments: MessageSegment[] = [];
|
private segments: MessageSegment[] = [];
|
||||||
private currentTextSegment: MessageSegment | null = null;
|
private currentTextSegment: MessageSegment | null = null;
|
||||||
@ -216,6 +219,10 @@ export class DialogSession {
|
|||||||
return this.isActive;
|
return this.isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get abortedByUser(): boolean {
|
||||||
|
return this.wasAbortedByUser;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载知识图谱数据
|
* 加载知识图谱数据
|
||||||
* 从 .iccoder/knowledge.json 读取
|
* 从 .iccoder/knowledge.json 读取
|
||||||
@ -1076,6 +1083,7 @@ export class DialogSession {
|
|||||||
abort(): void {
|
abort(): void {
|
||||||
// 先标记完成,防止 onClose 重复触发
|
// 先标记完成,防止 onClose 重复触发
|
||||||
const wasActive = this.isActive;
|
const wasActive = this.isActive;
|
||||||
|
this.wasAbortedByUser = true;
|
||||||
this.hasCompleted = true;
|
this.hasCompleted = true;
|
||||||
this.isActive = false;
|
this.isActive = false;
|
||||||
|
|
||||||
@ -1125,6 +1133,7 @@ export class DialogSession {
|
|||||||
// 直接调用 receiveAnswer,传递 taskId 作为 fallbackTaskId
|
// 直接调用 receiveAnswer,传递 taskId 作为 fallbackTaskId
|
||||||
// 如果 pendingQuestions 中有问题,走正常流程
|
// 如果 pendingQuestions 中有问题,走正常流程
|
||||||
// 如果没有,receiveAnswer 会使用 fallbackTaskId 直接发送到后端
|
// 如果没有,receiveAnswer 会使用 fallbackTaskId 直接发送到后端
|
||||||
|
this.markQuestionAnswered(askId, selected, customInput, answers);
|
||||||
await userInteractionManager.receiveAnswer(
|
await userInteractionManager.receiveAnswer(
|
||||||
askId,
|
askId,
|
||||||
selected,
|
selected,
|
||||||
@ -1133,6 +1142,30 @@ export class DialogSession {
|
|||||||
this.taskId
|
this.taskId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private markQuestionAnswered(
|
||||||
|
askId: string,
|
||||||
|
selected?: string[],
|
||||||
|
customInput?: string,
|
||||||
|
answers?: { [questionIndex: string]: string[] }
|
||||||
|
): void {
|
||||||
|
const normalizedAnswers =
|
||||||
|
answers && Object.keys(answers).length > 0
|
||||||
|
? answers
|
||||||
|
: { "0": customInput ? [customInput] : selected || [] };
|
||||||
|
|
||||||
|
for (let i = this.segments.length - 1; i >= 0; i--) {
|
||||||
|
const segment = this.segments[i];
|
||||||
|
if (
|
||||||
|
segment.askId === askId &&
|
||||||
|
(segment.type === "question" || segment.type === "plan")
|
||||||
|
) {
|
||||||
|
segment.answered = true;
|
||||||
|
segment.answers = normalizedAnswers;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -362,7 +362,11 @@ async function handleUserMessageWithBackend(
|
|||||||
.map((s) => s.content)
|
.map((s) => s.content)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
await historyManager.addAiMessage(textContent, undefined, segments);
|
const finalText = currentSession?.abortedByUser
|
||||||
|
? `${textContent}\n\n[对话已被用户中止]`
|
||||||
|
: textContent;
|
||||||
|
|
||||||
|
await historyManager.addAiMessage(finalText, undefined, segments);
|
||||||
console.log("[MessageHandler] AI响应已保存到历史记录");
|
console.log("[MessageHandler] AI响应已保存到历史记录");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[MessageHandler] 保存AI响应历史失败:", error);
|
console.error("[MessageHandler] 保存AI响应历史失败:", error);
|
||||||
@ -506,9 +510,11 @@ export async function handleUserAnswer(
|
|||||||
* 中止当前对话
|
* 中止当前对话
|
||||||
*/
|
*/
|
||||||
export async function abortCurrentDialog(): Promise<void> {
|
export async function abortCurrentDialog(): Promise<void> {
|
||||||
if (currentSession) {
|
const session = currentSession;
|
||||||
|
if (false && session) {
|
||||||
|
// 历史保存统一走 onComplete,避免手动中止时重复写入
|
||||||
// 保存当前已有的对话内容
|
// 保存当前已有的对话内容
|
||||||
const segments = currentSession.getSegments();
|
const segments = session!.getSegments();
|
||||||
if (segments && segments.length > 0) {
|
if (segments && segments.length > 0) {
|
||||||
try {
|
try {
|
||||||
const historyManager = ChatHistoryManager.getInstance();
|
const historyManager = ChatHistoryManager.getInstance();
|
||||||
|
|||||||
@ -147,8 +147,10 @@ export function getSegmentRendererScript(): string {
|
|||||||
options: segment.options || [],
|
options: segment.options || [],
|
||||||
multiSelect: false
|
multiSelect: false
|
||||||
}] : []);
|
}] : []);
|
||||||
const isAnswered = answeredQuestions.has(segment.askId);
|
const segmentAnswers = segment.answers || {};
|
||||||
const savedAnswers = answeredQuestions.get(segment.askId) || {};
|
const runtimeAnswers = answeredQuestions.get(segment.askId) || {};
|
||||||
|
const savedAnswers = Object.keys(segmentAnswers).length > 0 ? segmentAnswers : runtimeAnswers;
|
||||||
|
const isAnswered = segment.answered === true || answeredQuestions.has(segment.askId);
|
||||||
if (isAnswered) {
|
if (isAnswered) {
|
||||||
segmentDiv.classList.add('answered');
|
segmentDiv.classList.add('answered');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -894,6 +894,9 @@ export function getWebviewContent(
|
|||||||
if (messagesContainer) {
|
if (messagesContainer) {
|
||||||
messagesContainer.innerHTML = '';
|
messagesContainer.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
if (typeof answeredQuestions !== 'undefined' && answeredQuestions.clear) {
|
||||||
|
answeredQuestions.clear();
|
||||||
|
}
|
||||||
// 重置输入框布局到居中
|
// 重置输入框布局到居中
|
||||||
if (typeof window.resetInputAreaLayout === 'function') {
|
if (typeof window.resetInputAreaLayout === 'function') {
|
||||||
window.resetInputAreaLayout();
|
window.resetInputAreaLayout();
|
||||||
|
|||||||
Reference in New Issue
Block a user