diff --git a/context-runtime-profile.mjs b/context-runtime-profile.mjs index 3b8aa83..a962395 100644 --- a/context-runtime-profile.mjs +++ b/context-runtime-profile.mjs @@ -21,6 +21,16 @@ export const CONTEXT_RUNTIME_SHADOW_ENV = Object.freeze({ MEMIND_ZVEC_WORKSPACE_MODE: 'shadow', }); +/** Local active bundle (MCP/ budget / recall / zvec / headroom). Injection stays shadow separately. */ +export const CONTEXT_RUNTIME_ACTIVE_ENV = Object.freeze({ + MEMIND_HEADROOM_MODE: 'active', + MEMIND_CONTEXT_BUDGET_MODE: 'active', + MEMIND_RECALL_FUSION_MODE: 'active', + MEMIND_MCP_COMPACT_MODE: 'active', + MEMIND_ZVEC_WORKSPACE_MODE: 'active', + HEADROOM_OUTPUT_SHAPER: '0', +}); + export function describeContextRuntimeProfile(env = process.env) { return { headroom: resolveHeadroomMode(env), diff --git a/docs/context-runtime-local-dev.md b/docs/context-runtime-local-dev.md index 8ad2884..708c81a 100644 --- a/docs/context-runtime-local-dev.md +++ b/docs/context-runtime-local-dev.md @@ -24,23 +24,25 @@ MEMIND_ZVEC_WORKSPACE_MODE=shadow HEADROOM_OUTPUT_SHAPER=0 ``` -**混合晋升(逐项 active)**:shadow 证据足够后,每次只改一个开关,例如: - -```bash -MEMIND_MCP_COMPACT_MODE=active # 其余保持 shadow -``` - -验证: - -```bash -node scripts/check-mcp-compactor-local.mjs -node scripts/check-mcp-compact-active-local.mjs -``` - -active 时 `tkmind-search` / `tkmind-excel` MCP 会暴露 `ctx_fetch`,大 payload 会被压缩为 handle。 - Bundle 常量见 `context-runtime-profile.mjs` → `CONTEXT_RUNTIME_SHADOW_ENV`。 +## 本地 active 配置 + +五件套可全部 `active`(`CONTEXT_RUNTIME_ACTIVE_ENV`)。**memory injection 仍保持 shadow**(`MEMORY_AGENT_INJECTION_MODE=shadow`,禁止 active injection)。 + +```bash +node scripts/check-context-runtime-active-local.mjs +# → CONTEXT_RUNTIME_ACTIVE_OK +``` + +| 开关 | active 行为 | +|------|-------------| +| MCP compact | 压缩大 tool 结果 + `ctx_fetch` | +| context budget | 编排注入按预算 dedupe/drop | +| recall fusion | 融合 recall 结果生效 | +| zvec workspace | code 任务附加 workspace 检索 | +| headroom | LLM 经 proxy(不可达 fail-open) | + ## 离线事件形状预览 不启动 Portal 也可查看 gateway 将 emit 的 shadow 事件: @@ -78,6 +80,9 @@ node scripts/check-codebase-memory-mcp-local.mjs # dsh CLI + dry-run launch plan(见 docs/dsh-executor-local.md,默认零 LLM) node scripts/check-dsh-executor-local.mjs + +# Context Runtime active 五件套(零 LLM) +node scripts/check-context-runtime-active-local.mjs ``` ## Shadow Portal E2E(1 轮,省 token 默认只验事件) diff --git a/scripts/check-context-runtime-active-local.mjs b/scripts/check-context-runtime-active-local.mjs new file mode 100644 index 0000000..331d0f4 --- /dev/null +++ b/scripts/check-context-runtime-active-local.mjs @@ -0,0 +1,84 @@ +#!/usr/bin/env node +/** + * Verify Context Runtime active profile on this machine (no LLM). + */ +import { spawnSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { + CONTEXT_RUNTIME_ACTIVE_ENV, + describeContextRuntimeProfile, +} from '../context-runtime-profile.mjs'; +import { + ensureHeadroomProxyRunning, + probeHeadroomProxyReachable, + resolveHeadroomMode, +} from '../memind-headroom-policy.mjs'; + +const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); + +for (const [key, value] of Object.entries(CONTEXT_RUNTIME_ACTIVE_ENV)) { + process.env[key] = process.env[key] ?? value; +} + +const profile = describeContextRuntimeProfile(process.env); +console.log('CONTEXT_RUNTIME_ACTIVE_PROBE:'); +console.log(` profile=${JSON.stringify(profile)}`); + +const issues = []; +for (const [key, expected] of Object.entries(CONTEXT_RUNTIME_ACTIVE_ENV)) { + if (key === 'HEADROOM_OUTPUT_SHAPER') continue; + const actual = profile[ + key === 'MEMIND_HEADROOM_MODE' ? 'headroom' + : key === 'MEMIND_CONTEXT_BUDGET_MODE' ? 'contextBudget' + : key === 'MEMIND_RECALL_FUSION_MODE' ? 'recallFusion' + : key === 'MEMIND_MCP_COMPACT_MODE' ? 'mcpCompact' + : 'zvecWorkspace' + ]; + if (actual !== expected) { + issues.push(`${key}=${actual} (expected ${expected})`); + } +} + +function runScript(name) { + const result = spawnSync(process.execPath, [path.join(root, 'scripts', name)], { + cwd: root, + env: process.env, + encoding: 'utf8', + }); + return { + ok: result.status === 0, + stdout: (result.stdout ?? '').trim(), + stderr: (result.stderr ?? '').trim(), + }; +} + +for (const script of [ + 'check-mcp-compact-active-local.mjs', + 'check-mcp-compactor-local.mjs', + 'check-zvec-workspace-local.mjs', +]) { + const result = runScript(script); + console.log(` ${script}=${result.ok ? 'OK' : 'FAIL'}`); + if (!result.ok) { + issues.push(`${script} failed`); + if (result.stderr) console.error(result.stderr.slice(0, 400)); + } +} + +if (resolveHeadroomMode(process.env) === 'active') { + const boot = await ensureHeadroomProxyRunning({ env: process.env }); + const reachable = boot.reachable || await probeHeadroomProxyReachable({ env: process.env }); + console.log(` headroom_proxy=${reachable ? 'reachable' : 'unreachable'} started=${boot.started}`); + if (!reachable) { + issues.push('headroom active but proxy unreachable'); + } +} + +if (issues.length) { + console.error(`CONTEXT_RUNTIME_ACTIVE_FAIL: ${issues.join('; ')}`); + process.exit(1); +} + +console.log('CONTEXT_RUNTIME_ACTIVE_OK');