chore: version up to 2.80.34 and package
This commit is contained in:
@@ -169,6 +169,140 @@
|
||||
const skillFolderList = document.getElementById('skillFolderList');
|
||||
const agentMapAgentName = document.getElementById('agentMapAgentName');
|
||||
const agentMapStatus = document.getElementById('agentMapStatus');
|
||||
const readyBar = document.getElementById('readyBar');
|
||||
const rbDot = document.getElementById('rbDot');
|
||||
const rbContent = document.getElementById('rbContent');
|
||||
const ctxBadge = document.getElementById('ctxBadge');
|
||||
|
||||
// ── Ready-status bar ─────────────────────────────────────────────────
|
||||
let readyState = {};
|
||||
function fmtK(n) {
|
||||
if (typeof n !== 'number' || !isFinite(n)) return '?';
|
||||
if (n >= 1000) return (n / 1000).toFixed(n >= 10000 ? 0 : 1).replace(/\.0$/, '') + 'k';
|
||||
return String(n);
|
||||
}
|
||||
function renderReadyBar() {
|
||||
if (!readyBar || !rbContent) return;
|
||||
const s = readyState;
|
||||
const segs = [];
|
||||
// Engine
|
||||
if (s.engine) {
|
||||
const on = s.engine.online;
|
||||
const tag = on === true ? '온라인' : on === false ? '오프라인' : '확인 중';
|
||||
segs.push(`<span class="rb-seg ${on === false ? 'bad' : on === true ? 'ok' : ''}">${s.engine.label || 'Engine'}: ${tag}</span>`);
|
||||
}
|
||||
// Model
|
||||
if (s.model && s.model.name) {
|
||||
const loaded = s.model.loaded;
|
||||
const dot = loaded === true ? '● ' : loaded === false ? '○ ' : '';
|
||||
segs.push(`<span class="rb-seg" title="${loaded === true ? '메모리에 로드됨' : loaded === false ? '아직 로드되지 않음' : ''}">${dot}${escAttr(s.model.name)}</span>`);
|
||||
}
|
||||
// Brain
|
||||
if (s.brain) {
|
||||
segs.push(`<span class="rb-seg">Brain ${typeof s.brain.files === 'number' ? s.brain.files : '?'}<span class="rb-dim"> ${escAttr(s.brain.name || '')}</span></span>`);
|
||||
}
|
||||
// Agent + scope
|
||||
if (s.agent && s.agent.name) {
|
||||
const scope = s.agent.scopeFolders > 0
|
||||
? ` <span class="rb-link" data-act="map">(범위 ${s.agent.scopeFolders})</span>`
|
||||
: ` <span class="rb-dim">(범위 미설정)</span>`;
|
||||
segs.push(`<span class="rb-seg">Agent: ${escAttr(s.agent.name)}${scope}</span>`);
|
||||
} else {
|
||||
segs.push(`<span class="rb-seg rb-dim">Agent 없음</span>`);
|
||||
}
|
||||
// Memory
|
||||
segs.push(`<span class="rb-seg ${s.memory ? '' : 'rb-dim'}">메모리 ${s.memory ? '켜짐' : '꺼짐'}</span>`);
|
||||
// Multi-agent (only when on)
|
||||
if (s.multiAgent) segs.push(`<span class="rb-seg">멀티에이전트</span>`);
|
||||
// Context window (capped for small models gets a ↓ marker)
|
||||
if (typeof s.contextLength === 'number') {
|
||||
if (s.cappedForSmallModel) {
|
||||
segs.push(`<span class="rb-seg" title="작은 모델(≤4B) 감지 — 예산을 ${fmtK(s.contextLength)} tokens 로 축소 (설정 g1nation.contextLength = ${fmtK(s.nominalContextLength)}). g1nation.smallModelContextCap 로 조절.">ctx ${fmtK(s.contextLength)}<span class="rb-dim"> ↓작은모델</span></span>`);
|
||||
} else {
|
||||
segs.push(`<span class="rb-seg" title="모델 context window (g1nation.contextLength). 실제 로드된 값과 맞춰주세요.">ctx ${fmtK(s.contextLength)}</span>`);
|
||||
}
|
||||
}
|
||||
rbContent.innerHTML = segs.join('<span class="rb-sep">·</span>');
|
||||
if (rbDot) {
|
||||
const on = s.engine && s.engine.online;
|
||||
rbDot.className = 'rb-dot ' + (on === true ? 'ok' : on === false ? 'bad' : 'warn');
|
||||
}
|
||||
}
|
||||
function escAttr(t) { return String(t == null ? '' : t).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); }
|
||||
|
||||
// ── Context-budget badge (직전 요청 기준) ────────────────────────────
|
||||
function renderCtxBadge(b) {
|
||||
if (!ctxBadge) return;
|
||||
if (!b || typeof b.inputTokens !== 'number') { ctxBadge.textContent = ''; ctxBadge.className = 'ctx-badge'; ctxBadge.title = ''; return; }
|
||||
const parts = [`≈${fmtK(b.inputTokens)} in / ${fmtK(b.maxOutputTokens)} out`];
|
||||
if (typeof b.contextLength === 'number') {
|
||||
parts.push(b.cappedForSmallModel ? `ctx ${fmtK(b.contextLength)}↓` : `ctx ${fmtK(b.contextLength)}`);
|
||||
}
|
||||
if (typeof b.brainFiles === 'number' && b.brainFiles > 0) parts.push(`Brain ${b.brainFiles}`);
|
||||
if (b.includesOpenFile) parts.push('📄 열린 파일');
|
||||
if (b.imageCount > 0) parts.push(`🖼 ${b.imageCount}`);
|
||||
if (b.droppedHistory > 0) parts.push(`기록 −${b.droppedHistory}`);
|
||||
if (b.systemTruncated) parts.push('컨텍스트 일부 생략');
|
||||
if (b.cappedForSmallModel) parts.push('🔻 작은 모델 모드');
|
||||
if (b.tight) parts.push('⚠ 컨텍스트 거의 가득');
|
||||
const warn = b.tight || b.systemTruncated;
|
||||
ctxBadge.textContent = parts.join(' · ');
|
||||
ctxBadge.className = 'ctx-badge' + (warn ? ' warn' : ' ok');
|
||||
ctxBadge.title = `model: ${b.model || ''}${b.paramB != null ? ' (~' + b.paramB + 'B)' : ''}\n입력 ≈ ${b.inputTokens} tokens (시스템 ${b.systemTokens}, 기록 ${b.historyKept}개)\n출력 상한 ${b.maxOutputTokens} tokens / 유효 context window ${b.contextLength} tokens${b.cappedForSmallModel ? ' (작은 모델용 축소; 설정값 ' + b.nominalContextLength + ')' : ''}`;
|
||||
}
|
||||
if (readyBar) {
|
||||
readyBar.addEventListener('click', e => {
|
||||
const t = e.target;
|
||||
if (t && t.dataset && t.dataset.act === 'map') vscode.postMessage({ type: 'editKnowledgeMap' });
|
||||
});
|
||||
}
|
||||
|
||||
// ── Per-answer "scope used" footer ──────────────────────────────────
|
||||
const MEMORY_LAYER_LABELS = {
|
||||
'long-term-memory': '장기기억',
|
||||
'project-memory': '프로젝트기억',
|
||||
'procedural-memory': '절차기억',
|
||||
'episodic-memory': '에피소드기억',
|
||||
'project-scan': '프로젝트스캔',
|
||||
'recent-knowledge': '최근지식',
|
||||
};
|
||||
function dirOf(rel) {
|
||||
const i = Math.max(rel.lastIndexOf('/'), rel.lastIndexOf('\\'));
|
||||
return i > 0 ? rel.slice(0, i) : '(루트)';
|
||||
}
|
||||
function renderScopeFooter(target, v) {
|
||||
if (!target) return;
|
||||
const old = target.querySelector('.msg-scope-footer');
|
||||
if (old) old.remove();
|
||||
const footer = document.createElement('div');
|
||||
footer.className = 'msg-scope-footer';
|
||||
const files = Array.isArray(v.usedBrainFiles) ? v.usedBrainFiles : [];
|
||||
const layers = (Array.isArray(v.usedMemoryLayers) ? v.usedMemoryLayers : []).map(s => MEMORY_LAYER_LABELS[s] || s);
|
||||
if (files.length === 0 && layers.length === 0) {
|
||||
footer.innerHTML = `<span class="scope-link" data-act="map" title="에이전트↔지식 매핑 편집">🔎 참조 지식 없음</span> <span class="scope-dim">— 모델 자체 지식으로 답변</span>`;
|
||||
} else {
|
||||
const dirs = Array.from(new Set(files.map(dirOf)));
|
||||
let scopeLabel;
|
||||
if (v.scoped && Array.isArray(v.configuredFolders) && v.configuredFolders.length) {
|
||||
scopeLabel = v.configuredFolders.join(', ');
|
||||
} else if (dirs.length) {
|
||||
scopeLabel = dirs.slice(0, 4).join(', ') + (dirs.length > 4 ? ` 외 ${dirs.length - 4}` : '');
|
||||
} else {
|
||||
scopeLabel = '전체 브레인';
|
||||
}
|
||||
const agentTag = v.agentName ? `[${escAttr(v.agentName)}] ` : '';
|
||||
const fileTag = files.length ? ` <span class="scope-dim">· 파일 ${files.length}</span>` : '';
|
||||
const layerTag = layers.length ? ` <span class="scope-dim">· 메모리 ${escAttr(layers.join('·'))}</span>` : '';
|
||||
const titleAttr = files.length ? `사용된 브레인 파일:\n${files.join('\n')}` : '에이전트↔지식 매핑 편집';
|
||||
footer.innerHTML = `<span class="scope-link" data-act="map" title="${escAttr(titleAttr)}">🔎 참조: ${agentTag}${escAttr(scopeLabel)}</span>${fileTag}${layerTag}`;
|
||||
}
|
||||
footer.addEventListener('click', e => {
|
||||
const t = e.target;
|
||||
if (t && t.dataset && t.dataset.act === 'map') vscode.postMessage({ type: 'editKnowledgeMap' });
|
||||
});
|
||||
const actions = target.querySelector('.msg-actions');
|
||||
if (actions) target.insertBefore(footer, actions); else target.appendChild(footer);
|
||||
}
|
||||
|
||||
let agentMapDraft = { agentPath: '', name: '', knowledgeFolders: [], skillFolders: [] };
|
||||
|
||||
@@ -348,6 +482,7 @@
|
||||
setGenerating(false);
|
||||
resetStepper();
|
||||
Sound.success();
|
||||
vscode.postMessage({ type: 'getReadyStatus' });
|
||||
break;
|
||||
case 'restoreHistory':
|
||||
case 'sessionLoaded':
|
||||
@@ -433,7 +568,25 @@
|
||||
case 'engineStatus':
|
||||
statusDot.style.background = msg.value.online ? 'var(--success)' : 'var(--error)';
|
||||
engineStatusText.innerText = msg.value.online ? 'Online' : 'Offline';
|
||||
readyState.engine = Object.assign({}, readyState.engine, { online: !!msg.value.online });
|
||||
renderReadyBar();
|
||||
break;
|
||||
case 'readyStatus':
|
||||
readyState = Object.assign({}, readyState, msg.value || {});
|
||||
renderReadyBar();
|
||||
break;
|
||||
case 'contextBudget':
|
||||
renderCtxBadge(msg.value);
|
||||
break;
|
||||
case 'usedScope': {
|
||||
let target = streamBody && streamBody._parent;
|
||||
if (!target) {
|
||||
const all = chat.querySelectorAll('.msg.msg-ai');
|
||||
target = all[all.length - 1];
|
||||
}
|
||||
renderScopeFooter(target, msg.value || {});
|
||||
break;
|
||||
}
|
||||
case 'autoContinue':
|
||||
statusLabel.innerText = msg.value; thinkingBar.classList.add('active');
|
||||
if (msg.value.includes('Analyzing')) setStep('analyze');
|
||||
|
||||
Reference in New Issue
Block a user