fix(ext): workspaceUri 누락 + WS-only 전송 + user msg dedup
This commit is contained in:
@@ -103,7 +103,7 @@ const recentDiscordSentTexts: Map<string, number> = new Map();
|
|||||||
|
|
||||||
function writeChatSnapshot(text: string) {
|
function writeChatSnapshot(text: string) {
|
||||||
try {
|
try {
|
||||||
// WS route (preferred)
|
// WS route (preferred) — skip file write to prevent duplicate Discord delivery
|
||||||
if (wsBridge && wsBridge.isConnected()) {
|
if (wsBridge && wsBridge.isConnected()) {
|
||||||
wsBridge.sendChat({
|
wsBridge.sendChat({
|
||||||
content: text,
|
content: text,
|
||||||
@@ -111,8 +111,10 @@ function writeChatSnapshot(text: string) {
|
|||||||
project_name: projectName,
|
project_name: projectName,
|
||||||
});
|
});
|
||||||
logToFile(`[SNAPSHOT-WS] sent (${text.length} chars)`);
|
logToFile(`[SNAPSHOT-WS] sent (${text.length} chars)`);
|
||||||
|
if (activeSessionId) { writeRegistration(activeSessionId); }
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// File route (fallback / Phase 0 dual-write)
|
// File route (fallback — only when WS is NOT connected)
|
||||||
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
||||||
if (!fs.existsSync(snapshotDir)) { fs.mkdirSync(snapshotDir, { recursive: true }); }
|
if (!fs.existsSync(snapshotDir)) { fs.mkdirSync(snapshotDir, { recursive: true }); }
|
||||||
const id = Date.now().toString();
|
const id = Date.now().toString();
|
||||||
@@ -136,7 +138,7 @@ function writeChatSnapshot(text: string) {
|
|||||||
|
|
||||||
function writeChatSnapshotWithFiles(text: string, files: Array<{name: string, content: string}>) {
|
function writeChatSnapshotWithFiles(text: string, files: Array<{name: string, content: string}>) {
|
||||||
try {
|
try {
|
||||||
// WS route (preferred)
|
// WS route (preferred) — skip file write to prevent duplicate Discord delivery
|
||||||
if (wsBridge && wsBridge.isConnected()) {
|
if (wsBridge && wsBridge.isConnected()) {
|
||||||
wsBridge.sendChat({
|
wsBridge.sendChat({
|
||||||
content: text,
|
content: text,
|
||||||
@@ -145,8 +147,10 @@ function writeChatSnapshotWithFiles(text: string, files: Array<{name: string, co
|
|||||||
project_name: projectName,
|
project_name: projectName,
|
||||||
});
|
});
|
||||||
logToFile(`[SNAPSHOT-WS] sent with ${files.length} files (${text.length} chars)`);
|
logToFile(`[SNAPSHOT-WS] sent with ${files.length} files (${text.length} chars)`);
|
||||||
|
if (activeSessionId) { writeRegistration(activeSessionId); }
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// File route (fallback)
|
// File route (fallback — only when WS is NOT connected)
|
||||||
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
||||||
if (!fs.existsSync(snapshotDir)) { fs.mkdirSync(snapshotDir, { recursive: true }); }
|
if (!fs.existsSync(snapshotDir)) { fs.mkdirSync(snapshotDir, { recursive: true }); }
|
||||||
const id = Date.now().toString();
|
const id = Date.now().toString();
|
||||||
@@ -1141,6 +1145,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||||||
lastPendingStepIndex,
|
lastPendingStepIndex,
|
||||||
stallProbed,
|
stallProbed,
|
||||||
sawRunningAfterPending,
|
sawRunningAfterPending,
|
||||||
|
clickTrigger,
|
||||||
|
logToFile,
|
||||||
workspaceUri,
|
workspaceUri,
|
||||||
diffReviewMetadata: new Map(),
|
diffReviewMetadata: new Map(),
|
||||||
recentDiscordSentTexts,
|
recentDiscordSentTexts,
|
||||||
|
|||||||
@@ -684,12 +684,21 @@ function setupMonitor() {
|
|||||||
ctx.recentDiscordSentTexts.delete(trimmed);
|
ctx.recentDiscordSentTexts.delete(trimmed);
|
||||||
ctx.logToFile(`[USER-MSG] skipped echo relay (Discord origin, ${Math.round((Date.now()-sentAt)/1000)}s ago)`);
|
ctx.logToFile(`[USER-MSG] skipped echo relay (Discord origin, ${Math.round((Date.now()-sentAt)/1000)}s ago)`);
|
||||||
} else if (umText.length > 2) {
|
} else if (umText.length > 2) {
|
||||||
|
// Content-based dedup: AG can create multiple USER_INPUT steps for the same message
|
||||||
|
// (e.g. comment-while-working feature). Skip if same text relayed within 30s.
|
||||||
|
const dedupKey = `user_msg:${trimmed}`;
|
||||||
|
const lastRelayed = lastSnapshotText.get(dedupKey);
|
||||||
|
if (lastRelayed && (Date.now() - Number(lastRelayed)) < 30_000) {
|
||||||
|
ctx.logToFile(`[USER-MSG] skipped duplicate relay (same text ${Math.round((Date.now() - Number(lastRelayed))/1000)}s ago)`);
|
||||||
|
} else {
|
||||||
|
lastSnapshotText.set(dedupKey, String(Date.now()));
|
||||||
const truncated = umText.length > 800
|
const truncated = umText.length > 800
|
||||||
? umText.substring(0, 800) + '\n\n_(이하 생략)_'
|
? umText.substring(0, 800) + '\n\n_(이하 생략)_'
|
||||||
: umText;
|
: umText;
|
||||||
const source = isFromIDE ? 'AG 직접 입력' : 'API';
|
const source = isFromIDE ? 'AG 직접 입력' : 'API';
|
||||||
ctx.writeChatSnapshot(`👤 **사용자 (${source})**\n\n${truncated}`);
|
ctx.writeChatSnapshot(`👤 **사용자 (${source})**\n\n${truncated}`);
|
||||||
ctx.logToFile(`[USER-MSG] relayed ${umText.length} chars from step ${userInputIdx}`);
|
ctx.logToFile(`[USER-MSG] relayed ${umText.length} chars from step ${userInputIdx}`);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.writeChatSnapshot(`👤 **사용자** — _(내용 없음)_`);
|
ctx.writeChatSnapshot(`👤 **사용자** — _(내용 없음)_`);
|
||||||
ctx.logToFile(`[USER-MSG] step ${userInputIdx} text empty`);
|
ctx.logToFile(`[USER-MSG] step ${userInputIdx} text empty`);
|
||||||
@@ -1220,7 +1229,7 @@ export function writePendingApproval(data: { conversation_id: string; command: s
|
|||||||
...(data.modified_files ? { modified_files: data.modified_files } : {}),
|
...(data.modified_files ? { modified_files: data.modified_files } : {}),
|
||||||
...(data.edit_step_indices && data.edit_step_indices.length > 0 ? { edit_step_indices: data.edit_step_indices } : {}),
|
...(data.edit_step_indices && data.edit_step_indices.length > 0 ? { edit_step_indices: data.edit_step_indices } : {}),
|
||||||
};
|
};
|
||||||
// WS route (preferred) — send pending to Hub before file write
|
// WS route (preferred) — skip file write to prevent duplicate Discord delivery
|
||||||
if (ctx.wsBridge && ctx.wsBridge.isConnected()) {
|
if (ctx.wsBridge && ctx.wsBridge.isConnected()) {
|
||||||
ctx.wsBridge.sendPending({
|
ctx.wsBridge.sendPending({
|
||||||
request_id: id,
|
request_id: id,
|
||||||
@@ -1234,8 +1243,22 @@ export function writePendingApproval(data: { conversation_id: string; command: s
|
|||||||
edit_step_indices: data.edit_step_indices,
|
edit_step_indices: data.edit_step_indices,
|
||||||
});
|
});
|
||||||
ctx.logToFile(`[PENDING-WS] sent pending ${id} cmd="${data.command.substring(0, 60)}"`);
|
ctx.logToFile(`[PENDING-WS] sent pending ${id} cmd="${data.command.substring(0, 60)}"`);
|
||||||
|
// Cache diff_review metadata in-memory (needed for RPC acknowledgement)
|
||||||
|
if (data.step_type === 'diff_review' && (data.edit_step_indices?.length || data.modified_files?.length)) {
|
||||||
|
ctx.diffReviewMetadata.set(id, {
|
||||||
|
edit_step_indices: data.edit_step_indices || [],
|
||||||
|
modified_files: data.modified_files || [],
|
||||||
|
});
|
||||||
|
ctx.logToFile(`[DIFF-REVIEW-CACHE] stored metadata for rid=${id}`);
|
||||||
}
|
}
|
||||||
// File route (fallback / Phase 0 dual-write)
|
// Record in memory dedup
|
||||||
|
if (data.step_index !== undefined && data.conversation_id) {
|
||||||
|
recentPendingSteps.set(`${data.conversation_id}:${data.step_index}`, nowMs);
|
||||||
|
}
|
||||||
|
if (data.conversation_id) { writeRegistration(data.conversation_id); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// File route (fallback — only when WS is NOT connected)
|
||||||
fs.writeFileSync(path.join(pendingDir, `${id}.json`), JSON.stringify(payload, null, 2), 'utf-8');
|
fs.writeFileSync(path.join(pendingDir, `${id}.json`), JSON.stringify(payload, null, 2), 'utf-8');
|
||||||
console.log(`Gravity Bridge: pending approval written → ${id}.json`);
|
console.log(`Gravity Bridge: pending approval written → ${id}.json`);
|
||||||
// Cache diff_review metadata in-memory (survives pending file deletion by Collector/Bot)
|
// Cache diff_review metadata in-memory (survives pending file deletion by Collector/Bot)
|
||||||
|
|||||||
Reference in New Issue
Block a user